自著——30天自制红孩儿解释器 第6天 支持更多的操作符

自著——30天自制红孩儿解释器  第6天   支持更多的操作符

在第5天时,已经实现了带括号的四则混合运算的式子的计算。
为了在以后能够实现 对条件语句的解释执行,现在需要加上关系操作符
与逻辑操作符。

优先级是 运算操作符 优先于 关系操作符,关系操作符优先于逻辑操作符。

关系操作符的解释执行的结果只有真与假两种值。分别用1和0 来表示。1表示真。
表达式的BNF定义在第5天的基础上,增加以下的内容。

<relation_exp> :== <simple_exp> > <simple_exp> |<simple_exp> < <simple_exp> |
                   <simple_exp> >= <simple_exp> |<simple_exp> <= <simple_exp> |
           <simple_exp> == <simple_exp> |<simple_exp> != <simple_exp>
<boolean_exp> :==<relation_exp> |<relation_exp> && <relation_exp> |
                 <relation_exp> ||<relation_exp> |  <relation_exp> ^^ <relation_exp>

第6天第一版本的程序
需求: 实现 例如以下的关系表达式的执行。 5 > 4 , 5+9 == 14
实现: 因为关系操作符与运算操作符不在同一个优先级上,所以需要新开发
parse_relation_exp 函数,进行解析。
在执行函数中,也需要新增加 相应的执行函数。

形如以下的关系表达式,只能解析到第二个关系操作符之前的部分。
9<(2*(1+(5*5)))-6>((1+2)*3)+1 > ((9))

本版程序,在执行程序中,修改了逻辑错误,扩展了程序的适用范围。由原来的只能计算
整数的对象,扩展到有理数。新增了小数作为运算对象。

同时把 程序上用于执行的程序部分,与之相关的十多个函数独立成一个函数库,放在一个
单独的文件中,便于管理与维护。函数的名称进行了相关的规范化命名。
例如以下的修改。
addcalc --->execute_calc_add
subcalc ---->execute_calc_subtraction
mulcalc ----> execute_calc_multiply
divcalc  ---->execute_calc_divide
新的函数命名,更好的体现了函数的模块性。


第6天第二版本的程序
需求:在今天上一版本的基础上,实现 例如 以下的逻辑表达式的执行。 5 >4 && 5+9==14
      
第6天第三版本的程序
需求:功能与上一版本的相同。在执行过程中有优化的操作。  与逻辑操作符
的左侧 执行为假时,右侧的不需要再执行。直接返回值。
在或逻辑操作符的左侧 执行为真时,右侧的不需要再执行。 直接返回值。
新增加 异或逻辑操作.

<HTML>
<HEAD>
<TITLE> 30天自制解释器 6.1 </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<script src='get_token_general.js' ></script>
<script src='execute_lib.js' ></script>
</HEAD>
<BODY>
<p>本版本只能计算 a+b ,a-b,a*b ,a/b ,且本版有多个操作符,解析执行该表达式</p>
<p>允许有多个优先级存在  例如 : ((1+2)*3)+1 > ((9)) ,9< (2*(1+(5*5)))-6</p>
<p>a和b 都是正整数,而且 a 与 +,b 与+ 之间都可以有空格 </p>
<p>提供对括号改变运算的优先级的功能,本版本 支持多层嵌套的括号。和关系操作符</p>
<textarea id='txt1' rows="20" cols="80"></textarea>
<input type='button' value='执行' οnclick='eval()'>第六天第一版</input>
<textarea id='txt2' rows="20" cols="80"></textarea>
<script>
function eval()
{
var str=document.getElementById("txt1").innerText;
var result=0;
var token_array=[];

  token_array=get_token_general({"lineno":1,"linelength":str.length,"str":str},token_array);

  // result=parse_sim_exp(token_array,0,0);
     result=parse_relation_exp(token_array,0,0);
  // if (hasError(result.res)==0)
      // result=execute_exp(token_array);

document.getElementById("txt2").innerText=result.res;
}

function parse_relation_exp(arr,i,level)
{
       var operator1={};
   var operator2={};
   var result="";  

        operator1=  parse_sim_exp(arr,i,level);
        if(hasError(operator1.res)>=0)
              {
                 return {"res":operator1.res,"i":i};
              }
              else {result =operator1.res;
              i=operator1.i;
              }

   if (  i<arr.length-2 &&(arr[i+1].value=='>'||arr[i+1].value=='<'||arr[i+1].value=='>='||arr[i+1].value=='<='||arr[i+1].value=='=='||arr[i+1].value=='<>') )
     {
        operator2= parse_sim_exp(arr,i+2,level);
         if( hasError(operator2.res)==-1)
           {
         result=execute_binary_relation_operator_action(arr[i+1].value,result,operator2.res);
           i=operator2.i;
           }
         else if(hasError(operator2.res)>=0)
              {result=operator2.res;
             //  break;
              }
            
     }
    return {"res":result,"i":i};
}

