3

我正在尝试使用 ANTLR 解析值。这是我语法的相关部分:

root : IDENTIFIER | SELF | literal | constructor | call | indexer;

hierarchy : root (SUB^ (IDENTIFIER | call | indexer))*;

factor  : hierarchy ((MULT^ | DIV^ | MODULO^) hierarchy)*;

sum : factor ((PLUS^ | MINUS^) factor)*;

comparison  : sum (comparison_operator^ sum)*;

value   : comparison | '(' value ')';

我不会描述每个标记或规则,因为它们的名称可以很好地解释它们的作用。该语法运行良好且可以编译,允许我解析、使用value以下内容:

a.b[c(5).d[3] * e()] < e("f")

解释

价值识别剩下的唯一事情就是能够有括号中的层次结构根。例如:

(a.b).c
(3 < d()).e
...

天真地,没有太多期望,我尝试在我的root规则中添加以下替代方案:

root : ... | '(' value ')';

然而,value由于非 LL(*) 主义,这违反了规则:

rule value has non-LL(*) decision due to recursive rule invocations reachable
from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using 
backtrack=true option.

休息

即使在阅读了大部分The Definitive ANTLR Reference之后,我仍然不明白这些错误。但是,我所理解的是,在看到括号打开时,ANTLR 无法知道它是在查看括号值的开头还是括号根的开头。

如何清楚地定义带括号的层次结构根的行为?

编辑:根据要求,附加规则:

parameter : type IDENTIFIER -> ^(PARAMETER ^(type IDENTIFIER));

constructor : NEW type PAREN_OPEN (arguments+=value (SEPARATOR arguments+=value)*)? PAREN_CLOSE -> ^(CONSTRUCTOR type ^(ARGUMENTS $arguments*)?);

call : IDENTIFIER PAREN_OPEN (values+=value (SEPARATOR values+=value)*)? PAREN_CLOSE -> ^(CALL IDENTIFIER ^(ARGUMENTS $values*)?);

indexer : IDENTIFIER INDEX_START (values+=value (SEPARATOR values+=value)*)? INDEX_END -> ^(INDEXER IDENTIFIER ^(ARGUMENTS $values*));
4

1 回答 1

1

'(' value ')'从中取出value并将其放入root

root : IDENTIFIER | SELF | literal | constructor | call | indexer | '(' value ')';

...

value : comparison;

现在(a.b).c将产生以下解析:

在此处输入图像描述

(3 < d()).e

在此处输入图像描述

当然,您可能希望省略 AST 中的括号:

root : IDENTIFIER | SELF | literal | constructor | call | indexer | '('! value ')'!;

此外,您不需要在解析器规则中的Listusing中附加标记。+=以下:

call 
 : IDENTIFIER PAREN_OPEN (values+=value (SEPARATOR values+=value)*)? PAREN_CLOSE 
   -> ^(CALL IDENTIFIER ^(ARGUMENTS $values*)?)
 ;

可以改写为:

call 
 : IDENTIFIER PAREN_OPEN (value (SEPARATOR value)*)? PAREN_CLOSE 
   -> ^(CALL IDENTIFIER ^(ARGUMENTS value*)?)
 ;

编辑

您的主要问题是某些输入可以以两种(或更多!)方式解析。例如,输入(a)可以由value规则的替代 1 和 2 解析:

value 
 : comparison    // alternative 1
 | '(' value ')' // alternative 2
 ;

运行您的解析器规则:a comparison(alternative 1) 可以匹配(a),因为它匹配root规则,而规则又匹配'(' value ')'. 但这也是另类2的比赛!你就知道了:解析器“看到”一个输入,两个不同的解析并报告这种歧义。

于 2012-05-02T06:06:06.500 回答