使用Java的递归表达式求值程序

时间:2010-11-01 21:10:32

标签: java parsing recursion expression-evaluation

我打算写一个只进行加法和减法的表达式求值器。我有一个简单的算法来做到这一点;但是,我有一些实施问题。

我认为表达式为(它是一个字符串)

"(" <expression1> <operator> <expression2> ")"

这是我的算法

String evaluate( String expression )

   if expression is digit
      return expression

   else if expression is "(" <expression1> <operator> <expression2> ")"
      cut the brackets out of it
      expression1 = evaluate( <expression1> )
      operator = <operator>
      expression2 = evaluate( <expression2> )

   if operator is +
      expression1 + expression2

   else if operator is -
      expression1 - expression2 

我的问题是从表达式解析<expression1><operator><expression2>。我怎样才能做到这一点?

注意:我不是要求代码。我需要的只是一个想法。

谢谢,

-Ali

6 个答案:

答案 0 :(得分:7)

  

我的问题是解析&lt; expression1&gt;,   &LT;运营商GT;和&lt; expression2&gt;来自   表达

不要这样做,然后:)当你看到一个左括号时,你要对表达式进行递归调用。在表达结束时,要么你找到另一个操作符(所以你毕竟不在表达式的末尾),或者右括号,在这种情况下你从评价中返回。

答案 1 :(得分:3)

使用解析器生成器,例如JavaCUPANTLR。写下你的表达式的BNF并生成一个解析器。这是一个可以帮助您入门的示例语法:

Expression ::= Digit
            |  LeftBracket Expression Plus Expression RightBracket
            |  LeftBracket Expression Minus Expression RightBracket
            |  LeftBracket Expression RightBracket

自己做这件事的“hacky”方法是寻找第一个)回溯到最近的(看看中间的括号自由表达式,简单地拆分运算符符号并评估

答案 2 :(得分:3)

使用StringTokenizer将输入字符串拆分为括号,运算符和数字,然后迭代您的标记,对每个开放的parens进行递归调用,并为每个右括号退出方法。

我知道您没有要求代码,但这适用于有效输入:

public static int eval(String expr) {
    StringTokenizer st = new StringTokenizer(expr, "()+- ", true);
    return eval(st);
}

private static int eval(StringTokenizer st) {
    int result = 0;
    String tok;
    boolean addition = true;
    while ((tok = getNextToken(st)) != null) {
        if (")".equals(tok))
            return result;
        else if ("(".equals(tok))
            result = eval(st);
        else if ("+".equals(tok))
            addition = true;
        else if ("-".equals(tok))
            addition = false;
        else if (addition)
            result += Integer.parseInt(tok);
        else
            result -= Integer.parseInt(tok);
    }
    return result;
}

private static String getNextToken(StringTokenizer st) {
    while (st.hasMoreTokens()) {
        String tok = st.nextToken().trim();
        if (tok.length() > 0)
            return tok;
    }
    return null;
}

这需要更好地处理无效输入,但你明白了......

答案 3 :(得分:3)

我建议将中缀输入更改为后缀,然后对其进行评估,而不是减少表达式中缀。已经有很好的定义算法,并没有固有的多嵌套括号解析问题。

查看Shunting Yard Algorithm转换为postfix / RPN,然后使用Postfix Operations使用堆栈对其进行评估。这很快(O(n))且可靠。

HTH

答案 4 :(得分:1)

我建议采用一种更接近于this中描述的方法,但(在我看来)关于编译器设计的相关系列文章。我发现使用解析表达式部分的小函数/方法非常有效。

这种方法允许您将解析方法分解为许多子方法,这些子方法的名称和执行顺序紧跟在您可能用来描述要解析的表达式的EBNF之后。

答案 5 :(得分:-2)

也许为表达式运算符创建regular expressions,然后使用匹配来识别和分解您的内容。