如何在 JavaScript 中编写算术表达式解析器,而不使用 eval 或构造函数?

如何在 JavaScript 中编写算术表达式解析器,而不使用 eval 或构造函数?

问题描述:

给定一个字符串:

 var str1 = "25*5+5*7";

如果不使用 eval 或 JavaScript 中的构造函数,我如何编写一个名为输出"的函数,它接受字符串并输出字符串的算术值,在这个案例是160?

Without using eval or the constructor function in JavaScript, how would I be able to write a function called "output" that takes in the string and outputs the arithmetic value of the string, which in this case is 160?

这是递归解析之后的完整优先级表达式求值器我在对 OP 问题的评论中链接到的想法.

Here's a full precedence expression evaluator following the recursive parsing idea I linked-to in a comment on the OP's question.

为此,我首先为我要处理的表达式编写了一个简单的 BNF 语法:

To do this, first I wrote a simple BNF grammar for the expressions I wanted to process:

sum =  product | sum "+" product | sum "-" product ;
product = term | product "*" term | product "/" term ;
term = "-" term | "(" sum ")" | number ;

这本身就需要一些经验才能简单直接地完成.如果您没有使用 BNF 的经验,您会发现它对于描述复杂的项目流非常有用,比如表达式、消息、编程语言……

This by itself requires a bit of experience to do simply and straightforwardly. If you have no experience with BNF you will find it incredibly useful for describing complex streams of items like expressions, messages, programming langauges, ...

使用该语法,我遵循了另一条消息中概述的程序生成以下代码.很明显,它是由语法以一种愚蠢的机械方式驱动的,因此如果您拥有该语法,就很容易编写.

Using that grammar, I followed the procedure outlined in the other message to produce the following code. It should be obvious that it is driven by grammar in a dumb mechanical way, and therefore pretty easy to write if you have that grammar.

(未经测试.我不是 JavaScript 编码员.这肯定会包含一些语法/语义小问题.我花了大约 15 分钟来编写代码.)

(Untested. I'm not a JavaScript coder. This will surely contain a few syntax/semantic hiccups. Took me at about 15 minutes to code.)

var SE="Syntax Error";

function parse(str) { // returns integer expression result or SE
   var text=str;
   var scan=1;
   return parse_sum();

   function parse_sum() { 
      var number, number2;
      if (number=parse_product()==SE) return SE;
      while (true) {
        skip_blanks();
        if (match("+") {
           number2=parse_product();
           if (number2==SE) return SE;
           number+=number2;
        }
        else if (match('-')) {
                { number2=parse_product();
                  if (number2==SE) return SE;
                  number-=number2;
                } 
             else return number;
      }
   }

   function parse_product() {
      var number, number2;
      if (number=parse_number()==SE) return SE;
      while (true) {
        if (match("*") {
            number2=parse_term();
            if (number2==SE) return SE;
            number*=number2;
          }
          else if (match('/')) {
                  number2=parse_term();
                  if (number2==SE) return SE;
                  number/=number2;
               }
               else return number; 
      }
   }

   function parse_term() {
      var number;
      skip_blanks();
      if (match("(")) {
         number=parse_sum();
         if (number=SE) return SE;
         skip_blanks();
         if (!match(")") return SE;
      }
      else if match("-") {
              number= - parse_term();
           }
           else if (number=parse_number()==SE) return SE;
      return number;
   }

   function skip_blanks() {
      while (match(" ")) { };
      return;
    }

    function parse_number() {
       number=0;
       if (is_digit()) {
          while (is_digit()) {}
          return number;
        }
        else return SE;
    }

    var number;
    function is_digit() { // following 2 lines are likely wrong in detail but not intent
       if (text[scan]>="0" && text[scan]<="9") {
          number=number*10+text[scan].toInt();
          return true;
       }
       else return false;
    }

   function match(c) {
       if (text[scan]==c)
          { scan++; return true }
       else return false;
    }
 }

编写此类解析器/评估器很简单.请参阅我关于如何构建解析器的 SO 回答(链接到如何构建评估器).

It is straightforward to code such parsers/evaluators. See my SO answer on how to build a parser (which links to how to how to build an evaluator).