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

如何用JavaScript编写算术表达式解析器,而不使用eval或构造函数?,javascript,parsing,abstract-syntax-tree,recursive-descent,Javascript,Parsing,Abstract Syntax Tree,Recursive Descent,给定一个字符串: var str1 = "25*5+5*7"; 如果不使用JavaScript中的eval或构造函数,我如何编写一个名为“output”的函数来接收字符串并输出字符串的算术值(在本例中为160) 您可以创建一个新脚本: 函数解析(str){ var s=document.createElement('script'); s、 text=“window.result=“+str; document.body.appendChild;//运行脚本 document.body.r

给定一个字符串:

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

如果不使用JavaScript中的
eval
或构造函数,我如何编写一个名为“output”的函数来接收字符串并输出字符串的算术值(在本例中为160)

您可以创建一个新脚本:

函数解析(str){
var s=document.createElement('script');
s、 text=“window.result=“+str;
document.body.appendChild;//运行脚本
document.body.removeChild;//清理
return result;//返回结果
}

document.body.innerHTML=解析(“5*5+5*5”)这是一个具有*over+优先级的简单解析器。我试着让它尽可能有教育意义。我让你决定加减法。或者括号,如果你特别有野心的话

函数解析(str){
变量符号=[“*”,“+”];//按其求值顺序进行符号
var funcs=[multiply,add];//与符号关联的函数
var tokens=str.split(//\b/);//将字符串拆分为“tokens”(数字或符号)
对于(var round=0;round”);
对于(var place=0;place”);
tokens[place-1]=result.toString();//将结果存储为字符串
拼接(位置--,2);//删除过时的标记并备份一个位置
}
}
}
返回标记[0];//在结尾处,标记[]只有一项:结果
函数乘法(x,y){//实际进行数学运算的函数
返回x*y;
}
函数add(x,y){//实际进行数学运算的函数
返回x+y;
}
}
var str=“25*5+5*7”;

编写(“结果:+str+”=“+parse(str))在递归解析之后,这里有一个完全优先的表达式求值器 我在评论OP的问题时提到了这个想法

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

sum =  product | sum "+" product | sum "-" product ;
product = term | product "*" term | product "/" term ;
term = "-" term | "(" sum ")" | number ;
这本身就需要一点经验来简单而直接地做到。如果你没有BNF的经验,你会发现 它对于描述复杂的项目流(如表达式、消息、编程语言等)非常有用

使用该语法,我遵循了另一条消息中概述的过程 生成以下代码。很明显,它是由语法以一种愚蠢的机械方式驱动的,因此,如果你有语法的话,写起来相当容易

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

var SE=“语法错误”;
函数parse(str){//返回整数表达式结果或SE
var text=str;
var扫描=1;
返回parse_sum();
函数parse_sum(){
变量编号,编号2;
如果(number=parse_product()==SE)返回SE;
while(true){
跳过空格();
如果(匹配(“+”){
number2=解析_乘积();
如果(number2==SE)返回SE;
数字+=数字2;
}
else if(匹配('-')){
{number2=parse_乘积();
如果(number2==SE)返回SE;
数字-=数字2;
} 
否则返回号码;
}
}
函数parse_product(){
变量编号,编号2;
如果(number=parse_number()==SE)返回SE;
while(true){
如果(匹配(“*”){
number2=parse_term();
如果(number2==SE)返回SE;
数字*=数字2;
}
else if(匹配('/')){
number2=parse_term();
如果(number2==SE)返回SE;
数字/=数字2;
}
否则返回号码;
}
}
函数parse_term(){
var数;
跳过空格();
if(匹配(“”){
number=parse_sum();
如果(编号=SE)返回SE;
跳过空格();
如果(!match(“)”)返回SE;
}
否则,如果匹配(“-”){
number=-parse_term();
}
否则如果(number=parse_number()==SE)返回SE;
返回号码;
}
函数skip_blanks(){
while(匹配(“”){};
返回;
}
函数parse_number(){
数字=0;
如果(是_digit()){
while(is_digit()){}
返回号码;
}
否则返回SE;
}
var数;
函数为_digit(){//以下两行可能在细节上有误,但不是故意的

如果(text[scan]>=“0”&&text[scan]您可以使用以下表达式解析器:

var str1=“25*5+5*7”
document.write(str1+'='+math.eval(str1));
//输出:“25*5+5*7=160”

似乎是一个毫无意义的目标,特别是在那些明显的任意约束条件下。您实际上想做什么,为什么?您将编写一个简单的算术表达式解析器/计算器。数字可以是两位数吗?如果您要避免“eval”或者任何扭曲的变体,您需要实现一个解析器,用它来计算表达式
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;
    }
 }