2

有没有办法指定允许以下语法的语法:

f(x)(g, (1-(-2))*3, 1+2*3)[0]

它被转换为(在伪lisp中显示顺序):

(index 
  ((f x)
    g 
    (* (- 1 -2) 3)
    (+ (* 2 3) 1)
  ) 
  0
)

以及有限的运算符优先级等。


以下语法适用于 backtrack = true,但我想避免这种情况:

grammar T;

options {
 output=AST;
 backtrack=true;
 memoize=true;
}

tokens {
  CALL;
  INDEX;
  LOOKUP;
}

prog: (expr '\n')* ;

expr : boolExpr;

boolExpr
 : relExpr (boolop^ relExpr)?
 ;

relExpr
 : addExpr (relop^ addExpr)?
 | a=addExpr oa=relop b=addExpr ob=relop c=addExpr
   -> ^(LAND ^($oa $a $b) ^($ob $b $c))
 ;


addExpr
 : mulExpr (addop^ mulExpr)?
 ;

mulExpr
 : atomExpr (mulop^ atomExpr)?
 ;

atomExpr
 : INT
 | ID
 | OPAREN expr CPAREN -> expr
 | call
 ;

call
 : callable ( OPAREN (expr (COMMA expr)*)? CPAREN -> ^(CALL callable expr*)
            | OBRACK expr CBRACK -> ^(INDEX callable expr)
            | DOT ID -> ^(INDEX callable ID)
            )
 ;

fragment
callable
 : ID
 | OPAREN expr CPAREN
 ;

fragment
boolop
 : LAND | LOR
 ;

fragment
relop
 : (EQ|GT|LT|GTE|LTE)
 ;

fragment
addop
 : (PLUS|MINUS)
 ;

fragment
mulop
 : (TIMES|DIVIDE)
 ;

EQ : '==' ;
GT : '>' ;
LT : '<' ;
GTE : '>=' ;
LTE : '<=' ;

LAND : '&&' ;
LOR : '||' ;

PLUS : '+' ;
MINUS : '-' ;
TIMES : '*' ;
DIVIDE : '/' ;

ID : ('a'..'z')+ ;
INT : '0'..'9' ;

OPAREN : '(' ;
CPAREN : ')' ;
OBRACK : '[' ;
CBRACK : ']' ;
DOT : '.' ;

COMMA : ',' ;
4

1 回答 1

2

你的语法有几个问题:

1

只有词法分析器规则可以是fragments,而不是解析器规则。一些 ANTLR 目标只是忽略解析器规则前面的片段关键字(如 Java 目标),但最好将它们从语法中删除:如果您决定为不同的目标语言创建解析器,您可能会遇到问题,因为它。

2

没有backtrack=true,您不能混合使用树重写运算符 (^!)重写规则 ( ->),因为您需要在内部创建一个备选方案,relExpr而不是现在拥有的两个备选方案(这是为了消除歧义)。

在您的情况下,您无法仅使用^(在单个替代方案中)创建所需的 AST,因此您需要这样做:

relExpr
 : (a=addExpr -> $a) ( (oa=relOp b=addExpr    -> ^($oa $a $b))
                         ( ob=relOp c=addExpr -> ^(LAND ^($oa $a $b) ^($ob $b $c))
                         )?
                     )?
 ;

(是的,我知道,它不是特别漂亮,但这不能帮助 AFAIK)

LAND此外,如果它在tokens { ... }块中定义,您只能将令牌放入重写规则中:

tokens {
  // literal tokens
  LAND='&&';
  ...

  // imaginary tokens
  CALL;
  ...
}

否则,如果令牌(和其他解析器规则)确实出现在解析器规则本身内,则只能在重写规则中使用它们。

3

您没有考虑语法中的一元减号,请按如下方式实现:

mulExpr
 : unaryExpr ((TIMES | DIVIDE)^ unaryExpr)*
 ;

unaryExpr
 : MINUS atomExpr -> ^(UNARY_MINUS atomExpr)
 | atomExpr
 ;

现在,要创建不需要的语法,请从规则backtrack=true中删除IDand :'(' expr ')'atomExpr

atomExpr
 : INT
 | call
 ;

并在您的规则中使所有传递的内容都是callable可选的:call

call
 : (callable -> callable) ( OPAREN params CPAREN -> ^(CALL $call params)
                          | OBRACK expr CBRACK   -> ^(INDEX $call expr)
                          | DOT ID               -> ^(INDEX $call ID)
                          )*
 ;

这样,ID并且'(' expr ')'已经匹配call(并且没有歧义)。


考虑到上述所有注释,您可以得到以下语法:

grammar T;

options {
  output=AST;
}

tokens {
 // literal tokens
 EQ     = '==' ;
 GT     = '>' ;
 LT     = '<' ;
 GTE    = '>=' ;
 LTE    = '<=' ;
 LAND   = '&&' ;
 LOR    = '||' ;
 PLUS   = '+' ;
 MINUS  = '-' ;
 TIMES  = '*' ;
 DIVIDE = '/' ;
 OPAREN = '(' ;
 CPAREN = ')' ;
 OBRACK = '[' ;
 CBRACK = ']' ;
 DOT    = '.' ;
 COMMA  = ',' ;

 // imaginary tokens
 CALL;
 INDEX;
 LOOKUP;
 UNARY_MINUS;
 PARAMS;
}

prog
 : expr EOF -> expr
 ;

expr
 : boolExpr
 ;

boolExpr
 : relExpr ((LAND | LOR)^ relExpr)?
 ;

relExpr
 : (a=addExpr -> $a) ( (oa=relOp b=addExpr    -> ^($oa $a $b))
                         ( ob=relOp c=addExpr -> ^(LAND ^($oa $a $b) ^($ob $b $c))
                         )?
                     )?
 ;

addExpr
 : mulExpr ((PLUS | MINUS)^ mulExpr)*
 ;

mulExpr
 : unaryExpr ((TIMES | DIVIDE)^ unaryExpr)*
 ;

unaryExpr
 : MINUS atomExpr -> ^(UNARY_MINUS atomExpr)
 | atomExpr
 ;

atomExpr
 : INT
 | call
 ;

call
 : (callable -> callable) ( OPAREN params CPAREN -> ^(CALL $call params)
                          | OBRACK expr CBRACK   -> ^(INDEX $call expr)
                          | DOT ID               -> ^(INDEX $call ID)
                          )*
 ;

callable
 : ID
 | OPAREN expr CPAREN -> expr
 ;

params
 : (expr (COMMA expr)*)? -> ^(PARAMS expr*)
 ;

relOp
 : EQ | GT | LT | GTE | LTE
 ;

ID     : 'a'..'z'+ ;
INT    : '0'..'9'+ ;
SPACE  : (' ' | '\t') {skip();};

这会将输入解析"a >= b < c"为以下 AST:

在此处输入图像描述

输入"f(x)(g, (1-(-2))*3, 1+2*3)[0]"如下:

在此处输入图像描述

于 2012-05-23T18:48:36.463 回答