antlr - 另一个没有可行的替代方案...

标签 antlr

我有一个数学表达式语法文件,类似于在线教程中的文件:http://javadude.com/articles/antlr3xtut/

但现在我想添加函数选项,但我很难让词法分析器/解析器规则正常工作。我可以使用丑陋的词法分析器规则来使代码正常工作,但我想使用更干净的标记来使解析器规则正常工作。

如果我尝试这样做,我将捕获“第 1:9 行在输入‘Test(’) 处没有可行的替代方案”这样的表达式的异常,例如“a*b/13.2*Test(3,2)”

请检查以下语法文件中的注释,看看我的具体问题是什么

grammar ExpressionOnly;

options {
  language = Java;
}

@header {
  package kic.engine.grammar;
}

@lexer::header {
  package kic.engine.grammar;
}


// Top Rule
eval
  : expression
  ;

term 
  : func                     
  | '(' op1=expression ')'   
  | array                    
  | element                  
  ;

  // Sub Terms
  func
    // :  f=FUNC                   // Works but this is very ugly because FUNC contains '(';
    :  f=IDENT '('                 // <---------------------------- why does this not work: line 1:9 no viable alternative at input 'Test('
         (arg=expression (',' arg=expression)*)? 
       ')'
    ;

  array
    : '['  ele=element (',' ele=element)* ']'
    ;

  element
    : b=(K_TRUE | K_FALSE)      
    | NUMBER                    
    | IDENT                     
    | DATE                      
    | SQ_STRING                 
    | K_NULL                    
    ;

negation
  @init{ boolean negate = false; } 
  : (K_NOT | '!' { negate = true;} )? 
    term  
  ;

unary 
  @init{ boolean positive = true; }
  : ('+' | '-')* 
    negation 
  ;

power
  : op1=unary 
    ( '^'  op2=unary 
    )*  
  ;

multiply
  : op1=power          
    ( '*'  op2=power   
    | '/'  op2=power   
    | '%'  op2=power   
    )* 
  ;

add 
  : op1=multiply         
    ( '+' op2=multiply   
    | '-' op2=multiply   
    )*
  ;

relation
  : op1=add 
    ( '='   op2=add   
    | '!='  op2=add   
    | '<'   op2=add   
    | '<='  op2=add   
    | '>'   op2=add   
    | '>='  op2=add   
    )* 
  ;

expression
  : op1=relation
    ( (K_AND | '&')  op2=relation    
    | (K_OR | '|')   op2=relation   
    )*
  ;


// Case-insensitive alpha characters
fragment A: ('a'|'A');
fragment B: ('b'|'B');
fragment C: ('c'|'C');
fragment D: ('d'|'D');
fragment E: ('e'|'E');
fragment F: ('f'|'F');
fragment G: ('g'|'G');
fragment H: ('h'|'H');
fragment I: ('i'|'I');
fragment J: ('j'|'J');
fragment K: ('k'|'K');
fragment L: ('l'|'L');
fragment M: ('m'|'M');
fragment N: ('n'|'N');
fragment O: ('o'|'O');
fragment P: ('p'|'P');
fragment Q: ('q'|'Q');
fragment R: ('r'|'R');
fragment S: ('s'|'S');
fragment T: ('t'|'T');
fragment U: ('u'|'U');
fragment V: ('v'|'V');
fragment W: ('w'|'W');
fragment X: ('x'|'X');
fragment Y: ('y'|'Y');
fragment Z: ('z'|'Z');


// Fragments
fragment DIGIT    : '0' .. '9';  
fragment UPPER    : 'A' .. 'Z';
fragment LOWER    : 'a' .. 'z';
fragment LETTER   : LOWER | UPPER;
fragment WORD     : LETTER | '_' | '$' | '#' | '.';
fragment ALPHANUM : WORD | DIGIT;
fragment ESCAPE[StringBuilder buf] : 
  '\\'
  ( 't' { buf.append('\t'); }
  | 'n' { buf.append('\n'); }
  | 'r' { buf.append('\r'); }
  | '"' { buf.append('\"'); }
  | '\\' { buf.append('\\'); }
  )
  ;

// Keyowords
K_FALSE : F A L S E;
K_NULL : N U L L;
K_TRUE : T R U E;
K_AND : A N D;
K_NOT : N O T;
K_OR : O R;

// Tokens;
FUNC : LETTER+ '(';

IDENT : LETTER ALPHANUM*;

ARRAY_INDEX : IDENT '[';

DQ_STRING 
  @init { final StringBuilder buf = new StringBuilder(); } 
  : '"' 
    ( ESCAPE[buf]
    | i = ~('\\' | '"') { buf.appendCodePoint(i); }
    )*
  { setText(buf.toString()); }
  ;  

NUMBER: DIGIT+ ('.' DIGIT+)? (('e'|'E')('+'|'-')? DIGIT+)?;

DATE: '\'' DIGIT DIGIT DIGIT DIGIT '-' DIGIT DIGIT '-' DIGIT DIGIT (' ' DIGIT DIGIT ':' DIGIT DIGIT ':' DIGIT DIGIT ('.' DIGIT+)?)? '\'';

SQ_STRING : '\'' .* '\'';

// hidden tokens
WS : (' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;};

COMMENTS : '/*' .* '*/' {$channel=HIDDEN;};

有什么想法可以让函数规则与 IDENT token 一起使用吗?

最佳答案

输入Test(3,2) 变成以下标记:

[FUNC : Test(] [NUMBER : 3] [',' : ,] [NUMBER : 2] [')' : )] 

当前没有解析器规则需要 FUNC 标记,因此解析器会生成一个错误,打印该标记的内容:line 2:1 在输入 'Test(' 处没有可行的替代方案.

注释掉 FUNC 词法分析器规则,重新生成所有内容,然后重新运行。现在,相同的输入可以毫无错误地生成这些标记:

[IDENT : Test] ['(' : (] [NUMBER : 3] [',' : ,] [NUMBER : 2] [')' : )] 

出于测试目的,我将语法输出设为 AST,并将解析器规则 func 中的术语 f=IDENT 更改为 f=IDENT^,以便更容易地在 AST 中查看解析器是否识别了函数。

现在,输入 a*b/13.2*Test(3,2) 我得到以下 AST:

AST

输入 Test(3,2) 被正确识别为函数,并相应地生成 AST。

关于antlr - 另一个没有可行的替代方案...,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14031966/

相关文章:

antlr - 在范围和语法错误中使用 float ?

parsing - ANTLR4 语法在输入时没有可行的选择

antlr - 有谁知道在 ANTLRWorks 中调试树语法的方法

java - 如何根据语法拆分输入

java - 在 Java 和 ANTLRWorks 调试器中捕获 ANTLR 的 NoViableAltException

java - 为什么我的 ANTLR4 语法中的这一添加会破坏不相关的规则替代方案?

antlr - 当有更通用的标记可用时,如何在词法分析期间将连接的标记分开

parsing - 为什么这个 ANTLR4 语法有歧义?

ANTLR4 Beta 3 非常简单的语法不起作用

c - 使用 c 语法构建 ast 时管理操作优先级