递归下降方式的运算解析器

来源:互联网 发布:linux的head命令 编辑:程序博客网 时间:2024/05/16 12:37

做了递归下降方式的运算解析器(C#),支持变量定义与运算 :

using System;

namespace ParserSpace
{
 /// <summary>
 /// 解析器类Parser
 /// </summary>
 public sealed class Parser
 {
  //Array for variables
  private double[] vars = new double[26];

  //令牌类型
  enum tokenEnum{NONE,DELIMITER,VARIABLE,NUMBER};

  //语法错误类型
  int SYNTAX=0;
  int UNBALPARENS=1;
  int NOEXP=2;
  int DIVBYZERO=3;

  //表达式完
  string EOE="/0";

  public string exp;  //表达式
  int expIdx;  //表达式当前指针
  public string token;//当前的令牌
  tokenEnum tokType; //当前的令牌类型

  //取得下一个令牌
  public  void getToken()
  {
    tokType=tokenEnum.NONE;
    token="";

    //检查表达式是否取完
    if(expIdx==exp.Length)
    {
     token=EOE;
     return;
    }

    //如果是空格则跳过
    while(expIdx<exp.Length&&(exp[expIdx]==' '))++expIdx;

    //是不是空格完了命令行也完成了
    if(expIdx==exp.Length)
    {
     token=EOE;
     return;
    }

    if(exp[expIdx]==':')   //如果冒号
    {
     token+=exp[expIdx];
     expIdx++;
     tokType=tokenEnum.DELIMITER;
    }
    else
     if (isDelim(exp[expIdx]))  //如果是操作符
     {
    token+=exp[expIdx];
    expIdx++;
    tokType=tokenEnum.DELIMITER;
     }
     else if((('a'<=exp[expIdx])&&('z'>=exp[expIdx]))||
       (('A'<=exp[expIdx])&&('Z'>=exp[expIdx])))
       //如果是变量
    {
       while(!isDelim(exp[expIdx]))
       {
        token+=exp[expIdx];
        expIdx++;
        if(expIdx>=exp.Length)
        break;
       }
       tokType=tokenEnum.VARIABLE;
      }
      else if (('0'<=exp[expIdx])&&('9'>=exp[expIdx]))  //如果是数字
     {
        while(!isDelim(exp[expIdx]))
        {
         token+=exp[expIdx];
         expIdx++;
         if(expIdx>=exp.Length)
        break;
        }
      tokType=tokenEnum.NUMBER;
     }
     else  //不可识别的终结表达式
     {
      token=EOE;
      return ;
     }
  }

  //如果是一个分隔符则返回真值
  private bool isDelim(char c)
  {
   if ((" +-/*%^=()".IndexOf(c)!=-1))
    return true;
   return false;
  }


  //解析器入口程序
  public double evaluate(string expstr)
  {
   double result=0.0;
   exp=expstr;
   expIdx=0;


   getToken();
   if(token.Equals(EOE))
    handleErr(NOEXP); //表示没有表达式

   //解析并计算表达式
   result=evalExp1();

   if(!token.Equals(EOE))
    handleErr(SYNTAX);

      return result;
  }

  //处理赋值
  private double evalExp1()
  {
   double result;
   int varIdx;
   tokenEnum ttokType;
   string temptoken;

   if (tokType==tokenEnum.VARIABLE)
   {
    //保存旧值
    temptoken=token;
    ttokType=tokType;

    //计算变量的索引
    varIdx=char.ToUpper(token[0])-'A';

    getToken();
    if (token.Equals('='))
    {
    putBack();  //返回当前的令牌
    //恢复老的令牌 (非赋值)
    token=temptoken;
    tokType=ttokType;
    }
    else
    {
     getToken(); //取得表达式的下一部分
     result=evalExp2();
     vars[varIdx]=result;
     return result;
    }
   }
   return evalExp2();
  }

  //两个项的加减
  private double evalExp2()
  {
   char op;
   double result;
   double partialResult;
   result=evalExp3();

   while((op=token[0])=='+'||op=='-')
   {
    getToken();
    partialResult=evalExp3();
    switch(op)
    {
      case '-':
       result=result-partialResult;
       break;
      case '+':
       result= result+partialResult;
       break;

    }
   }
   return result;
  }

  //两个项的乘或除
  private double evalExp3()
  {
   char op;
   double result;
   double partialResult;

   result=evalExp4();

   while((op=token[0])=='*'||op=='/'||op=='%')
   {
    getToken();
    partialResult=evalExp4();
    switch(op)
    {
      case '*':
      result=result * partialResult;
      break;
      case '/':
      if (partialResult==0.0)
        handleErr(DIVBYZERO);
      result=result / partialResult;
      break;
      case '%':
      if(partialResult==0.0)
        handleErr(DIVBYZERO);
      result= result % partialResult;
      break;
    }
   }
   return result;
        }

  //指数运算
  private double evalExp4()
  {
   double result;
   double partialResult;
   double ex;
   

   result=evalExp5();

   if(token.Equals('^'))
   {
     getToken();
     partialResult=evalExp4();
     ex=result;
     if(partialResult==0.0)    //指数为零
     {
      result=1.0;
     }
     else
    for(int t=(int)partialResult-1;t>0;t--)
      result=result*ex;
   }
   return result;
  }

  //计算一元的加减运算
  private double evalExp5()
  {
   double result;
   string op;
   op="";
   if((tokType==tokenEnum.DELIMITER)&& token.Equals('+')||token.Equals('-'))
   {
    op=token;
    getToken();
   }
   result=evalExp6();

   if(op.Equals('-'))
     result=-result;
   return result;
  }

  //处理加括号的表达式
  private double evalExp6()
  {
   double result;

   if(token.Equals('('))
   {
     getToken();
     result=evalExp2();
     if(!token.Equals(')'))
     handleErr(UNBALPARENS);
     getToken();
   }
   else
    result=atom();
   return result;
  }

  //读取数字
  private double atom()
  {
   double result=0.0;
 
   switch(tokType)
   {
    case tokenEnum.NUMBER:
            try{
    result=Double.Parse(token);
   }
   catch(FormatException exc)
   {
     handleErr(SYNTAX);
   }
            getToken();
   break;
    case tokenEnum.VARIABLE:
   result=findVar(token);
   getToken();
   break;
    default:
   handleErr(SYNTAX);
    break;
   }
   return result;
  }

  //处理错误
  private void handleErr(int error)
  {
   string[] err={
     "语法错误",
     "括号缺失(不对称)",
     "没有表达式",
     "被除数为零"
   };
   throw new ParserException(err[error]);
  }

  //返回变量的值
  private double findVar(string vname)
  {
   if ((vname[0]>='a')&&(vname[0]<='Z'))
   {
    handleErr(SYNTAX);
    return 0.0;
   }
   return vars[char.ToUpper(vname[0])-'A'];
  }

  //返回令牌到输入字符串流中
  private void putBack()
  {
   if (token==EOE)return;
   for (int i = 0; i < token.Length; i++)
    expIdx--;
  }

  public Parser()
  {
  }
 }
}

原创粉丝点击