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

use*_*336 7 javascript parsing recursive-descent abstract-syntax-tree

给定一个字符串:

 var str1 = "25*5+5*7";
Run Code Online (Sandbox Code Playgroud)

如果不使用evalJavaScript中的构造函数,我怎样才能编写一个名为"output"的函数,该函数接收字符串并输出字符串的算术值,在本例中为160?

Ira*_*ter 11

这是一个完整的优先级表达式求值程序,遵循我在OP问题的注释中链接的递归解析思想.

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

sum =  product | sum "+" product | sum "-" product ;
product = term | product "*" term | product "/" term ;
term = "-" term | "(" sum ")" | number ;
Run Code Online (Sandbox Code Playgroud)

这本身需要一些简单而直接的经验.如果您没有使用BNF的经验,您会发现它非常适用于描述复杂的项目流,如表达式,消息,编程语言,......

使用该语法,我按照其他消息中概述的过程生成以下代码.显而易见的是,它是以一种愚蠢的机械方式由语法驱动的,因此如果你有这种语法就很容易写.

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

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;
    }
 }
Run Code Online (Sandbox Code Playgroud)

编写这样的解析器/评估器是很简单的.请参阅我的答案,了解如何构建解析器(链接到如何构建求值程序).


Ori*_*iol 0

您可以创建一个新脚本:

function parse(str) {
  var s = document.createElement('script');
  s.text = "window.result = " + str;
  document.body.appendChild(s); // Run script
  document.body.removeChild(s); // Clean up
  return result;                // Return the result
}
document.body.innerHTML = parse("5*5+5*5");
Run Code Online (Sandbox Code Playgroud)

或者使用事件处理程序内容属性:

function parse(str) {
  var el = document.createElement('div');
  el.setAttribute('onclick', "this.result = " + str);
  el.onclick();     // Run script
  return el.result; // Return the result
}
document.body.innerHTML = parse("5*5+5*5");
Run Code Online (Sandbox Code Playgroud)

请注意,这些方法是不安全的,而且同样邪恶,eval甚至更丑陋。所以我不推荐他们。