Antlr 无法跳转到下一个备选方案的PredicateException处理

Antlr 无法跳转到下一个备选方案的PredicateException处理,antlr,antlr4,Antlr,Antlr4,我有一些模棱两可的意见。我想做的是,如果谓词在规则内部的计算结果为false,则跳过其中一个选项(我想检查我的链内部是否没有空格,但不想实际生成空格标记并将其注入每个规则)。 我知道我可以用antlr捕捉异常,但它似乎只适用于全局规则范围。 我想我可以试试java代码。 例如,我有一些antlr4生成的java代码: 开关(get解释器().adaptivePredict(_input,117,_ctx)){ ... 案例4: { _localctx=新的ChainExpressionConte

我有一些模棱两可的意见。我想做的是,如果谓词在规则内部的计算结果为false,则跳过其中一个选项(我想检查我的链内部是否没有空格,但不想实际生成空格标记并将其注入每个规则)。 我知道我可以用antlr捕捉异常,但它似乎只适用于全局规则范围。
我想我可以试试java代码。 例如,我有一些antlr4生成的java代码:

开关(get解释器().adaptivePredict(_input,117,_ctx)){
...
案例4:
{
_localctx=新的ChainExpressionContext(_localctx);
_ctx=_localctx;
_prevctx=_localctx;
设置状态(907);
链();
}
打破
...
案例34:
{
_localctx=新函数expressioncontext(_localctx);
_ctx=_localctx;
_prevctx=_localctx;
设置状态(953);
函数callnoparen();
}
打破
}
我想做的是这样的事情

boolean标志=true;
int _myalt=get解释器().adaptivePredict(_input,117,_ctx);
while(旗帜){
flag=false;
开关(_myalt){
...
案例4:
{
_localctx=新的ChainExpressionContext(_localctx);
_ctx=_localctx;
_prevctx=_localctx;
设置状态(907);
试一试{
链();
}捕获(FailedPredicateException){
如果(**还自适应预测此规则报告的歧义**){
flag=true;
_myalt=34;
持续
}
}
打破
...
}
}
甚至有可能(我的意思是这样的代码可能会以某种方式破坏整个antlr解析)?或者antlr有一些更好的方法,比如自定义错误处理

编辑 例如,我有语法

chain
    : chainBase memberAccess*
    ;

expression
    : ...                                  
    | chain                                                                  
    ...
    | functionCallNoParen                                                   
    ;
我想解析不明确的短语(对于具有一个通道的解析器,默认情况下忽略隐藏的标记,此输入看起来完全相同)

根据内部的空白字符不同(第一个是functionCallNoParen,第二个是chain),所以我可以尝试以下内容

chain
    : chainBase {!isCurrentTokenAWhitespace()}? memberAccess*
    ;

这里出现了所描述的问题

我的MySQL语法中也有类似的问题,其中空格决定我是否必须处理紧跟开括号的关键字或查看函数调用。为此,我有一个谓词,根据一个或多个空格的存在,将关键字转换为普通标识符(最终由SQL模式控制)。在您的情况下,您可以使用
put
关键字来实现这一点。下面是一个示例:

ADDDATE_SYMBOL: A D D D A T E { setType(determineFunction(ADDDATE_SYMBOL)); }; // MYSQL-FUNC
单字母规则仅用于允许独立于大小写的关键字(例如,
A:'A'|'A';
)。您可以在此处查看完整语法:

函数
setType
来自ANTLR4运行时(这里是lexer实例),并且
determineFunction
是自定义lexer类中的一个成员函数,定义为:

size_t MySQLBaseLexer::determineFunction(size_t proposed) {
  // Skip any whitespace character if the sql mode says they should be ignored,
  // before actually trying to match the open parenthesis.
  if (isSqlModeActive(IgnoreSpace)) {
    size_t input = _input->LA(1);
    while (input == ' ' || input == '\t' || input == '\r' || input == '\n') {
      getInterpreter<atn::LexerATNSimulator>()->consume(_input);
      channel = HIDDEN;
      type = MySQLLexer::WHITESPACE;
      input = _input->LA(1);
    }
  }

  return _input->LA(1) == '(' ? proposed : MySQLLexer::IDENTIFIER;
}
size\u t MySQLBaseLexer::determineFunction(提议的大小){
//如果sql模式指示应忽略任何空格字符,请跳过它们,
//在实际尝试匹配开括号之前。
if(isSqlModeActive(信号空间)){
大小输入=\u输入->LA(1);
而(输入=“”| |输入=‘\t’| |输入=‘\r’| |输入=‘\n’){
get解释器()->消耗(_输入);
通道=隐藏;
type=MySQLLexer::WHITESPACE;
输入=_输入->LA(1);
}
}
return _input->LA(1)='('?建议:MySQLLexer::IDENTIFIER;
}

这应该足够感谢您的回答,但是
put
不是关键字,只是任何标识符。我实际上可以尝试在lexer中跳过空格的方法,但我不知道如何将您的
IgnoreSpace
与解析器链接,或者它甚至来自解析器。您当然可以在任何解析器或lex中使用这种方法er规则并在本机代码中进行验证(在输入流中回顾或向前)。该
IgnoreSpace
标志是基于当前SQL模式设置的lexer类中的一个成员。这与您没有实际关系,我留下它只是为了显示您可以根据某些外部条件做出决定(如果需要)(例如,根据某些标志或语言版本切换某些语言功能).问题是我无法确定我应该在哪里忽略空白,我想让antlr根据空白的存在情况选择正确的替代方案。我描述了它。所以我试图以某种方式克服它。你在antlr4过期时有这样的问题吗?
size_t MySQLBaseLexer::determineFunction(size_t proposed) {
  // Skip any whitespace character if the sql mode says they should be ignored,
  // before actually trying to match the open parenthesis.
  if (isSqlModeActive(IgnoreSpace)) {
    size_t input = _input->LA(1);
    while (input == ' ' || input == '\t' || input == '\r' || input == '\n') {
      getInterpreter<atn::LexerATNSimulator>()->consume(_input);
      channel = HIDDEN;
      type = MySQLLexer::WHITESPACE;
      input = _input->LA(1);
    }
  }

  return _input->LA(1) == '(' ? proposed : MySQLLexer::IDENTIFIER;
}