编译原理实现计算器

匿名 (未验证) 提交于 2019-12-03 00:26:01

要求

计算器接受四则运算表达式为输入(如下所示)。如果表达式语法正确,则输出计算结果,否则报错,指出错误位置及原因。

“;”结束;

加减乘除;支持括号;

数字和字母

print()函数,输出并换行;

print()函数不仅可以输出变量,还可以直接输出表达式的值,例如print(1+2)

C/C++、Java,,第三方库。

,corner cases。例如除零;

思路说明

一、中缀表达式求值

1MyStack.h

#pragma once #include <iostream> #define MAX 100  using namespace std;  template <class T>  class MyStack  {      public:              T data[MAX];              int top;               public:              void init();        // 初始化栈              bool empty();       // 判断栈是否为空              T getTop();         // 读取栈顶元素(不出栈)              void push(T x);     // 进栈              T pop();            // 出栈   };   template<class T>   void MyStack<T>::init()  {          this->top = 0;  }   template<class T>   bool MyStack<T>::empty()  {          return this->top == 0 ? true : false;  }   template<class T>  T MyStack<T>::getTop()  {      if (empty())          {              cout << "栈为空!\n";              exit(1);          }      return this->data[this->top - 1];   }   template<class T>   void MyStack<T>::push(T x)  {      if (this->top == MAX)          {               cout << "栈已满!\n";               exit(1);           }       this->data[this->top] = x;       this->top++;  }   template<class T>   T MyStack<T>::pop()  {       if (this->empty())          {              cout << "栈为空! \n";              exit(1);          }            T e = this->data[this->top - 1];       this->top--;      return e;  }

2InfixToPostfix.h

boolcharop// 判断是否为运算符

intcharop// 求运算符优先级

doublestringpre, map<string, int> mymap, inti// 把中缀表达式转换为后缀表达式

doublecharstr[], inti, map<string, int> mymap); // 将数字字符串转变成相应的数字,标识符转换为数字

doublecharpost[], map<string, int> mymap//对后缀表达式求值

