【问题标题】:Java - extending on a simple recursive descent parserJava - 扩展一个简单的递归下降解析器
【发布时间】:2015-06-17 16:09:14
【问题描述】:

我编写了这个简单的递归解析器方法,它计算简单的算术表达式(仅由 +、-、* 和 / 组成)。

但是,我目前被困在一些事情上:

  1. 如何实现括号识别?
  2. 如何实现一元运算符的识别?例如一元减号 (-) 和阶乘 (!)
  3. 如何实现功能识别?例如罪(x)

    private static double eval(String s) {
    
        if (s.charAt(0) == '-' || s.charAt(0) == '+') {
            s = "0" + s;
        }
    
        if (s.indexOf("+") > -1) {
            return (eval(s.substring(0, s.indexOf("+"))) + eval(s.substring(s.indexOf("+") + 1, s.length())));
        } else if (s.indexOf("-") > -1) {
            return (eval(s.substring(0, s.indexOf("-"))) - eval(s.substring(s.indexOf("-") + 1, s.length())));
        } else if (s.indexOf("*") > -1) {
            return (eval(s.substring(0, s.indexOf("*"))) * eval(s.substring(s.indexOf("*") + 1, s.length())));
        } else if (s.indexOf("/") > -1) {
            return (eval(s.substring(0, s.indexOf("/"))) / eval(s.substring(s.indexOf("/") + 1, s.length())));
        } else if (s.indexOf("^") > -1) {
            return (Math.pow(evaluate(s.substring(0, s.indexOf("^"))), evaluate(s.substring(s.indexOf("^") + 1, s.length()))));
        }
    
        return Double.parseDouble(s);
    }
    

感谢任何帮助。提前致谢!

【问题讨论】:

  • 你听说过反向波兰表示法吗? en.wikipedia.org/wiki/Reverse_Polish_notation 还是必须递归?
  • 是的,我已经使用堆栈完成了一个数学解析器(使用 shuntingyard 从中缀转换为后缀)。这个必须是递归的:/

标签: java parsing recursion


【解决方案1】:

它看起来很宽泛,但我会尝试在这里提出我的想法,而不是难以理解的评论。

  1. 寻找括号可能会很棘手,因为有一些用于优先级,而另一些用于函数参数。我要做的是首先查找'('。如果它遵循函数,则跳过它,否则遍历所有字符,直到'('==')'的数量,这就是你传递给 eval , 之前、之间 () 和之后) 的所有内容都将单独调用 eval()。

  2. 对于一元运算符“-”,您很可能需要查找表达式中的前一个字符。比如:

    } else if (s.indexOf("-") > -1) { // keeping this index would make more sense now
       if char at index -1 from '-' in list of characters indicating unary operator
          return -eval(s.substring(s.indexOf("-")+1, s.length())));
    
    else {
    return (eval(s.substring(0, s.indexOf("-"))) - 
      eval(s.substring(s.indexOf("-") + 1, s.length())));
        }
    }
    

这些字符绝对是括号、其他运算符,或者如果 '-' 的索引为 0。请问自己如何识别一元运算符并在此处应用相同的规则。

同样的方法也适用于 '!':

if(s.indexOf("!") > -1) {
    return fact(eval(s.substring(s.indexOf("-") + 1, s.length())));
}

编辑: 正如 OP 正确注意到的那样,这种方法会跳过一些表达式部分,所以对函数和一元运算符要做什么:

return eval(everything before + eval(expression)+ everything after);
  1. 函数看起来和一元运算符一模一样,你只需要弄清楚优先级,所以在查找运算符之前先识别'sin('。然后应用与一元运算符相同的方法。 如果找到函数,则删除最后的右括号。

    return fun(eval(rest of expression));
    

希望这些想法对您有所帮助。

【讨论】:

  • 我不太明白你的一元减号逻辑是如何工作的 - 它说return -eval(s.substring(s.indexOf("-")+1, s.length()));?
  • 表示计算'-'右侧的表达式并将符号更改为'-'。当我想到它时,对于递归,替换对一元运算符的调用然后评估表达式会更有意义。请参阅已编辑的 pts2 和 3。
  • 但是'-'左边的东西不会被忽略吗?
  • return eval(everything before + eval(expression)+ everything after);
  • 你在一元'-'上分割字符串。之前的内容以字符串的形式出现在这里。作为“-”参数的表达式将是:1) 函数或 2) 数字。涵盖这两种情况,剩下的就是表达式之后的内容。括号中的表达式将在前面介绍,因此您已经 - for number 了。让它递归工作并不是那么简单,这就是我建议堆叠方法的原因。
猜你喜欢
  • 1970-01-01
  • 2021-11-09
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 2012-05-21
  • 1970-01-01
相关资源
最近更新 更多