ANTLR4运算符的优先级

时间:2018-01-23 17:01:12

标签: parsing operators antlr antlr4 operator-precedence

这是我的语法:

grammar FOOL;

@header {
    import java.util.ArrayList;
}

@lexer::members {
   public ArrayList<String> lexicalErrors = new ArrayList<>();
}

/*------------------------------------------------------------------
 * PARSER RULES
 *------------------------------------------------------------------*/

prog   : exp SEMIC                      #singleExp
       | let exp SEMIC                  #letInExp
       | (classdec)+ SEMIC (let)? exp SEMIC #classExp
       ;

classdec  : CLASS ID ( EXTENDS ID )? (LPAR (vardec ( COMMA vardec)*)? RPAR)?  (CLPAR ((fun SEMIC)+)? CRPAR)?;

let       : LET (dec SEMIC)+ IN ;

vardec  : type ID ;

varasm     : vardec ASM exp ;

fun    : type ID LPAR ( vardec ( COMMA vardec)* )? RPAR (let)? exp ;

dec   : varasm           #varAssignment
      | fun              #funDeclaration
      ;


type   : INT
        | BOOL
        | ID
      ;

    exp    : left=term (operator=(PLUS | MINUS) right=term)*
       ;

term   : left=factor (operator=(TIMES | DIV) right=factor)*
       ;

factor : left=value (operator=(EQ | LESSEQ | GREATEREQ | GREATER | LESS | AND | OR ) right=value)*
       ;

value  :  MINUS?INTEGER                                   #intVal
      | (NOT)? ( TRUE | FALSE )                       #boolVal
      | LPAR exp RPAR                                 #baseExp
      | IF cond=exp THEN CLPAR thenBranch=exp CRPAR (ELSE CLPAR elseBranch=exp CRPAR)?  #ifExp
      | MINUS?ID                                             #varExp
      | THIS                                              #thisExp
      | funcall        #funExp
      | (ID | THIS) DOT funcall   #methodExp
      | NEW ID ( LPAR (exp (COMMA exp)* )? RPAR)?             #newExp
      | PRINT ( exp )                                 #print
      ;
/* PRINT LPAR exp RPAR */

funcall
    : ID ( LPAR (exp (COMMA exp)* )? RPAR )
    ;


/*------------------------------------------------------------------
 * LEXER RULES
 *------------------------------------------------------------------*/
SEMIC  : ';' ;
COLON  : ':' ;
COMMA  : ',' ;
EQ     : '==' ;
ASM    : '=' ;
PLUS   : '+' ;
MINUS  : '-' ;
TIMES  : '*' ;
DIV    : '/' ;
TRUE   : 'true' ;
FALSE  : 'false' ;
LPAR   : '(' ;
RPAR   : ')' ;
CLPAR  : '{' ;
CRPAR  : '}' ;
IF        : 'if' ;
THEN   : 'then' ;
ELSE   : 'else' ;
PRINT : 'print' ;
LET    : 'let' ;
IN     : 'in' ;
VAR    : 'var' ;
FUN    : 'fun' ;
INT    : 'int' ;
BOOL   : 'bool' ;
CLASS   : 'class' ;
EXTENDS   : 'extends' ;
THIS   : 'this' ;
NEW    : 'new' ;
DOT    : '.' ;
LESSEQ    : ('<=' | '=<') ;
GREATEREQ    : ('>=' | '=>') ;
GREATER: '>' ;
LESS   : '<' ;
AND    : '&&' ;
OR     : '||' ;
NOT    : '!' ;


//Numbers
fragment DIGIT : '0'..'9';
INTEGER       : DIGIT+;

//IDs
fragment CHAR  : 'a'..'z' |'A'..'Z' ;
ID              : CHAR (CHAR | DIGIT)* ;

//ESCAPED SEQUENCES
WS              : (' '|'\t'|'\n'|'\r')-> skip;
LINECOMENTS    : '//' (~('\n'|'\r'))* -> skip;
BLOCKCOMENTS    : '/*'( ~('/'|'*')|'/'~'*'|'*'~'/'|BLOCKCOMENTS)* '*/' -> skip;

ERR_UNKNOWN_CHAR
    :   . { lexicalErrors.add("UNKNOWN_CHAR " + getText()); }
    ;

我认为关于运算符优先级的语法存在问题。 特别是这一个

let int x = (5-2)+4; in print x;

打印7,而这一个:

    let
    int x = 5-2+4;
in
    print x;

打印9。 为什么第一个有效?我怎样才能使第二个工作,只改变语法? 我认为在exp,term或factor中有一些变化。

这是第一个解析树http://it.tinypic.com/r/2nj8tqw/9。 这是第二个解析树http://it.tinypic.com/r/2iv02z6/9

1 个答案:

答案 0 :(得分:1)

exp    :  left=term (operator=(PLUS | MINUS) right=exp)?

这会产生导致它的解析树。简而言之,5 - 2 + 4将被解析为:

term  PLUS       exp
 2         term MINUS exp
            2        term
                      4

这应该有所帮助,尽管您必须更改评估逻辑:

exp    :  left=term (operator=(PLUS | MINUS) right=term)*

factor和任何其他可能的二进制操作相同。