使生成的解析器在 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));
我一直无法让生成的解析器在 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));