访客模式程序无法正常工作
Visitor pattern program doesn't work correct
我需要为计算器创建一个简单的编译器,我正在使用 antlr4 和访问者模式。
这是我的语法文件 Simple_Calculator.g4 :
grammar Simple_Calculator;
program : statements ;
statements : statement | statements statement ;
statement : identifier '=' expr ';' #assign
| 'begin' statements 'end' #brac
| 'if' expr 'then' statement #if
| 'if' expr 'then' statement 'else' statement #if_elset
| 'while' expr 'do' statement #while
| 'for' identifier '=' number ':' number 'do' statement #for
| 'print' identifier ';' #print
;
expr : expr binop expr #ope
| '!' expr #invert
| '(' expr ')' #parenthesis
| identifier #identify
| number #num
;
binop : '+'
| '-'
| '*'
| '/'
| '<'
| '>'
| '<='
| '>='
| '=='
| '!='
| '^'
;
identifier : STRING+('-'|STRING|INT)* ;
number : INT+('.'INT+)? ;
STRING: [a-zA-Z]+ ;
INT : [0-9]+ ;
WS : [ \t\r\n] -> skip ;
下面是 MainVisitor extends Simple_CalculatorBaseVisitor
class 中的 visitOpe
和 visitAssign
方法:
public class MainVisitor extends Simple_CalculatorBaseVisitor<Object> {
@Override
public Object visitAssign(Simple_CalculatorParser.AssignContext ctx) {
String id = (String) (visit(ctx.identifier()));
String value = (String)(visit(ctx.expr()));
if (storage.containsKey(id)) {
storage.replace(id, value);
} else {
storage.put(id, value);
}
return storage; //To change body of generated methods, choose Tools | Templates.
} // end of visitAssign
@Override
public Object visitOpe(Simple_CalculatorParser.OpeContext ctx) {
String leftOperand = (String) visit(ctx.expr(0));
String rightOperand = (String) visit(ctx.expr(1));
/*if (rightOperand.matches("^\d+$")) {
return rightOperand;
}*/
String Operation = ctx.binop().getText();
switch (Operation) {
case "+": {
leftOperand = setOperands(leftOperand);
rightOperand = setOperands(rightOperand);
return String.valueOf(Integer.parseInt(leftOperand) + Integer.parseInt(rightOperand));
}
case "-":
leftOperand = setOperands(leftOperand);
rightOperand = setOperands(rightOperand);
return String.valueOf(Integer.parseInt(leftOperand) - Integer.parseInt(rightOperand));
case "*":
leftOperand = setOperands(leftOperand);
rightOperand = setOperands(rightOperand);
return String.valueOf(Integer.parseInt(leftOperand) * Integer.parseInt(rightOperand));
case "/":
leftOperand = setOperands(leftOperand);
rightOperand = setOperands(rightOperand);
return String.valueOf(Integer.parseInt(leftOperand) / Integer.parseInt(rightOperand));
// the rest possible conditions
}
//other methods
}// end of visitOpe
问题是,当我想在赋值表达式中使用“-”运算符时,当程序读取 visitAssign
中的行 String value = (String)(visit(ctx.expr()));
时,它不会在那之后访问 visitOpe
,而是 returns 整个表达式。
例如,当我给出程序时:
i=5;
i=i+2;
print i;
作为输入,它工作正常。它将 i
作为标识符存储在 HashMap
中,在第二行中,它将向其添加 2 个单位并最终打印其值。
但是如果我将 i=i+2;
更改为 i=i-2
,它会存储初始值为 5 的 i
,但在第二行中,它不会通过 visitOpe
方法,而是通过它returns "i-2" 并将其存储为 i
的值,最后打印它。
'*' 和 '/' 运算符可以很好地作为加法。它只是关于'-',我不知道是什么问题。
那么,如何解决这个问题:
此致
有了那个语法片段
identifier : STRING+('-'|STRING|INT)* ;
i-2
是一个有效的标识符。一种选择是从标识符中删除 '-'
。
所以:
identifier : STRING+(STRING|INT)* ;
不同的观察,但如果您正在制作计算器或任何计算数学表达式的东西,您可能还会重新考虑您的 binop
优先级。在一个小组中,他们从上到下进行评估。它不像旧的 BNF 文法那样人们耍花招,高优先级的运算符掉到底部。因此,在您的情况下,像 3+2*5 这样的表达式会产生 25 而不是 13,因为加法的优先级高于乘法。请注意这个来自 Bart Kiers 优先级的优秀语法 (Mu) 是如何布局的:
expr
: expr POW<assoc=right> expr #powExpr
| MINUS expr #unaryMinusExpr
| NOT expr #notExpr
| expr op=(MULT | DIV | MOD) expr #multiplicationExpr
| expr op=(PLUS | MINUS) expr #additiveExpr
| expr op=(LTEQ | GTEQ | LT | GT) expr #relationalExpr
| expr op=(EQ | NEQ) expr #equalityExpr
| expr AND expr #andExpr
| expr OR expr #orExpr
| atom #atomExpr
;
最高优先级。
我需要为计算器创建一个简单的编译器,我正在使用 antlr4 和访问者模式。 这是我的语法文件 Simple_Calculator.g4 :
grammar Simple_Calculator;
program : statements ;
statements : statement | statements statement ;
statement : identifier '=' expr ';' #assign
| 'begin' statements 'end' #brac
| 'if' expr 'then' statement #if
| 'if' expr 'then' statement 'else' statement #if_elset
| 'while' expr 'do' statement #while
| 'for' identifier '=' number ':' number 'do' statement #for
| 'print' identifier ';' #print
;
expr : expr binop expr #ope
| '!' expr #invert
| '(' expr ')' #parenthesis
| identifier #identify
| number #num
;
binop : '+'
| '-'
| '*'
| '/'
| '<'
| '>'
| '<='
| '>='
| '=='
| '!='
| '^'
;
identifier : STRING+('-'|STRING|INT)* ;
number : INT+('.'INT+)? ;
STRING: [a-zA-Z]+ ;
INT : [0-9]+ ;
WS : [ \t\r\n] -> skip ;
下面是 MainVisitor extends Simple_CalculatorBaseVisitor
class 中的 visitOpe
和 visitAssign
方法:
public class MainVisitor extends Simple_CalculatorBaseVisitor<Object> {
@Override
public Object visitAssign(Simple_CalculatorParser.AssignContext ctx) {
String id = (String) (visit(ctx.identifier()));
String value = (String)(visit(ctx.expr()));
if (storage.containsKey(id)) {
storage.replace(id, value);
} else {
storage.put(id, value);
}
return storage; //To change body of generated methods, choose Tools | Templates.
} // end of visitAssign
@Override
public Object visitOpe(Simple_CalculatorParser.OpeContext ctx) {
String leftOperand = (String) visit(ctx.expr(0));
String rightOperand = (String) visit(ctx.expr(1));
/*if (rightOperand.matches("^\d+$")) {
return rightOperand;
}*/
String Operation = ctx.binop().getText();
switch (Operation) {
case "+": {
leftOperand = setOperands(leftOperand);
rightOperand = setOperands(rightOperand);
return String.valueOf(Integer.parseInt(leftOperand) + Integer.parseInt(rightOperand));
}
case "-":
leftOperand = setOperands(leftOperand);
rightOperand = setOperands(rightOperand);
return String.valueOf(Integer.parseInt(leftOperand) - Integer.parseInt(rightOperand));
case "*":
leftOperand = setOperands(leftOperand);
rightOperand = setOperands(rightOperand);
return String.valueOf(Integer.parseInt(leftOperand) * Integer.parseInt(rightOperand));
case "/":
leftOperand = setOperands(leftOperand);
rightOperand = setOperands(rightOperand);
return String.valueOf(Integer.parseInt(leftOperand) / Integer.parseInt(rightOperand));
// the rest possible conditions
}
//other methods
}// end of visitOpe
问题是,当我想在赋值表达式中使用“-”运算符时,当程序读取 visitAssign
中的行 String value = (String)(visit(ctx.expr()));
时,它不会在那之后访问 visitOpe
,而是 returns 整个表达式。
例如,当我给出程序时:
i=5;
i=i+2;
print i;
作为输入,它工作正常。它将 i
作为标识符存储在 HashMap
中,在第二行中,它将向其添加 2 个单位并最终打印其值。
但是如果我将 i=i+2;
更改为 i=i-2
,它会存储初始值为 5 的 i
,但在第二行中,它不会通过 visitOpe
方法,而是通过它returns "i-2" 并将其存储为 i
的值,最后打印它。
'*' 和 '/' 运算符可以很好地作为加法。它只是关于'-',我不知道是什么问题。
那么,如何解决这个问题:
此致
有了那个语法片段
identifier : STRING+('-'|STRING|INT)* ;
i-2
是一个有效的标识符。一种选择是从标识符中删除 '-'
。
所以:
identifier : STRING+(STRING|INT)* ;
不同的观察,但如果您正在制作计算器或任何计算数学表达式的东西,您可能还会重新考虑您的 binop
优先级。在一个小组中,他们从上到下进行评估。它不像旧的 BNF 文法那样人们耍花招,高优先级的运算符掉到底部。因此,在您的情况下,像 3+2*5 这样的表达式会产生 25 而不是 13,因为加法的优先级高于乘法。请注意这个来自 Bart Kiers 优先级的优秀语法 (Mu) 是如何布局的:
expr
: expr POW<assoc=right> expr #powExpr
| MINUS expr #unaryMinusExpr
| NOT expr #notExpr
| expr op=(MULT | DIV | MOD) expr #multiplicationExpr
| expr op=(PLUS | MINUS) expr #additiveExpr
| expr op=(LTEQ | GTEQ | LT | GT) expr #relationalExpr
| expr op=(EQ | NEQ) expr #equalityExpr
| expr AND expr #andExpr
| expr OR expr #orExpr
| atom #atomExpr
;
最高优先级。