如何用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;
}
}