postfix(stringpre, map<string, int> mymap, intipremymapi0

postfixpostfix_value(charpost[], map<string, int> mymap)来对后缀表达式求值。求值过程中,如果是操作数就调用read_number(charstr[], inti, map<string, int> mymap)map

#pragma once #include "MyStack.h" #include <map>  #include <string>  using namespace std; bool isoperator(char op);                                       // 判断是否为运算符 int priority(char op);                                          // 求运算符优先级 double postfix(string pre, map<string, int> mymap, int *i);     // 把中缀表达式转换为后缀表达式 double read_number(char str[], int *i, map<string, int> mymap); // 将数字字符串转变成相应的数字,标识符转换为数字 double postfix_value(char post[], map<string, int> mymap);      //对后缀表达式求值  map<string, int> Identities;//存放标识符的声明和定义 map<string, int>::iterator iter; //判断是否为操作符 bool isoperator(char op) {     switch (op)     {     case '+':     case '-':     case '*':     case '/':         return 1;     default:         return 0;     } }  //设置运算符优先级 int priority(char op) {     switch (op)     {     case '#':         return -1;     case '(':         return 0;     case '+':     case '-':         return 1;     case '*':     case '/':         return 2;     default:         return -1;     } }  //把中缀表达式转换为后缀表达式,返回后缀表达式的长度(包括空格) double postfix(string pre, map<string, int> mymap,int *i) {     char post[MAX];      //后缀表达式数组     int j = 0;     MyStack<char> stack;     stack.init();        // 初始化存储操作符的栈     stack.push('#');     // 首先把结束标志‘;’放入栈底      while (pre[*i] != ';')     {         if ((pre[*i] >= '0' && pre[*i] <= '9') || pre[*i] == '.' || (pre[*i] >= 'a'&&pre[*i] <= 'z') || (pre[*i] >= 'A'&&pre[*i] <= 'Z')) // 遇到数字、字母和小数点直接写入后缀表达式         {             post[j++] = pre[*i];         }         else if (pre[*i] == '(')        // 遇到“(”不用比较直接入栈             stack.push(pre[*i]);         else if (pre[*i] == ')')        // 遇到右括号将其对应左括号后的操作符(操作符栈中的)全部写入后缀表达式         {             while (stack.getTop() != '(')             {                 post[j++] = stack.pop();             }             stack.pop();                // 将“(”出栈,后缀表达式中不含小括号         }         else if (isoperator(pre[*i]))         {             post[j++] = ' ';            // 用空格分开操作数                                           while (priority(pre[*i]) <= priority(stack.getTop()))             {                 // 当前的操作符小于等于栈顶操作符的优先级时,将栈顶操作符写入到后缀表达式,重复此过程                 post[j++] = stack.pop();             }             stack.push(pre[*i]);        // 当前操作符优先级大于栈顶操作符的优先级,将该操作符入栈         }          (*i)++;     }     while (stack.top) // 将所有的操作符加入后缀表达式     {         post[j++] = stack.pop();     }     double result= postfix_value(post, mymap);     return result; }  // 将数字字符串转变成相应的数字,标识符转换为数字 double read_number(char str[], int *i, map<string, int> mymap) {     double x = 0.0;     int k = 0;     bool f = false;     while (str[*i] >= '0' && str[*i] <= '9')  // 处理整数部分     {         x = x * 10 + (str[*i] - '0');         (*i)++;     }      if (str[*i] == '.') // 处理小数部分     {         (*i)++;         while (str[*i] >= '0'&&str[*i] <= '9')         {             x = x * 10 + (str[*i] - '0');             (*i)++;             k++;         }     }     while (k != 0)     {         x /= 10.0;         k--;     }     while ((str[*i] >= 'a'&&str[*i] <= 'z') || (str[*i] >= 'A'&&str[*i] <= 'Z'))//处理标识符     {         int len = *i;         string token = "";         do {             token = token + str[*i];             (*i)++;         } while ((str[*i] >= 'a'&&str[*i] <= 'z') || (str[*i] >= 'A'&&str[*i] <= 'Z')||( str[*i] >= '0' && str[*i] <= '9'));         x = mymap[token];     }     return x; }  //对后缀表达式求值 double postfix_value(char post[], map<string, int> mymap) {     MyStack<double> stack;    // 操作数栈     stack.init();     int i = 0;     double x1, x2;      while (post[i] != '#')     {         if (post[i] >= '0' && post[i] <= '9' || (post[i] >= 'a'&&post[i] <= 'z') || (post[i] >= 'A'&&post[i] <= 'Z'))             stack.push(read_number(post, &i, mymap));         else if (post[i] == ' ')             i++;         else if (post[i] == '+')         {             x2 = stack.pop();             x1 = stack.pop();             stack.push(x1 + x2);             i++;         }         else if (post[i] == '-')         {             x2 = stack.pop();             x1 = stack.pop();             stack.push(x1 - x2);             i++;         }         else if (post[i] == '*')         {             x2 = stack.pop();             x1 = stack.pop();             stack.push(x1*x2);             i++;         }         else if (post[i] == '/')         {             x2 = stack.pop();             x1 = stack.pop();             stack.push(x1 / x2);             i++;         }     }     double result = stack.getTop();     return result; }

二、对字符串的解析

Scanner.h

mappostfix(stringpre, map<string, int> mymap, inti)求值,将值存入map中。对于print语句,将其里面的式子调用postfix(stringpre, map<string, int> mymap, inti)求值并输出。

#pragma once #include "InfixToPostfix.h"  using namespace std;  void scaner(string prog)//传入要解析的字符串 {     int p = 0;     char ch = prog[p];     string token;     while (ch != 0)     {         if ((ch >= 'a'&&ch <= 'z') || (ch >= 'A'&&ch <= 'Z'))  //拼凑出标识符         {             token = "";             do {                 token = token + ch;                 p++;                 ch = prog[p];             } while ((ch >= '0'&&ch <= '9') || (ch >= 'a'&&ch <= 'z') || (ch >= 'A'&&ch <= 'Z'));          }         else if (ch == '=') {             p++;             double value = postfix(prog, Identities, &p);             Identities.insert(pair<string, int>(token, value));//将求出的标识符的值和标识符存入Identities             p++;             ch = prog[p];         }         else {             if (strcmp(token.c_str(), "print")==0) {                 p++;                 //将最后的闭合括号换为;                 int endN = prog.find_last_of(")");                 prog[endN] = ';';                 double value = postfix(prog, Identities, &p);                 cout << value << endl;                 token = "";                 ch = 0;             }         }     } }

三、对文件的读取

“Analyse.h”文件,里面有stringfPath)函数,对其传入读取文件的路径,完成对文件内容的按行读取。读取每一行,则对每一行进行错误检查。对无错误的语句调用scaner(stringprog)进行处。

#pragma once #include "Scanner.h" #include <fstream> void analyse(string fPath) {     string path = fPath;     ifstream in(path, ios::in);     string line = "";     int errl = 0, errPsn = 0;//错误所在的行和位置     //按行读取文件     while (!in.eof()) {         getline(in, line);         errl++;         if (line != "") {//判断结尾是否是";"             if (line[line.length() - 1] != ';') {                 errPsn = line.length();                 cout << "Error(line " << errl << ",position " << errPsn << "): 应输入';'" << endl;                 system("pause");             }//end if             if (line.find("/0") != -1) {//判断除数是否为零                 errPsn = line.find("/0") + 1;                 cout << "Error(line " << errl << ",position " << errPsn << "): Divisor cannot be zero!" << endl;                 system("pause");             }//end if             string token;             int n = line.find('=');//判断标识符是否声明             if (n != -1) {                 for (int i = n + 1; i < line.length(); i++) {                     char c = line[i];                     token = "";                     while ((c >= 'a'&&c <= 'z') || (c >= 'A'&&c <= 'Z')) {                         token += c;                         i++;                         c = line[i];                     }//end while                     if (token != ""&&Identities.find(token) == Identities.end()) {                         errPsn = i - token.length();                         cout << "Error(line " << errl << ",position " << errPsn << "):  undefined identifier" << endl;                         system("pause");                     }//end if                 }//end for             }//end if         }//end if         scaner(line);     }//end while     in.close(); }

main函数

#include "Analyse.h" int main(int argc,char **argv) {     if (argc==0) {         cout << "启动错误!" << endl;         system("pause");     }     else {         analyse(argv[1]);     }     analyse("error1.in");     system("pause");     return 0; }

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!