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

做了递归下降方式的运算解析器(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()
  {
  }
 }
}

递归下降分析法 一、实验目的: 根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。 二、实验说明 1、递归下降分析法的功能 词法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。 2、递归下降分析法的前提 改造文法:消除二义性、消除左递归、提取左因子,判断是否为LL(1)文法, 3、递归下降分析法实验设计思想及算法 为G的每个非终结符号U构造一个递归过程,不妨命名为U。 U的产生式的右边指出这个过程的代码结构: (1)若是终结符号,则和向前看符号对照, 若匹配则向前进一个符号;否则出错。 (2)若是非终结符号,则调用与此非终结符对应的过程。当A的右部有多个产生式时,可用选择结构实现。 三、实验要求 (一)准备: 1.阅读课本有关章节, 2.考虑好设计方案; 3.设计出模块结构、测试数据,初步编制好程序。 (二)上课上机: 将源代码拷贝到机上调试,发现错误,再修改完善。第二次上机调试通过。 (三)程序要求: 程序输入/输出示例: 对下列文法,用递归下降分析法对任意输入的符号串进行分析: (1)E->eBaA (2)A->a|bAcB (3)B->dEd|aC (4)C->e|dc 输出的格式如下: (1)递归下降分析程序,编制人:姓名,学号,班级 (2)输入一以#结束的符号串:在此位置输入符号串例如:eadeaa# (3)输出结果:eadeaa#为合法符号串 注意: 1.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 2.对学有余力的同学,可以详细的输出推导的过程,即详细列出每一步使用的产生式。 (四)程序思路 0.定义部分:定义常量、变量、数据结构。 1.初始化:从文件将输入符号串输入到字符缓冲区中。 2.利用递归下降分析法分析,对每个非终结符编写函数,在主函数中调用文法开始符号的函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值