如何解析带括号的层次结构根?

时间:2012-05-01 23:15:06

标签: antlr

我正在尝试使用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")

Interpretation

唯一能够识别价值的是能够使用带括号的层次结构根。例如:

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

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

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

但是由于非LL(*)ism:

,这会破坏value规则
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.

Break

即使在阅读了大部分 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*));

1 个答案:

答案 0 :(得分:1)

'(' value ')'移除value并将其放入root

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

...

value : comparison;

现在(a.b).c将导致以下解析:

enter image description here

(3 < d()).e in:

enter image description here

当然,你可能想省略AST的括号:

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

此外,您无需在解析器规则中使用List+=中附加令牌。以下内容:

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
 ;

运行解析器规则:comparison(备选方案1)可以与(a)匹配,因为它与root规则相匹配,后者与'(' value ')'匹配。但这也是替代2场比赛!而且你有它:解析器“看到”一个输入,两个不同 解析和报告这种歧义。