1.1:左结合文法:
exp -> exp addop term | term
addop -> + | -
term -> term mulop factor | factor
mulop -> * | /
factor -> (exp) | number
1.2左结合代码实现
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
char token; /* global token variable */
/*function prototype for recursive calls*/
float exp(void);
float term(void);
float factor(void);
int i = 0;
string Equation;
char getc(){
return Equation[i++];
}
int getnum(){
if(isdigit(Equation[i]) && isdigit(Equation[i+1])){
i+=2;
return (Equation[i-3]-'0')*100+(Equation[i-2]-'0')*10+Equation[i-1]-'0';
}
if(isdigit(Equation[i])){
i++;
return (Equation[i-2]-'0')*10+Equation[i-1]-'0';
}
return Equation[i-1]-'0';
}
void error(void)
{
fprintf(stderr, "error\n");
exit(1);
}
void Div0error(void)
{
fprintf(stderr, "Divide by Zero Error\n");
exit(1);
}
void match(char expectedToken)
{
if (token==expectedToken) token=getc();
else error();
}
int main()
{
float result;
/*load token with first character for lookahead*/
Equation="1-2+3";//这里是要计算的算式
token=getc();
result=exp();
if (token=='\0') /*check for end of line*/
printf("left-associative Result = %.2f\n", result);
else error(); /*extraneous chars on line*/
return 0;
}
float exp(void)
{
float temp=term();
while ( (token=='+') || (token=='-') )
switch (token)
{
case '+': match ('+'); temp+=term(); break;
case '-': match ('-'); temp-=term(); break;
}
return temp;
}
float term(void)
{
float temp=factor();
while (token=='*' || token == '/')
switch(token)
{
case '*': match('*');temp*=factor();break;
case '/':
match('/');
float divisor = factor();
if(divisor == 0)
Div0error();
else
temp/=divisor;
break;
}
return temp;
}
float factor(void)
{
float temp;
if (token=='(')
{
match ('(');
temp = exp();
match(')');
}
else
if (isdigit(token))
{
temp = getnum();
token = getc();
}
else error();
return temp;
}
2.1右结合文法
exp -> term [addop exp]
addop -> + | -
term -> factor [mulop term]
mulop -> * | /
factor -> (exp) | number
2.2右结合代码实现
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
char token; /* global token variable */
/*function prototype for recursive calls*/
float exp(void);
float term(void);
float factor(void);
int i = 0;
string Equation;
char getc(){
return Equation[i++];
}
int getnum(){
if(isdigit(Equation[i]) && isdigit(Equation[i+1])){
i+=2;
return (Equation[i-3]-'0')*100+(Equation[i-2]-'0')*10+Equation[i-1]-'0';
}
if(isdigit(Equation[i])){
i++;
return (Equation[i-2]-'0')*10+Equation[i-1]-'0';
}
return Equation[i-1]-'0';
}
void error(void)
{
fprintf(stderr, "error\n");
exit(1);
}
void Div0error(void)
{
fprintf(stderr, "Divide by Zero Error\n");
exit(1);
}
void match(char expectedToken)
{
if (token==expectedToken) token=getc();
else error();
}
int main()
{
float result;
/*load token with first character for lookahead*/
Equation="1-2+3";//这里是要计算的算式
token=getc();
result=exp();
if (token=='\0') /*check for end of line*/
printf("right-associative Result = %.2f\n", result);
else error(); /*extraneous chars on line*/
return 0;
}
float exp(void)
{
float temp=term();
while ( (token=='+') || (token=='-') )
switch (token)
{
case '+': match ('+'); temp+=exp(); break;
case '-': match ('-'); temp-=exp(); break;
}
return temp;
}
float term(void)
{
float temp=factor();
while (token=='*' || token == '/')
switch(token)
{
case '*': match('*');temp*=term();break;
case '/':
match('/');
float divisor = term();
if(divisor != 0)
temp/=divisor;
else Div0error();
break;
}
return temp;
}
float factor(void)
{
float temp;
if (token=='(')
{
match ('(');
temp = exp();
match(')');
}
else
if (isdigit(token))
{
temp = getnum();
token = getc();
}
else error();
return temp;
}
3.1堆栈的左右结合实现
中缀表达->后缀表达式
左右结合分别的关键在于同级运算的执行先后顺序,在堆栈实现中即是要修改栈顶比较时的判断
3.1.1堆栈左结合
#include <iostream>
#include <stack>
using namespace std;
string Equation="1-2+3";//要计算的算式
string retL[100];
int posL =0;
char getc(){
return Equation[posL++];
}
int getnum(){
if(isdigit(Equation[posL]) && isdigit(Equation[posL+1])){
posL+=2;
return (Equation[posL-3]-'0')*100+(Equation[posL-2]-'0')*10+Equation[posL-1]-'0';
}
if(isdigit(Equation[posL])){
posL++;
return (Equation[posL-2]-'0')*10+Equation[posL-1]-'0';
}
return Equation[posL-1]-'0';
}
int getPriority(char c){
if(c == '(') return 1;
else if(c == '+' || c == '-') return 2;
else if(c == '*' || c == '/') return 3;
else if(c == ')') return 4;
else {
cout << "error input in getPriority()" << endl;
return -1;
}
}
void TonibolanL(int &l){
char c ;
int pos = l;
stack<char> operate;
c = getc();
while(1){
if(c >= '0' && c <= '9'){
retL[pos++] = to_string(getnum());
}
else{
if(c == '('){
operate.push(c);
}else if(c == ')'){
while(operate.top() != '('){
retL[pos++] = operate.top();
operate.pop();
}
if(operate.top() == '('){
operate.pop();
}
}
else if(c == '+' || c == '-' || c == '*' || c == '/'){
if(operate.empty() || getPriority(c) > getPriority(operate.top())){
operate.push(c);
}
else {
while(getPriority(c) <= getPriority(operate.top())){
retL[pos++] = operate.top();
operate.pop();
if(operate.empty()) break;
}
operate.push(c);
}
}else if(c == '\0' || c == '\n' || c == '='){
break;
}else{
cout << "Error Input:" << c << endl;
break;
}
}
c = getc();
}
while (!operate.empty())
{
retL[pos++] = operate.top();
operate.pop();
}
l = pos;
}
float Calcval(string* ret,int l)
{
stack<string> st;
//遍历后缀表达式
int i = 0;
while (i<l)
{
if(ret[i] == "+")
{
//遇到操作符,连续出栈两个元素,进行运算,在将结果入栈
float a = stof(st.top());
st.pop();
float b = stof(st.top());
st.pop();
float c = b+a;
st.push(to_string(c));
}else if(ret[i] == "-"){
float a = stof(st.top());
st.pop();
float b = stof(st.top());
st.pop();
float c = b-a;
st.push(to_string(c));
}else if(ret[i] == "*"){
float a = stof(st.top());
st.pop();
float b = stof(st.top());
st.pop();
float c = b*a;
st.push(to_string(c));
}else if(ret[i] == "/"){
float a = stof(st.top());
st.pop();
float b = stof(st.top());
st.pop();
if(a!=0){
float c = b/a;
st.push(to_string(c));
}else{
cout << "Divide by Zero Error" << endl;
break;
}
}
else if(stof(ret[i])<=100 && stof(ret[i]) >= 0) //若果是数字直接入栈
{
st.push(ret[i]);
}else{
cout << "error token:" << ret[i] << endl;
break;
}
i++;
}
return stof(st.top()); //栈里面的数据就是最后的结果
}
int main(){
int l = 0;
TonibolanL(l);
// for(int i = 0;i < l;i++){
// cout << ret[i] << " ";
// }
// cout << endl;
cout << Calcval(retL,l) << endl;
return 0;
}
3.1.2堆栈右结合
#include <iostream>
#include <stack>
using namespace std;
string Equation="1-2+3";//这里是要计算的算式
string retR[100];
int posR =0;
char getc(){
return Equation[posR++];
}
int getnum(){
if(isdigit(Equation[posR]) && isdigit(Equation[posR+1])){
posR+=2;
return (Equation[posR-3]-'0')*100+(Equation[posR-2]-'0')*10+Equation[posR-1]-'0';
}
if(isdigit(Equation[posR])){
posR++;
return (Equation[posR-2]-'0')*10+Equation[posR-1]-'0';
}
return Equation[posR-1]-'0';
}
int getPriority(char c){
if(c == '(') return 1;
else if(c == '+' || c == '-') return 2;
else if(c == '*' || c == '/') return 3;
else if(c == ')') return 4;
else {
cout << "error input in getPriority()" << endl;
return -1;
}
}
void TonibolanR(int &r){
char c ;
int pos = r;
stack<char> operate;
c = getc();
while(1){
if(c >= '0' && c <= '9'){
retR[pos++] = to_string(getnum());
}
else{
if(c == '('){
operate.push(c);
}else if(c == ')'){
while(operate.top() != '('){
retR[pos++] = operate.top();
operate.pop();
}
if(operate.top() == '('){
operate.pop();
}
}
else if(c == '+' || c == '-' || c == '*' || c == '/'){
//右结合只需要把这里的优先级比较改掉即可
if(operate.empty() || getPriority(c) >= getPriority(operate.top())){
operate.push(c);
}
else {
while(getPriority(c) < getPriority(operate.top())){
retR[pos++] = operate.top();
operate.pop();
if(operate.empty()) break;
}
operate.push(c);
}
}else if(c == '\0' || c == '\n' || c == '='){
break;
}else{
cout << "Error Input:" << c << endl;
break;
}
}
c = getc();
}
while (!operate.empty())
{
retR[pos++] = operate.top();
operate.pop();
}
r = pos;
}
float Calcval(string* ret,int l)
{
stack<string> st;
//遍历后缀表达式
int i = 0;
while (i<l)
{
if(ret[i] == "+")
{
//遇到操作符,连续出栈两个元素,进行运算,在将结果入栈
float a = stof(st.top());
st.pop();
float b = stof(st.top());
st.pop();
float c = b+a;
st.push(to_string(c));
}else if(ret[i] == "-"){
float a = stof(st.top());
st.pop();
float b = stof(st.top());
st.pop();
float c = b-a;
st.push(to_string(c));
}else if(ret[i] == "*"){
float a = stof(st.top());
st.pop();
float b = stof(st.top());
st.pop();
float c = b*a;
st.push(to_string(c));
}else if(ret[i] == "/"){
float a = stof(st.top());
st.pop();
float b = stof(st.top());
st.pop();
if(a!=0){
st.push(to_string(b/a));
}else{
cout << "Divide by Zero Error" << endl;
break;
}
}
else if(stof(ret[i])<=100 && stof(ret[i]) >= 0) //若果是数字直接入栈
{
st.push(ret[i]);
}else{
cout << "error token:" << ret[i] << endl;
break;
}
i++;
}
return stof(st.top()); //栈里面的数据就是最后的结果
}
int main(){
int r = 0;
TonibolanR(r);
for(int i = 0;i < r;i++){
cout << retR[i] << " ";
}
cout << endl;
cout << Calcval(retR,r) << endl;
return 0;
}
4.1随机算式的生成
这里目标是生成绝对准确的算式
1、生成[3,5]个运算分量,范围在[0,100]
2、生成[2,4]个运算符,[+,-,*,/]随机
3、50%概率生成括号
4、先生成左括号(只能在运算分量之前)
5、在根据左括号位置确定右括号(只能在数字之后,且左右括号之间至少有两个运算分量和一个运算符)
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
using namespace std;
string op[4] = {"+","-","*","/"};
//获取运算分量
string getRandomNum(){
return to_string(rand() % 101); //0、1、2、3......99、100
}
//获取运算符
int getRandomOp(){
return rand() % 4; //0、1、2、3
}
//获取等式中运算分量个数
int getRandomEquationLength(){
return rand() % 3 + 3;//运算分量数可能为3、4、5 ,运算符数量则可能是2、3、4
}
//是否出现括号
int ifBracket(){
return rand() % 2;//0、1
}
//左括号出现的位置
int LeftBracket_pos(int length){
switch(length){
case 3: return rand()%2;break;
case 4: return rand()%3;break;
case 5: return rand()%4;break;
default: return -1;break;
}
}
//右括号出现的位置
int RightBracket_pos(int length,int l_pos){
switch(length){
case 3:
switch(l_pos){
case 0: return rand()%2 + 1;break;
case 1: return 2;break;
}
break;
case 4:
switch(l_pos){
case 0: return rand()%3 + 1;break;
case 1: return rand()%2 + 2;break;
case 2: return 3;break;
}
break;
case 5:
switch(l_pos){
case 0: return rand()%4 + 1;break;
case 1: return rand()%3 + 2;break;
case 2: return rand()%2 + 3;break;
case 3: return 4;break;
}
break;
default: return -1;break;
}
return -1;
}
string getRandomEquation(){
string equation = "";
int length = getRandomEquationLength();
if(ifBracket()){
int l_pos = LeftBracket_pos(length);
int r_pos = RightBracket_pos(length,l_pos);
for(int i = 0;i < length;i++){
//(
if(i == l_pos) equation += "(";
equation += getRandomNum();
//)
if(i == r_pos) equation += ")";
if(i != length - 1) equation += op[getRandomOp()];
}
}else{
for(int i = 0;i < length;i++){
equation += getRandomNum();
if(i != length - 1) equation += op[getRandomOp()];
}
}
return equation;
}
int main(){
srand((unsigned int)time(NULL));
for(int i=0;i<100;i++){
cout << getRandomEquation() <<endl;
}
return 0;
}
5.1引用参考博客
堆栈实现计算器(9条消息) 数据结构--简单实现计算器_数据结构 简单计算器_哈哈哈哈哈哈丶的博客-CSDN博客
随机数的生成