我们在课堂上给出了这样的语法:
grammar Calculator;
@header {
import java.util.*;
}
@parser::members {
/** "memory" for our calculator; variable/value pairs go here */
Map<String, Double> memory = new HashMap<String, Double>();
}
statlist : stat+ ;
stat : vgl NL #printCompare
| ass NL #printAssign
| NL #blank
;
ass : <assoc=right> VAR ('=') vgl #assign
;
vgl : sum(op=('<'|'>') sum)* #compare
;
sum : prod(op=('+'|'-') prod)* #addSub
;
prod : pot(op=('*'|'/') pot)* #mulDiv
;
pot :<assoc=right> term(op='^' pot)? #poten
;
term : '+' term #add
| '-' term #subtract
| '(' sum ')' #parens
| VAR #var
| INT #int
;
/*Rules for the lexer */
MUL : '*' ;
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
BIG : '>' ;
SML : '<' ;
POT : '^' ;
VAR : [a-zA-Z]+ ;
NL : [\n] ;
INT : [0-9]+ ;
WS : [ \r\t]+ -> skip ; // skip spaces, tabs
我在翻译像
这样的结构时遇到了问题sum : prod(op=('+'|'-') prod)* #addSub
进入工作代码。目前相应的方法如下所示:
/** prod(op=('+'|'-') prod)* */
@Override
public Double visitAddSub(CalculatorParser.AddSubContext ctx) {
double left = visit(ctx.prod(0));
if(ctx.op == null){
return left;
}
double right = visit(ctx.prod(1));
return (ctx.op.getType() == CalculatorParser.ADD) ? left+right : left-right;
}
当前输出看起来像这样
3+3+3
6.0
这显然是假的。如何在不触及语法的情况下让访问者正确访问节点?
答案 0 :(得分:0)
看看规则:
prod(op=('+'|'-') prod)*
看到*
?这意味着括号内的内容可以出现0次或更多次。
您的访问者代码假定只有一个或两个孩子prod
,但不会更多。这就是您看到6.0
的原因:解析器将3+3+3
放入上下文中,但您的访问者仅处理3+3
并将最终+3
退出。
因此,只需对所有while
和op
子项使用prod
循环,并将其累积到结果中。
答案 1 :(得分:0)
好的,在Lucas的帮助和op+=
的使用下,我设法解决了我的问题。它看起来很复杂但有效。
/** prod(op+=('+'|'-') prod)* */
@Override
public Double visitAddSub(CalculatorParser.AddSubContext ctx) {
Stack<Double> temp = new Stack<Double>();
switch(ctx.children.size()){
case 1: return visit(ctx.prod(0));
default:
Double ret = 0.0;
for(int i = 0; i < ctx.op.size(); i++){
if(ctx.op.get(i).getType()==CalculatorParser.ADD){
if(temp.isEmpty()) {
ret = visit(ctx.prod(i)) + visit(ctx.prod(i+1));
temp.push(ret);
} else {
ret = temp.pop() + visit(ctx.prod(i+1));
temp.push(ret);
}
} else {
if(temp.isEmpty()) {
ret = visit(ctx.prod(i)) - visit(ctx.prod(i+1));
temp.push(ret);
} else {
ret = temp.pop() - visit(ctx.prod(i+1));
temp.push(ret);
}
}
}
}
return temp.pop();
}
我们使用switch-case来确定此上下文有多少个孩子。如果超过3个,我们至少有2个运营商。然后我们使用单个运算符和堆栈来确定结果。