我正在尝试使用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 ')';
但是由于非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.
即使在阅读了大部分 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*));
答案 0 :(得分:1)
从'(' value ')'
移除value
并将其放入root
:
root : IDENTIFIER | SELF | literal | constructor | call | indexer | '(' value ')';
...
value : comparison;
现在(a.b).c
将导致以下解析:
(3 < d()).e
in:
当然,你可能想省略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场比赛!而且你有它:解析器“看到”一个输入,两个不同
解析和报告这种歧义。