首页 > 解决方案 > 如何为算术计算java解析器编写递归while循环

问题描述

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

'exp' ::= 术语 | 期限 + 经验 | 期限 - exp

术语 ::= 整数字面量

而且我已经完成了仅包含整数文字的单个术语的解析器,但是,我无法实现在字符串方程中解析操作的目标。

在这个应用程序中,我试图token通过 usingTokenizer.hasNext()方法检查是否存在下一个存在,如果token是类型,Token.Type.Add则返回一个新的 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;
        }

标签: javaparsinggrammartokenizearithmetic-expressions

解决方案


让我们来看看这个输入73 + 65

你打电话parse,哪个电话parseTermparseTerm然后循环令牌。对于第一个标记,它是一个文字,所以它被添加到Lit(PS:变量名以大写字母开头的风格不好)。然后+读取令牌并进入else, 调用parse. 现在再次parse调用parseLit,读取文字 for 65。令牌流现在为空,因此parseLit返回。parse也返回,因为令牌流仍然是空的(请注意,parse从未进入循环)。

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

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

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

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


推荐阅读