我正在处理一个对上下文敏感的语法。这是它的描述:
这是语法的简化版本:
grammar TestGrammar;
@members {
boolean isValue = false;
}
exprSet: (expr NL?)+;
expr: expr log_op expr
| part
| '(' expr ')'
;
part: (fieldId comp_op)? values;
fieldId: STRNG;
values: values log_op values
| value
| '(' values ')'
;
value: strng;
strng: ( STRNG
| {isValue}? comp_op
)+;
log_op: '&' '&';
comp_op: '=';
NL: '\r'? '\n';
WS: ' ' -> channel(HIDDEN);
STRNG: CHR+;
CHR: [A-Za-z];
我在 strng 规则中使用语义谓词。它应该根据 isValue 变量扩展可能的令牌集;
当语义谓词评估为false时,会出现问题。我希望有2个 STRNG 代币与' ='它们之间的标记将被视为 part 节点。而不是它,它将每个 STRNG 标记解析为值,并抛出' ='重新同步时的令牌。
这里输入字符串和结果表达式树不正确:
a && b=c
要查看正确的表达式树,它足以从 strng 规则中删除具有语义谓词的替代方法(这使其成为静态,因此不适合我的解决方案):
strng: ( STRNG
// | {isValue}? comp_op
)+;
这里得到的表达式树:
BTW,当语义谓词评估为真时 - 结果如预期: strng 规则匹配一组扩展的标记:
strng: ( STRNG
| {!isValue}? comp_op
)+;
请解释为什么会以这种方式发生,并帮助找出正确的解决方案。谢谢!
答案 0 :(得分:0)
从values
删除一个选项怎么样?否则,文本a && b
可能是
expr
- > expr
log_op
expr
或
expr
- > part
- > values
log_op
values
。 似乎Antlr通过使用第二个选项来解决它!
values
: //values log_op values
value
| '(' values ')'
;
答案 1 :(得分:0)
我相信您的expr
规则编写顺序错误。尝试将二进制表达式移动到最后一个替代而不是第一个替代。
答案 2 :(得分:0)
好的,我意识到目前的做法不适合我的任务。
我选择了另一种基于覆盖Lexer的nextToken()和emit()方法的方法,如ANTLR4: How to inject tokens中所述。
它几乎完全控制了令牌流。我有以下优势:
拥有所有这些可能性,我能够解决解析器中的所有歧义。
P.S。感谢所有试图提供帮助的人,我很感激!