我有一个简单的数学表达式解析器,我想自己构建AST(意味着没有ast解析器)。但每个节点只能容纳两个操作数。所以2 + 3 + 4会产生这样的树:
+
/ \
2 +
/ \
3 4
问题是,我无法让我的语法进行递归,这里只是“添加”部分:
add returns [Expression e]
: op1=multiply { $e = $op1.e; Print.ln($op1.text); }
( '+' op2=multiply { $e = new AddOperator($op1.e, $op2.e); Print.ln($op1.e.getClass(), $op1.text, "+", $op2.e.getClass(), $op2.text); }
| '-' op2=multiply { $e = null; } // new MinusOperator
)*
;
但是在一天结束时,这将产生一棵树,如:
+
/ \
2 4
我知道问题出在哪里,这是因为“添加”可能永远或无限地出现(*),但我不知道如何解决这个问题。我想到了类似的东西:
“添加”部分:
add returns [Expression e]
: op1=multiply { $e = $op1.e; Print.ln($op1.text); }
( '+' op2=(multiply|add) { $e = new AddOperator($op1.e, $op2.e); Print.ln($op1.e.getClass(), $op1.text, "+", $op2.e.getClass(), $op2.text); }
| '-' op2=multiply { $e = null; } // new MinusOperator
)?
;
但是这会给我一个反复的错误。有什么想法吗?
答案 0 :(得分:1)
我没有完整的语法来测试此解决方案,但考虑将其替换(来自问题中的第一个add
规则):
$e = new AddOperator($op1.e, $op2.e);
有了这个:
$e = new AddOperator($e, $op2.e); //$e instead of $op1.e
这样,('+' multiply)*
上的每次迭代都会延伸e
而不是替换它。
可能需要花一点时间才能做到正确,或者您可能需要在规则中使用临时Expression
来管理事情。只需确保循环创建的最后一个表达式位于=
运算符右侧的某个位置,如$e = new XYZ($e, $rhs.e);
中所示。