如何为算数计算 java 解析器编写递归 while 循环

How to write a recursive while loop for arimethic calculation java parser

我已经用以下语法编写了算术计算解析器的代码

'exp' ::= 术语 |术语 + exp |术语 - exp

term ::=整数文字

并且我已经完成了对仅包含整数字面量的单个项的解析,但是,我无法实现字符串方程中解析操作的目的。

在此应用程序中,我尝试使用 Tokenizer.hasNext() 方法检查是否存在下一个 token,以及 token 的类型是否为 Token.Type.Add然后 return 一个带有当前文字项和操作的新 Exp 以及通过 parse() 方法解析的下一个 Exp。我已经定义了各种 类 例如 Token(String token, Type type),Exp(Term) / Exp(Term,Op,Exp),Term(Lit),Lit(int)

Tokenizer.takeNext() 将获取下一个标记并将其从当前标记器缓冲区中删除。 我根本无法从给定的方程式中解析运算符。

Parsing equation: 73 + 65 
73=73
Parsing equation: 10 - 4
10=10
Parsing equation: 7 + 9 + 10
7=7
Parsing equation: 5 - 1
5=5

这是我从学校讲座中学到的一般方法,不是作业问题。任何帮助将不胜感激。

public class Token {
    public enum Type {Unknown, Lit, Add, Minus, Multiply, Division};
    private String _token = "";
    private Type _type = Type.Unknown;
}
public enum Operation {
    None (""),
    Add ("+"),
    Sub ("-"),
    Mult ("*"),
    Div ("/");

    String op;
public class Exp {

    Term _term = null;
    Exp _exp = null;
    Operation _op = null;

    public Exp(Term term) {
        _term = term;
        _op = Operation.None;
    }

    public Exp(Term term, Operation op, Exp exp) {
        _exp = exp;
        _term = term;
        _op = op;
    }
     public Exp parse(){
        Exp term = parseTerm();
        while(_tokenizer.hasNext()) {
            Token token = _tokenizer.takeNext();
            if(token.type() == Token.Type.Add) {
                Operation op = Operation.Add;
                _tokenizer.next();
                Exp exp = parse();
                term = new Exp(term._term,op,exp);
                }
            }
        return term;
    }

    // <term>   ::= <integer literal>
    public Exp parseTerm(){
        Exp exp = null;
        String Lit = "";
        while(_tokenizer.hasNext()) {
            Token token = _tokenizer.takeNext();
            if(token.type() == Token.Type.Lit)
                Lit+=token.token();
            else
                parse();
            }
        Lit lit = new Lit(Integer.parseInt(Lit));
        Term term = new Term(lit);
        exp = new Exp(term);
        return exp;
        }

让我们来看看输入 73 + 65:

你调用 parse,它调用 parseTermparseTerm 然后遍历标记。对于第一个标记,它是一个文字,所以它被添加到 Lit (PS:变量名以大写字母开头不是好的风格)。然后 + 令牌被读取并进入 else,调用 parse。现在 parse 再次调用 parseLit,读取 65 的文字。令牌流现在为空,因此 parseLit returns。 parse也returns因为token流还是空的(注意parse里面的循环还没有进入)

parseparseLit 的值 return 是文字表达式 65,但 parseLit 从未实际使用该值。它只是调用 parse 并丢弃结果。

所以现在我们回到了 parseLit 的第一次调用,parse 刚刚 returned。所以令牌流是空的,我们退出循环。 Lit 的内容是“73”,因此这是对 parseLit 的调用 return 的内容。现在我们 return 第一次调用 parse,它只是 return 是 parseLit 的结果,因为同样,令牌流是空的,所以循环永远不会进入.

所以这里出了什么问题是您消耗了所有输入而没有实际为加法构建树。用于执行此操作的代码(即 parse 中的 while 循环)永远不会运行,因为由于 [=12= 中的循环,您已经在进入循环之前读取了所有标记] 和对 parse 的第二次调用(您丢弃其结果)。

term 的语法规则不使用 exp,因此 parseTerm 不应调用 parse。而且该规则也不是递归的,因此 parseTerm 不应包含循环。 parseTerm 应该做的就是读取一个应该是文字的标记,然后 return 相应的 Exp 对象。