function parse_sim_exp(arr,i,level)
{
   var operator1={};
   var operator2={};
   var result="";  

        operator1=  parse_term(arr,i,level);
        if(hasError(operator1.res)>=0)
              {
                 return {"res":operator1.res,"i":i};
              }
              else {result =operator1.res;
              i=operator1.i;
              }

   while(  i<arr.length-2 &&(arr[i+1].value=='+'||arr[i+1].value=='-') )
     {
        operator2= parse_term(arr,i+2,level);
         if( hasError(operator2.res)==-1)
           {
         result=execute_binary_calc_operator_action(arr[i+1].value,result,operator2.res);
           i=operator2.i;
           }
         else if(hasError(operator2.res)>=0)
              {result=operator2.res;
               break;
              }
            
     }
    return {"res":result,"i":i};
}

function parse_term(arr,i,level)
{
   var operator1=0;
   var operator2=0;
   var result="";
        operator1=  parse_factor(arr,i,level);
        if(hasError(operator1.res)>=0)
              {
               return {"res":operator1.res,"i":i};
              }
              else {result =operator1.res;
               i=operator1.i;}

   while( i<arr.length-2 &&(arr[i+1].value=='*'||arr[i+1].value=='/')  )
     {
        operator2= parse_factor(arr,i+2,level);

         if( hasError(operator2.res)==-1)
           {
           result=execute_binary_calc_operator_action(arr[i+1].value,result,operator2.res);
            i=operator2.i;
           }
         else if(hasError(operator2.res)>=0)
              {result=operator2.res;
               break;
              }

     }

    return {"res":result,"i":i};
}

function parse_factor(arr,i,level)
{
  var result=0;
  var resultObj={};

   if(arr[i].type==5)
     {result=arr[i].value;}
    else if (arr[i].type==7)
      {
         if (arr[i].value=='(')
         {
                 resultObj=parse_sim_exp(arr,i+1,level+1);
                 result=resultObj.res;
                 i=resultObj.i;
         }

          if (i<arr.length-1&& arr[i+1].value==')')
          {
                 i=i+1;
          }
          else if (i==arr.length-1 && arr[i]!=')')
              {
                   result='[error]: should be  ) : at '+arr[i].startindex+" but value: "+arr[i].value;
              }
          else
          {
              result='[error]: should be  ) : at '+arr[i].startindex+" but value: "+arr[i].value;
          }
      }
     else
       {result='[error]: is not number: at '+arr[i].startindex+" value: "+arr[i].value;}
    return {"res":result,"i":i};
}

function hasError(str)
{
 if(isNum(str)==1)
    return -1;
  else
  return str.indexOf("error");
}

function make_lisp_program_action(operand,operator1,operator2)
{
   return "("+ operand + " "+operator1+" "+operator2+")";
}

</script>
</BODY>
</HTML>
execute_lib.js文件的代码如下:
function execute_exp(arr)
{
   var start=0;
   var result=-1;
   var params=[];
     if (arr[start].type!=5)
        {start=1;}
    for (var i=start;i<arr.length-1;i+=2)
      {
          if(result==-1)
            {params.push(arr[i+1].value);
             params.push(arr[i+2].value);
             params.push(arr[i].value);
            }
          else
             {
                params=[];
                params.push(arr[i+1].value);
                params.push(arr[i+2].value);
                params.push(result);
             }
             result=execute_exp_bytwoOperators(params);
      }
      return result;
}

function execute_exp_bytwoOperators(arr)
{
   var result=0;
   var temp=arr;
      if (temp.length>1)
       {
          if(temp[0]=='+')
           {
              result=addcalc(temp[1],temp[2]);}
           else if (temp[0]=='-')
              {result=subcalc(temp[2],temp[1]);}
           else if(temp[0]=='*')
           {
              result=mulcalc(temp[1],temp[2]);}
           else if (temp[0]=='/')
              {result=divcalc(temp[2],temp[1]);}
       }
   else
    {result=temp[0]+"  can't eval"}
    return result;
}

