我在使用antlr4.1生成解析器时遇到了一个大问题 语法由以下2个文件组成:
grammar Common;
identifierNum: hostId DOT observableId DOT method ':Num';
identifierString: hostId DOT observableId DOT method ':String';
hostId: ID;
observableId: ID;
method: ID'('')';
MUL: '*';
DIV: '/';
ADD: '+';
SUB: '-';
DOT: '.';
MIN: '<';
MAX: '>';
ID: [a-zA-Z0-9]+;
STRING: '\''[a-zA-Z0-9]+ '\'';
DIGIT: [0-9]+ ;
DOUBLE: [0-9]* DOT [0-9]+ ;
WS: [ \n\t]+ -> skip;
和这个文件
grammar Expression;
import Common;
expression: stringExpr # StringExpression
| numExpr # NumExpression
;
stringExpr: stringExpr ADD stringExpr # Concat
| STRING # BaseStr
| identifierString # IdString
| '(' stringExpr ')' # ParensString
;
numExpr: numExpr op=(MUL|DIV) numExpr # MulDiv
| numExpr op=(ADD|SUB) numExpr # AddSub
| DIGIT # Int
| DOUBLE # Double
| identifierNum # IdNum
| '(' numExpr ')' # ParensNum
;
我使用antlr工具生成了访问者
antlr_grammars/Expression.g4 -o src/test -no-listener -visitor -package test.antlr_grammars
我创建了这个类
public class Visitor extends ExpressionBaseVisitor<Value> {
@Override
public Value visitIdentifierString(IdentifierStringContext ctx) {
System.out.println("visit idString");
String i = "aaa";
return new Value(i);
}
@Override
public Value visitIdentifierNum(IdentifierNumContext ctx) {
System.out.println("visit identifierNum");
System.out.println("visit " + ctx.getText());
String i = "100";
if (i.contains(".")){
double value = Double.parseDouble(i);
return new Value(value);
}
else {
int value = Integer.parseInt(i);
return new Value(value);
}
}
@Override
public Value visitNumExpression(NumExpressionContext ctx) {
System.out.println("visit NumExpr");
System.out.println("visit" + ctx.getText());
return visit(ctx.numExpr());
}
@Override
public Value visitStringExpression(StringExpressionContext ctx) {
System.out.println("visit StringExpr");
return visit(ctx.stringExpr());
}
@Override
public Value visitDouble(DoubleContext ctx) {
System.out.println("visit double");
System.out.println("visit" + ctx.getText());
String str = ctx.getText();
double i = Double.parseDouble(str);
return new Value(i);
}
@Override
public Value visitInt(IntContext ctx) {
System.out.println("visit Int");
System.out.println("visit " + ctx.getText());
String str = ctx.getText();
Integer i = Integer.parseInt(str);
return new Value(i);
}
@Override
public Value visitBaseStr(BaseStrContext ctx) {
System.out.println("visit baseString");
String str = ctx.getText();
return new Value(str);
}
@Override
public Value visitAddSub(AddSubContext ctx) {
System.out.println("visit addSub");
System.out.println("visit" + ctx.getText());
Value leftVal = visit(ctx.numExpr(0));
Value rightVal = visit(ctx.numExpr(1));
if (ctx.op.getType() == ExpressionParser.ADD) {
if (leftVal.getType().toString() == "INT"
&& rightVal.getType().toString() == "INT") {
int left = visit(ctx.numExpr(0)).intVal();
int right = visit(ctx.numExpr(1)).intVal();
return new Value(left + right);
} else if (leftVal.getType().toString() == "DOUBLE"
&& rightVal.getType().toString() == "DOUBLE") {
double left = visit(ctx.numExpr(0)).doubleVal();
double right = visit(ctx.numExpr(1)).doubleVal();
return new Value(left + right);
} else if (leftVal.getType().toString() == "INT"
&& rightVal.getType().toString() == "DOUBLE") {
double left = (double) visit(ctx.numExpr(0)).intVal();
double right = visit(ctx.numExpr(1)).doubleVal();
return new Value(left + right);
} else {
double left = visit(ctx.numExpr(0)).doubleVal();
double right = (double) visit(ctx.numExpr(1)).intVal();
return new Value(left + right);
}
} else {
if (leftVal.getType().toString() == "INT"
&& rightVal.getType().toString() == "INT") {
int left = visit(ctx.numExpr(0)).intVal();
int right = visit(ctx.numExpr(1)).intVal();
return new Value(left - right);
} else if (leftVal.getType().toString() == "DOUBLE"
&& rightVal.getType().toString() == "DOUBLE") {
double left = visit(ctx.numExpr(0)).doubleVal();
double right = visit(ctx.numExpr(1)).doubleVal();
return new Value(left - right);
} else if (leftVal.getType().toString() == "INT"
&& rightVal.getType().toString() == "DOUBLE") {
double left = (double) visit(ctx.numExpr(0)).intVal();
double right = visit(ctx.numExpr(1)).doubleVal();
return new Value(left - right);
} else {
double left = visit(ctx.numExpr(0)).doubleVal();
double right = (double) visit(ctx.numExpr(1)).intVal();
return new Value(left - right);
}
}
}
@Override
public Value visitMulDiv(MulDivContext ctx) {
System.out.println("visit MulDiv");
System.out.println("visit" + ctx.getText());
Value leftVal = visit(ctx.numExpr(0));
Value rightVal = visit(ctx.numExpr(1));
if (ctx.op.getType() == ExpressionParser.MUL) {
if (leftVal.getType().toString() == "INT"
&& rightVal.getType().toString() == "INT") {
int left = visit(ctx.numExpr(0)).intVal();
int right = visit(ctx.numExpr(1)).intVal();
return new Value(left * right);
} else if (leftVal.getType().toString() == "DOUBLE"
&& rightVal.getType().toString() == "DOUBLE") {
double left = visit(ctx.numExpr(0)).doubleVal();
double right = visit(ctx.numExpr(1)).doubleVal();
return new Value(left * right);
} else if (leftVal.getType().toString() == "INT"
&& rightVal.getType().toString() == "DOUBLE") {
double left = (double) visit(ctx.numExpr(0)).intVal();
double right = visit(ctx.numExpr(1)).doubleVal();
return new Value(left * right);
} else {
double left = visit(ctx.numExpr(0)).doubleVal();
double right = (double) visit(ctx.numExpr(1)).intVal();
return new Value(left * right);
}
} else {
if (leftVal.getType().toString() == "INT"
&& rightVal.getType().toString() == "INT") {
int left = visit(ctx.numExpr(0)).intVal();
int right = visit(ctx.numExpr(1)).intVal();
return new Value(left / right);
} else if (leftVal.getType().toString() == "DOUBLE"
&& rightVal.getType().toString() == "DOUBLE") {
double left = visit(ctx.numExpr(0)).doubleVal();
double right = visit(ctx.numExpr(1)).doubleVal();
return new Value(left / right);
} else if (leftVal.getType().toString() == "INT"
&& rightVal.getType().toString() == "DOUBLE") {
double left = (double) visit(ctx.numExpr(0)).intVal();
double right = visit(ctx.numExpr(1)).doubleVal();
return new Value(left / right);
} else {
double left = visit(ctx.numExpr(0)).doubleVal();
double right = (double) visit(ctx.numExpr(1)).intVal();
return new Value(left / right);
}
}
}
@Override
public Value visitConcat(ConcatContext ctx) {
System.out.println("visit Concat");
String string1 = visit(ctx.stringExpr(0)).stringVal();
String string2 = visit(ctx.stringExpr(1)).stringVal();
return new Value(string1.concat(string2));
}
@Override
public Value visitIdString(IdStringContext ctx) {
return visit(ctx.identifierString());
}
@Override
public Value visitIdNum(IdNumContext ctx) {
System.out.println("visit idNum");
System.out.println("visit " + ctx.getText());
return visit(ctx.identifierNum());
}
@Override
public Value visitParensString(ParensStringContext ctx) {
System.out.println("visit parensString");
return visit(ctx.stringExpr());
}
@Override
public Value visitParensNum(ParensNumContext ctx) {
System.out.println("visit parensNum");
return visit(ctx.numExpr());
}
}
问题是我的语法可能不明确,因为如果我编写一些操作,我只会收到以下消息“输入时没有可行的替代方案...” 实际上,我找到了另一种方法来解决这个问题(添加 :Num 和 :String 来区分不同类型的输入),但我想使用这种语义。
我的主要内容如下
public static void main(String args[]) {
String expr1 = "10" ;
System.out.println("Result = " + parse(expr1));
}
private static final String parse(String expression) {
ANTLRInputStream input = new ANTLRInputStream(expression);
ExpressionLexer lexer = new ExpressionLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpressionParser testParser = new ExpressionParser(tokens);
ParseTree parseTree = testParser.expression();
Visitor visitor = new Visitor();
return String.valueOf(visitor.visit(parseTree));
}
}
不明白哪里错了。 感谢您的帮助 =)
最佳答案
您的 Java 代码中有很多问题:
leftVal.getType().toString() == "DOUBLE"
切勿使用 ==
进行字符串相等性检查!
阅读此内容:How do I compare strings in Java? ,并真正理解它。
但是您不应该从一开始就比较字符串。相反,比较整数类型:
leftVal.getType() == ExpressionParser.DOUBLE
这对我来说毫无意义:
String i = "100";
if (i.contains(".")){
...
事实上,您收到没有可行的替代方案消息是因为您的输入“10”
被标记为ID
。这是因为 ID
token 仅匹配数字,就像 DIGIT
规则一样:
ID: [a-zA-Z0-9]+;
...
DIGIT: [0-9]+ ;
并且由于 ID
是在 DIGIT
之前定义的,因此它具有优先权。要么包含 ID
作为 numExpr
替代方案,要么让 ID
标记以字母开头:
ID: [a-zA-Z] [a-zA-Z0-9]*;
关于java - 使用antlr4的二义性语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23617940/