Parsing ANTLR4上下文敏感规则:语义谓词失败时意外的分析/重新同步

Parsing ANTLR4上下文敏感规则:语义谓词失败时意外的分析/重新同步,parsing,antlr4,Parsing,Antlr4,我正在研究一种上下文敏感的语法。以下是它的描述: 它描述了一组表达式 每个表达式包含一个或多个由逻辑运算符分隔的部分 每个部分由可选字段标识符、一些比较运算符(也是可选的)和值列表组成 值也由逻辑运算符分隔 默认值是一个字符序列。有时(取决于上下文),可以扩展每个值的一组可能字符。它甚至可以使用比较运算符(根据第三条规则,用于将字段标识符从值列表中分离)将其视为值的字符 以下是语法的简化版本: grammar TestGrammar; @members { boolean isValu

我正在研究一种上下文敏感的语法。以下是它的描述:

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

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规则中删除一个带有语义谓词的替代项就足够了(这使得它是静态的,因此不适合我的解决方案):

下面是生成的表达式树:

顺便说一句,当语义谓词的计算结果为true时-结果与预期一致:strng规则匹配扩展的标记集:

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

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

值中删除一个选项如何?否则,文本
a&&b
可能是

  • expr
    ->
    expr
    log\u op
    expr
  • expr
    ->
    部分
    ->
    日志操作
  • 。 似乎Antlr通过使用第二个选项解决了这个问题

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

    我相信你的
    expr
    规则写错了顺序。尝试将二进制表达式移动为最后一个替代项,而不是第一个

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

    我选择了另一种基于覆盖Lexer的nextToken()和emit()方法的方法,如中所述

    它让我几乎完全控制了代币流。我有以下优点:

    • 将所需类型分配给令牌
    • 推迟向解析器发送尚未定义类型的令牌(通过在隐藏通道上发送假令牌)
    • 分割和合并代币的可能性
    • 可以将推迟的代币组织到队列中
    有了所有这些可能性,我能够解决解析器中的所有歧义


    另外,感谢所有试图帮助我的人,我很感激

    谢谢你的回答!不幸的是,这没有帮助。主要原因是:以这种方式不可能表示值列表,每个部分将只有一个值,可能包含在括号内。不管怎样,我试过了,但没有成功。。。它仍然将“b=c”表示为两个部分,并在语义谓词的计算结果为false时抛出“=”标记……不幸的是,它没有帮助。结果与第一个屏幕截图上的结果相同。似乎当语义谓词失败时,它会抛出FailedPredicateException异常,强制执行错误恢复过程,该过程将通过调用堆栈向下到达根(exprSet)节点。没有叶子的第二分枝。似乎解析器在恢复过程中启动了故障安全策略(如《最终ANTLR参考》一书中“错误恢复故障安全”子章节所述)。无论如何,还不清楚为什么在恢复过程中找不到正确的替代方案。我还需要进一步研究。特别是关于恢复:ANTLR 4在任何情况下都不会执行任何回溯。如果预测在第一次尝试时未能返回正确的备选方案,那么它将无法完全返回正确的备选方案。
        values
             : //values log_op values
               value
             | '(' values ')'
             ;