如何从输入参数设置ANTLR标记值?

时间:2015-03-16 17:08:12

标签: antlr4 parser-generator

假设我在ANTLR 4中定义了一个非常简单的语法:

input : String Separator String ;
String : 'a'..'z' ;
Separator : ',' ;

对于这个语法,分隔符是固定的;它总是一个逗号。有没有办法让分隔符变量?也就是说,我想使用输入参数定义分隔符,该参数由调用lexer-parser的代码设置。我可以这样定义一个getter和setter:

@lexer::members
{
    String sep = ",";

    public void setSep(String sep)
    {
        this.sep = sep;
    }

    private String getSep()
    {
        return sep;
    }
}

但是如何在词法分析器规则中更改分隔符的值?这很接近,但错了:

Separator : ',' { setText(getSep()); } ;

2 个答案:

答案 0 :(得分:1)

在查看其他一些问题之后,我决定尝试使用语义谓词来解决这个问题。这是我的完整解决方案:

grammar InputCombinedGrammar;

@parser::members
{
    String sep = ",";

    public void setSep(String sep)
    {
        this.sep = sep;
    }

    private String getSep()
    {
        return sep;
    }
}

input : String { getSep().equals(_input.LT(1).getText()) }? Separator String EOF ;
String : 'a'..'z' ;
Separator : . ;

需要注意的两件事:

  1. 分隔符将匹配任何字符,而不仅仅是逗号。
  2. 语义谓词使用lookahead将下一个标记与分隔符进行比较。如果匹配,则规则继续。如果没有,则会抛出错误。
  3. 此解决方案信任语义谓词仅使用正确的分隔符。我对这个解决方案很满意,但我想看到别人。

答案 1 :(得分:1)

我会在词法分析器中处理它:

@lexer::members {
  ...
}

input : String Separator String EOF ;

Separator : { sep.equals(_input.LA(1).getText()) }? . ;
String : 'a'..'z' ;

如果您在解析器中执行此操作,那么在 Separator : . ;之后定义的所有规则永远不能是单个字符,因为它会被Separator规则捕获。