防止ANTLR 4中的左递归与无效输入匹配

时间:2019-05-16 03:03:08

标签: java antlr antlr4 operator-precedence left-recursion

我正在编写一种简单的编程语言。它具有以下语法:

program: declaration+;

declaration: varDeclaration
           | statement
           ;

varDeclaration: 'var' IDENTIFIER ('=' expression)?';';
statement: exprStmt
         | assertStmt
         | printStmt
         | block
         ;

exprStmt: expression';';
assertStmt: 'assert' expression';';
printStmt: 'print' expression';';
block: '{' declaration* '}';

//expression without left recursion
/*
expression: assignment
          ;

assignment: IDENTIFIER '=' assignment
          | equality;

equality: comparison (op=('==' | '!=') comparison)*;

comparison: addition  (op=('>' | '>=' | '<' | '<=') addition)* ;

addition: multiplication (op=('-' | '+') multiplication)* ;

multiplication: unary (op=( '/' | '*' ) unary )* ;

unary: op=( '!' | '-' ) unary
     | primary
     ;
*/

//expression with left recursion
expression: IDENTIFIER '=' expression
          | expression op=('==' | '!=') expression
          | expression op=('>' | '>=' | '<' | '<=') expression
          | expression op=('-' | '+') expression
          | expression op=( '/' | '*' ) expression
          | op=( '!' | '-' ) expression
          | primary
          ;

primary: intLiteral
       | booleanLiteral
       | stringLiteral
       | identifier
       | group
       ;

intLiteral: NUMBER;
booleanLiteral: value=('True' | 'False');
stringLiteral: STRING;
identifier: IDENTIFIER;
group: '(' expression ')';

TRUE: 'True';
FALSE: 'False';
NUMBER:   [0-9]+ ;
STRING: '"' ~('\n'|'"')* '"' ;
IDENTIFIER :   [a-zA-Z]+ ;

此左递归语法很有用,因为它可确保解析树中的每个节点最多具有2个子代。例如, var a = 1 + 2 + 3将变成两个嵌套的加法表达式,而不是一个带有三个孩子的加法表达式。该行为很有用,因为它使编写解释器变得容易,因为我可以(高度简化)进行操作:

public Object visitAddition(AdditionContext ctx) {
    return visit(ctx.addition(0)) + visit(ctx.addition(1));
}

而不是遍历所有子节点。

但是,这种左递归语法有一个缺陷,那就是它接受无效的语句。 例如:

var a = 3;
var b = 4;
a = b == b = a;

在此语法下有效,即使预期行为为

  1. b == b首先被解析,因为==的优先级高于分配(=)。
  2. 因为首先解析b == b,所以表达式变得不连贯。解析失败。

相反,发生了以下不良行为:将最后一行解析为(a = b)==(b = a)。

AST Image

如何防止左递归解析不连贯的语句,例如a = b == b = a

非左递归语法识别出此输入正确,并引发了解析错误,这是所需的行为。

0 个答案:

没有答案