function execute_binary_logic_operator_action(operand,oper1,oper2)
{
    var result=0;
          if(operand=='>')
           {
              result=execute_relation_greater(oper1,oper2);}
           else if (operand=='&&')
              {result=execute_logic_and(oper1,oper2);}
           else if(operand=='||')
           {
              result=execute_logic_or(oper1,oper2);}
           else if(operand=='^^')
           {
              result=execute_logic_xor(oper1,oper2);}
           else
               {result=operand+"  can't eval"}
    return result;
}
function execute_binary_relation_operator_action(operand,oper1,oper2)
{
    var result=0;
          if(operand=='>')
           {
              result=execute_relation_greater(oper1,oper2);}
           else if (operand=='<')
              {result=execute_relation_less(oper1,oper2);}
           else if(operand=='>=')
           {
              result=execute_relation_greaterEqual(oper1,oper2);}
           else if (operand=='<=')
              {result=execute_relation_lessEqual(oper1,oper2);}
           else if(operand=='<>')
           {
              result=execute_relation_notEqual(oper1,oper2);}
           else if (operand=='==')
              {result=execute_relation_Equal(oper1,oper2);}
           else
               {result=operand+"  can't eval"}
    return result;
}


function execute_binary_calc_operator_action(operand,oper1,oper2)
{
   var result=0;
          if(operand=='+')
           {
              result=execute_calc_add(oper1,oper2);}
           else if (operand=='-')
              {result=execute_calc_subtraction(oper1,oper2);}
           else if(operand=='*')
           {
              result=execute_calc_multiply(oper1,oper2);}
           else if (operand=='/')
              {result=execute_calc_divide(oper1,oper2);}
           else
               {result=operand+"  can't eval"}
    return result;
}

function execute_logic_and(oper1,oper2)
{
   if(oper1==0)
        return 0;
   if(oper1==1&&oper2==1)
       return 1;
    else
    {return 0;}
}

function execute_logic_or(oper1,oper2)
{
   if(oper1==1)
        return 1;
   if(oper1==0||oper2==1)
       return 1;
    else
    {return 0;}
}

function execute_logic_xor(oper1,oper2)
{
   if(oper1==oper2)
        return 0;
    else
    {return 1;}
}

function execute_logic_and(oper1,oper2)
{
   if(oper1==0)
        return 0;
   if(oper1==1&&oper2==1)
       return 1;
    else
    {return 0;}
}
//   relation  
function execute_relation_greater(oper1,oper2)
{
   if (oper1>oper2)
     return 1;
   else
      return 0;
}

function execute_relation_less(oper1,oper2)
{
   if (oper1<oper2)
     return 1;
   else
      return 0;
}

function execute_relation_greaterEqual(oper1,oper2)
{
   if (oper1>=oper2)
     return 1;
   else
      return 0;
}

function execute_relation_lessEqual(oper1,oper2)
{
   if (oper1<=oper2)
     return 1;
   else
      return 0;
}

function execute_relation_notEqual(oper1,oper2)
{
   if (oper1!=oper2)
     return 1;
   else
      return 0;
}

function execute_relation_Equal(oper1,oper2)
{
   if (oper1==oper2)
     return 1;
   else
      return 0;
}

//addcalc --->execute_calc_add
function execute_calc_add(operator1,operator2)
{
  return  parseFloat(operator1)+parseFloat(operator2);
}
// subcalc ----execute_calc_subtraction
function execute_calc_subtraction(operator1,operator2)
{
  return  parseFloat(operator1)-parseFloat(operator2);
}
//mulcalc ----> execute_calc_multiply
function execute_calc_multiply(operator1,operator2)
{
  return  parseFloat(operator1)*parseFloat(operator2);
}
//divcalc  ---->execute_calc_divide
function execute_calc_divide(operator1,operator2)
{
  var result =0;
     if (operator2!=0)
        { result=parseFloat(operator1)/parseFloat(operator2);
        }
      else
        { result='runtime error : div is 0.'}
  return  result;
}

get_token_general.js文件的代码如下:
//var b=[];
// a="int a,b;char c;c=a&&b;";
function get_token_general(a,b)
{
    var str='';
    var preState=0;
    var curState=0;
    var pretype=0;
    var curtype=0;
    var temp='';
    var tempString='';
    
    var id=b.length;
    var startindex=0;

  for(var i=0;i<a.linelength;i++)
  {
   
      str=a.str.substr(i,1);
      curtype=getType(str);
      curState=getState(preState,pretype,curtype);
      temp=str;

      if (curState==0)             //(preState==0&&curState==0)   //  stop
      {
        
           id=id+1;

           b.push({"id":id,"type":curtype,"value":temp,"lineno":a.lineno,"startindex":i});
        
      }
      else if (curState==1)           //(preState==0&&curState==1)  //jump up
      {
         startindex=i;
         tempString=temp;
      }
      else if (curState==3)         //(preState==1&&curState==0)  //jump down
      {
        id=id+1;
       b.push({"id":id,"type":pretype,"value":tempString,"lineno":a.lineno,"startindex":startindex});
      
        
        
           id=id+1;

           b.push({"id":id,"type":curtype,"value":temp,"lineno":a.lineno,"startindex":i});
        
        tempString='';
      }
      else if (curState==8)
      {
               id=id+1;
       b.push({"id":id,"type":pretype,"value":tempString,"lineno":a.lineno,"startindex":startindex});
      

       tempString='';
      }
      else if (curState==2)              //(preState==1&&curState==1)  //run
      {
         tempString=tempString+temp;
      }
      else if (curState==4)
      {
       id=id+1;
       b.push({"id":id,"type":pretype,"value":tempString,"lineno":a.lineno,"startindex":startindex});
      

          startindex=i;
           tempString=temp;
      }

      pretype=curtype;
      preState=curState;

   }
   if(tempString!='')
   {
              id=id+1;
       b.push({"id":id,"type":pretype,"value":tempString,"lineno":a.lineno,"startindex":startindex});
       
   }
  return b;
}

