ANTLR4上下文相关规则:语义谓词失败时意外解析/重新同步

时间:2014-07-15 07:42:55

标签: parsing antlr4

我正在处理一个对上下文敏感的语法。这是它的描述:

  • 它描述了一组表达式。
  • 每个表达式包含由逻辑运算符分隔的一个或多个部分。
  • 每个部分都包含可选字段标识符,后跟一些比较运算符(也是可选的)和值列表。
  • 值也由逻辑运算符分隔。
  • 默认值是一系列字符。有时(取决于上下文)可以扩展每个值的可能字符集。它甚至可以使用比较运算符(根据第3条规则用于从值列表中分离字段标识符)将其视为值的字符。

这是语法的简化版本:

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

enter image description here

要查看正确的表达式树,它足以从 strng 规则中删除具有语义谓词的替代方法(这使其成为静态,因此不适合我的解决方案):

strng: (  STRNG 
       // | {isValue}? comp_op
       )+;

这里得到的表达式树:

enter image description here

BTW,当语义谓词评估为真时 - 结果如预期: strng 规则匹配一组扩展的标记:

strng: (  STRNG 
        | {!isValue}? comp_op
       )+;

请解释为什么会以这种方式发生,并帮助找出正确的解决方案。谢谢!

3 个答案:

答案 0 :(得分:0)

values删除一个选项怎么样?否则,文本a && b可能是

  1. expr - > expr log_op expr
    1. expr - > part - > values log_op values
    2. 。 似乎Antlr通过使用第二个选项来解决它!

          values
               : //values log_op values
                 value
               | '(' values ')'
               ;
      

答案 1 :(得分:0)

我相信您的expr规则编写顺序错误。尝试将二进制表达式移动到最后一个替代而不是第一个替代。

答案 2 :(得分:0)

好的,我意识到目前的做法不适合我的任务。

我选择了另一种基于覆盖Lexer的nextToken()和emit()方法的方法,如ANTLR4: How to inject tokens中所述。

它几乎完全控制了令牌流。我有以下优势:

  • 将所需类型分配给令牌;
  • 推迟向尚未定义的类型发送令牌(通过在隐藏频道上发送假令牌);
  • 分割和合并令牌的可能性;
  • 可以将推迟的代币组织成队列。

拥有所有这些可能性,我能够解决解析器中的所有歧义。

P.S。感谢所有试图提供帮助的人,我很感激!