编译原理 计算器 java,编译原理实现计算器

要求

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

“;”结束;

加减乘除;支持括号;

数字和字母

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

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

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

,corner cases。例如除零;

思路说明

一、中缀表达式求值

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

2InfixToPostfix.h

boolcharop// 判断是否为运算符

intcharop// 求运算符优先级

doublestringpre,mapmymap,inti// 把中缀表达式转换为后缀表达式

doublecharstr[],inti,mapmymap);// 将数字字符串转变成相应的数字,标识符转换为数字

doublecharpost[],mapmymap//对后缀表达式求值

postfix(stringpre,mapmymap,intipremymapi0

postfixpostfix_value(charpost[],mapmymap)来对后缀表达式求值。求值过程中,如果是操作数就调用read_number(charstr[],inti,mapmymap)map#pragma once #include "MyStack.h" #include #include using namespace std; bool isoperator(char op); // 判断是否为运算符 int priority(char op); // 求运算符优先级 double postfix(string pre, map mymap, int *i); // 把中缀表达式转换为后缀表达式 double read_number(char str[], int *i, map mymap); // 将数字字符串转变成相应的数字,标识符转换为数字 double postfix_value(char post[], map mymap); //对后缀表达式求值 map Identities;//存放标识符的声明和定义 map::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 mymap,int *i) { char post[MAX]; //后缀表达式数组 int j = 0; MyStack 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 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 mymap) { MyStack 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,mapmymap,inti)求值,将值存入map中。对于print语句,将其里面的式子调用postfix(stringpre,mapmymap,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(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 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; }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值