function getType(str)
{
   var type=0;    
      if(isAlphabet(str)==1)
      {
      type=1;    
      }
      else if(isDigit(str)==1)
      {
      type=5;    
      }
      else if (isDelimiter(str)==1)
      {
       type=6;      
      }
      else if (isBlock(str)==1)
      {
        type=7;
      }
      else if (isOperand(str)==1)
      {
        type=8;
      }
      else if ( isSpace(str)==1)
      {
         type=9;    
      }
      return type;
}
function getState(preState,pretype,curtype)
{
    var curState=0;
      if(preState==0||preState==9||preState==3||preState==8)
      {
        if(curtype==5||curtype==1)
          {curState=1;}
        else if(curtype==6||curtype==7)
          { curState=0;}
         else if(curtype==9)
         {curState=9;}
      }
      else if(preState==1||preState==2)
      {
             if(curtype==5)
              {
                if(pretype!=8)
                    {curState=2;}
                 else
                    {curState=4;}
              }    
             else if (curtype==1)
              {
                if(pretype==1)
                {curState=2;}
                else if (pretype==8)
                {curState=4;}
                else
                {curState=2;}
              }
             else if(curtype==6||curtype==7)
               { curState=3;}
              else if(curtype==8)
              {curState=4;}
             else if(curtype==9)
              {curState=8;}
      }
      else if (preState==4)
      {      if(curtype<=5&&pretype<=5)
             {
                 curState=2;
             }
             else if(curtype==6||curtype==7)
               { curState=3;}
              else if(curtype==8&&pretype==8)
              {curState=2;}
             else if(curtype==9)
              {curState=8;}
             else
               {curState=4;}
      }
      else
      {
         curState=0;
      }
      return curState;
}

function isAlphabet(str)
{
   var result=0;
   if(str>='a' &&str<='z'||(str>='A'&&str<='Z'))
     {
       result=1;
     }
  return result;
}

function isDigit(str)
{
   var result=0;
   if(str>='0' &&str<='9'||(str=='.'))
     {
       result=1;
     }
  return result;
}

/*4.3 版本时加上*/
function isNum(str)
{
    var result=1;
  for (var i=0; i<str.length ;i++ )
  {
      if (isDigit()!=1)
      {
           result=0;
           break;
      }
  }
  return result;
}

function isOperand(str)
{
 var result=0;
   if(str=='+')
   { result=1;}
      else if (str=='-')
   { result=1;}
    else if (str=='*')
   { result=1;}
    else if (str=='/')
   { result=1;}
   else if (str=='=')
   { result=1;}
    else if (str=='>')
   { result=1;}
   else if (str=='<')
   { result=1;}
   else if (str=='%')
    { result=1;}
    else if (str=='^')
   { result=1;}
    else if (str=='&')
   { result=1;}
   else if (str=='|')
   { result=1;}
   else if (str=='!')
   { result=1;}
   return result;     
}

function isDelimiter(str)
{
   var result=0;
   if(str==',')
   { result=1;}
   else if (str==';')
   { result=1;}
    else if (str==':')
   { result=1;}
 
   return result;
}

function isBlock(str)
{
 var result=0;
   if(str=='(')
   { result=1;}
      else if (str==')')
   { result=1;}
    else if (str=='{')
   { result=1;}
    else if (str=='}')
   { result=1;}
   else if (str=='[')
   { result=1;}
    else if (str==']')
   { result=1;}
   return result;
}


function isSpace(str)
{
 var result=0;
   if(str==' ')
   { result=1;}
   else if (str=='    ')
   { result=1;}

   return result;
}

上一篇:使用vscode写python报No such file or directory


下一篇:Oracle存储过程中EXECUTE IMMEDIATE 执行结果是空时怎么继续执行