使生成的解析器在 Java 中为 ANTLR 4.8 工作

Making generated parser work in Java for ANTLR 4.8

我一直无法让生成的解析器在 Java 中为 ANTLR 4.8 工作。这个问题还有其他答案,但似乎 ANTLR 自 4.7 以来已经发生了变化,所有其他答案都是在此变化之前。我的代码是:

    String formula = "(fm.a < fm.b) | (fm.a = fm.b)";
    CharStream input = CharStreams.fromString(formula);
    Antlr.LogicGrammerLexer lexer = new Antlr.LogicGrammerLexer(input);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    Antlr.LogicGrammerParser parser = new Antlr.LogicGrammerParser(tokens);
    ParseTree pt = new ParseTree(parser);

它似乎正在将公式正确读入 CharStream,但我过去尝试做的任何事情都根本不起作用。例如,如果我尝试打印出解析树,则什么也不会打印出来。以下行将不打印任何内容:

    System.out.println(lexer._input.getText(new Interval(0, 100)));

感谢任何建议。

编辑: 添加语法文件:

grammar LogicGrammer;

logicalStmt: BOOL_EXPR | '('logicalStmt' '*LOGIC_SYMBOL' '*logicalStmt')';
BOOL_EXPR: '('IDENTIFIER' '*MATH_SYMBOL' '*IDENTIFIER')';
IDENTIFIER: CHAR+('.'CHAR*)*;
CHAR: 'a'..'z' | 'A'..'Z' | '1'..'9';
LOGIC_SYMBOL: '~' | '|' | '&';
MATH_SYMBOL: '<' | '≤' | '=' | '≥' | '>';

这一行:

ParseTree pt = new ParseTree(parser);

不正确。您需要在您的解析器对象上调用开始规则方法来获取您的解析树

Antlr.LogicGrammerParser parser = new Antlr.LogicGrammerParser(tokens);
ParseTree pt = parser.logicalStmt();

就打印出您的输入而言,通常以 _(如 _input)开头的字段不适合外部使用。尽管我怀疑失败可能是因为您的输入流中没有 100 个字符,所以 Interval 无效。 (我没试过看具体失败)

如果你包括你的语法,我们中的一个人可以很容易地尝试生成和编译,也许更具体。


使用你的语法,这对我有用:

import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.tree.ParseTree;

public class Logic {
    public static void main(String... args) {
        String formula = "(fm.a < fm.b) | (fm.a = fm.b)";
        CharStream input = CharStreams.fromString(formula);
        LogicGrammerLexer lexer = new LogicGrammerLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        LogicGrammerParser parser = new LogicGrammerParser(tokens);
        ParseTree pt = parser.logicalStmt();
        System.out.println(pt.toStringTree());
        System.out.println(input.getText(new Interval(1, 28)));
    }
}

输出:

([] (fm.a < fm.b))
fm.a < fm.b) | (fm.a = fm.b)

顺便说一句,对您的语法提出一些小建议:

  • 设置规则 skip 空格 WS: [ \t\r\n]+ -> skip;
  • BOOL_EXPR 更改为解析器规则(因为它由来自其他词法分析器规则的标记组成:
grammar LogicGrammer
    ;

logicalStmt
    : boolExpr
    | '(' logicalStmt LOGIC_SYMBOL logicalStmt ')'
    ;
boolExpr:     '(' IDENTIFIER MATH_SYMBOL IDENTIFIER ')';
IDENTIFIER:   CHAR+ ('.' CHAR*)*;
CHAR:         'a' ..'z' | 'A' ..'Z' | '1' ..'9';
LOGIC_SYMBOL: '~' | '|' | '&';
MATH_SYMBOL:  '<' | '≤' | '=' | '≥' | '>';
WS:           [ \t\r\n]+ -> skip;

BOOL_EXPR 不应该是词法分析器规则。我建议你改为这样做:

grammar LogicGrammer;

parse
 : logicalStmt EOF
 ;

logicalStmt
 : logicalStmt LOGIC_SYMBOL logicalStmt
 | logicalStmt MATH_SYMBOL logicalStmt
 | '(' logicalStmt ')'
 | IDENTIFIER
 ;

IDENTIFIER
 : CHAR+ ( '.'CHAR+ )*
 ;

LOGIC_SYMBOL
 : [~|&]
 ;

MATH_SYMBOL
 : [<≤=≥>]
 ;

SPACE
 : [ \t\r\n] -> skip
 ;

fragment CHAR
 : [a-zA-Z1-9]
 ;

可通过运行以下代码进行测试:

String formula = "(fm.a < fm.b) | (fm.a = fm.b)";
LogicGrammerLexer lexer = new LogicGrammerLexer(CharStreams.fromString(formula));
LogicGrammerParser parser = new LogicGrammerParser(new CommonTokenStream(lexer));
ParseTree root = parser.parse();
System.out.println(root.toStringTree(parser));