【问题标题】:Making generated parser work in Java for ANTLR 4.8使生成的解析器在 Java 中为 ANTLR 4.8 工作
【发布时间】:2022-01-11 05:03:12
【问题描述】:

我一直无法让生成的解析器在 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: '<' | '≤' | '=' | '≥' | '>';

【问题讨论】:

    标签: java antlr4


    【解决方案1】:

    这一行:

    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]+ -&gt; 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;
    

    【讨论】:

    • 感谢您的帮助,这真的很有帮助。我现在已经添加了语法文件。我只有一个规则,但是当我查看解析器对象上的完整代码时,我看不到任何返回 ParseTree 的方法。有什么想法吗?
    • 为了更具体地了解我正在尝试做的事情 - 我正在尝试从字符串公式中提取所有 BOOL_EXPR 叶节点(例如 (fm.a
    【解决方案2】:

    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));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 2012-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多