先使用词法分析得到二元组,用语法分析二元组看表达式语法是否正确,如果正确,计算表达式的值,如果错误,输出语法错误信息。
测试程序:
// pL/0语言词法分析器
#include<bits/stdc++.h>
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include<stack>
#include<string.h>
using namespace std;
bool IsOperator(char ch);
char Precede(char opr1, char opr2);
double Operate(double opnd1, char op, double opnd2);
int ConvertToIndex(char opr);
ifstream infile("c.txt");//词法分析的结果或语法分析的输入
string str;//string变量进行字符识别
string sym; //指针
string sym1;
int temp=0;
void expressionAnalysis();//表达式分析
void termAnaysis();//项分析
void factorAnalysis();//因子分析
int advance();
int conterr=0;//记录错误
int lpnum=0;//记录左括号
int found;//提取字符串中指针的位置
int flag=0;//记录往后移动一个指针SYM是否正确
string s;//用来保存要分析的字符串
struct _2tup
{
string token;
int id;
};
int advance() //SYM的移动
{
if(!getline(infile,str)) //从文件中提取字符
{
return 0;
}
found=str.find(',',0);
if(found==-1) //当为error的时候,没有‘,’
{
conterr++;
cout<<"语法错误 识别字符错误"<<endl;
return -1;
}
if(temp==1)
sym1=sym;
sym=str.substr(1,found-1);
// cout<<str.substr(found+1,4)<<endl;
if(temp==0)
{
sym1=sym;
temp=1;
}
// cout<<sym<<" "<<sym1<<endl;
if(sym=="23" && sym1=="24")
{
conterr++;
cout<<"')'和'('中间缺少运算符\n";
return -1;
}
if(sym=="24" && sym1=="23")
{
conterr++;
cout<<"'('和')'中间缺少项\n";
return -1;
}
if(sym=="24"&&(sym1!="28"&&sym1!="29"))
{
conterr++;
cout<<"')'前面缺少项\n";
return -1;
}
if(sym1=="24"&&(sym=="28"||sym=="29"))
{
conterr++;
cout<<"')'后缺少运算符\n";
return -1;
}
if(sym1=="23"&&(sym=="12"||sym=="13"||sym=="14"||sym=="15"))
{
conterr++;
cout<<"'('后缺少项\n";
return -1;
}
// cout<<sym<<endl;
return 1;
}
void factorAnalysis()
{
// cout<<"factor\n"<<sym<<endl;
// cout<<sym<<endl;
if(sym=="28"||sym=="29") //如果是标识符和无符号整数,指针就往后移动
{
flag=advance();
if(conterr)
{
return;
}
if(sym=="23")
{
conterr++;
cout<<"'('前缺少运算符\n";
return;
}
if(lpnum==0&&sym=="24")
{
conterr++;
cout<<"语法错误 ')'不匹配"<<endl;
return;
}
}
else if(sym=="23") //如果是左括号,就要接下来判断是否为表达式,指针往后移动
{
// cout<<"hello"<<sym1<<endl;
if(sym1=="28"||sym1=="29")
{
cout<<"(前面缺少运算符"<<endl;
conterr++;
return ;
}
lpnum++;
// cout<<lpnum<<endl;
flag=advance();
if(conterr)
{
return;
}
if(flag==0) //当为最后一个标志的时候,若没有右括号匹配就错误
{
conterr++;
cout<<"语法错误 '('后缺少表达式"<<endl;
return;
}
// cout<<sym<<endl;
expressionAnalysis();
if(conterr)
{
return;
}
if(flag==0||sym!="24")
{
conterr++;
cout<<"语法错误 表达式后面缺少')'"<<endl;
return;
}
else
{
lpnum--;
flag=advance();
if(conterr)
{
return;
}
if(flag==0)
{
return;
}
}
}
else
{
cout<<"语法错误 因子首部不为<标识符>|<无符号整数>|'('"<<endl;
conterr++;
return;
}
return;
}
void termAnalysis()
{
// cout<<"term\n"<<sym<<endl;
factorAnalysis();
if(conterr)
{
return;
}
while((sym=="14")||(sym=="15")) //当为'*'或'/'的时候,一直往后识别因子并循环
{
flag=advance();
if(conterr)
{
return;
}
if(flag==0)
{
conterr++;
cout<<"语法错误 <乘法运算符>后缺因子"<<endl;
return;
}
if(conterr)
{
return;
}
factorAnalysis();
if(conterr)
{
return;
}
}
return;
}
void expressionAnalysis()
{
// cout<<"expression!\n"<<sym<<endl;
if(conterr)
{
return;
}
if((sym=="14")||(sym=="15")) //当为'*'或'/'的时候
{
flag=advance();
if(!conterr)
{
return;
}
if(flag==0)
{
cout<<"语法错误 <加法运算符>后缺项"<<endl;
conterr++;
return;
}
}
termAnalysis();
if((sym=="14")||(sym=="15")) //当为'*'或'/'的时候
{
flag=advance();
if(!conterr)
{
return;
}
if(flag==0)
{
cout<<"语法错误 <加法运算符>后缺项"<<endl;
conterr++;
return;
}
}
if(conterr)
{
return;
}
while((sym=="12")||(sym=="13")) //当为'+'或'-'的时候,一直往后识别项并循环
{
// cout<<str.substr(found+1,4)<<endl;
flag=advance();
if(conterr)
{
return;
}
if(flag==0)
{
cout<<"语法错误 <加法运算符>后缺项"<<endl;
conterr++;
return;
}
termAnalysis();
if(conterr)
{
return;
}
}
return;
}
bool is_blank(char ch)
{
return ch == ' ' || ch == ' ';//空格或控制字符
}
bool gofor(char& ch, string::size_type& pos, const string& prog)//返回指定位置的字符
{
++pos;
if (pos >= prog.size())
{
return false;
}
else
{
ch = prog[pos];
return true;
}
}
_2tup scanner(const string& prog, string::size_type& pos, const map<string, int>& keys, int& row)
{
/*
if
标示符
else if
数字
else
符号
*/
_2tup ret;
string token;
int id = 0;
char ch;
ch = prog[pos];
while(is_blank(ch))
{
++pos;
ch = prog[pos];
}
// 判断标示符、关键字
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')
{
map<string, int>::const_iterator cit;
//保证读取一个单词
while((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')
{
token += ch;//追加标示符、关键字
if (!gofor(ch, pos, prog))
{
break;
}
if(token=="odd")
{
id=cit->second;
goto end;
}
}
// 这里先看做都是其他标示符
id = keys.size();
// 验证是否是关键字
cit = keys.find(token);//根据string类型的token返回int类型的id赋值给cit
if (cit != keys.end())
{
id = cit->second;//此时是关键字,记录他的id
// if(id<=10)
// cout<<cit->first<<"is true!"<<cit->second<<endl;
}
}
// 识别常数
else if ((ch >= '0' && ch <= '9'))
{
while (ch >= '0' && ch <= '9' )
{
token += ch;
if (!gofor(ch, pos, prog))
{
break;
}
}
id = keys.size() - 1;
int dot_num = 0;
for (string::size_type i = 0; i != token.size(); ++i)
{
if (token[i] == '.')
{
++dot_num;
}
}
if (dot_num > 1)
{
id = -1;
}
}
else
{
map<string, int>::const_iterator cit;
switch (ch)
{
case '-': // - 操作符
token += ch;
gofor(ch,pos,prog);
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
break;
case ':':
token += ch;
if (gofor(ch, pos, prog))
{
if (ch == '=') // -- 操作符
{
token += ch;
gofor(ch, pos, prog); //不让:= 中的=重复使用
}
}
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
break;
case '=':
token += ch;
gofor(ch,pos,prog);
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
break;
case '/': // / 操作符
token += ch;
gofor(ch,pos,prog);
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
break;
case '+':
token += ch;
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
gofor(ch, pos, prog);
break;
case '<':
token += ch;
if (gofor(ch, pos, prog))
{
if (ch == '>')
{
token += ch;
gofor(ch,pos,prog);
}
else if (ch == '=')
{
token += ch;
gofor(ch, pos, prog);
}
}
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
break;
case '>':
token += ch;
if (gofor(ch, pos, prog))
{
if (ch == '=')
{
token += ch;
gofor(ch, pos, prog);
}
}
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
break;
case '(': // / 操作符
token += ch;
gofor(ch,pos,prog);
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
break;
case ')': // / 操作符
token += ch;
gofor(ch,pos,prog);
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
break;
case '*':
token += ch;
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
gofor(ch, pos, prog);
break;
case ',':
case '.':
case ';':
token += ch;
gofor(ch, pos, prog);
//++pos;
//ch = prog[pos];
cit = keys.find(token);
if (cit != keys.end())
{
id = cit->second;
}
break;
case '\n':
token += "换行";
++pos;
ch = prog[pos];
id = -2;
break;
default:
token += "错误";
++pos;
ch = prog[pos];
id = -1;
break;
}
}
end:
ret.token = token;
ret.id = id;
return ret;
}
void init_keys(const string& file, map<string, int>& keys)//读取单词符号和种别码
{
ifstream fin(file.c_str());//.c_str返回的是当前字符串的首地址
if (!fin)
{
cerr << file << " doesn't exist!" << endl;//cerr不经过缓冲而直接输出,一般用于迅速输出出错信息
// exit(1);
}
keys.clear();//清空map对象里面的内容
string line;
string key;
int id;
while (getline(fin, line))//这个函数接收两个参数:一个输入流对象和一个string对象,getline函数从输入流的下一行读取,并保存读取的内容到string中
{
istringstream sin(line);//istringstream sin(s);定义一个字符串输入流的对象sin,并调用sin的复制构造函数,将line中所包含的字符串放入sin 对象中!
sin >> key >> id;//读取里面的字符串每一行一个key id
keys[key] = id;
}
}
void read_prog(const string& file, string& prog) //读取代码,并追加到prog上
{
ifstream fin(file.c_str());
if (!fin)
{
cerr << file << " error!" << endl;
// exit(2);
}
prog.clear();
string line;
while (getline(fin, line))
{
prog += line + '\n';
}
}
/**
这个是用来判断一个字符是不是
操作符的
*/
bool IsOperator(char ch)
{
if (ch == '+' || ch == '-' ||
ch == '*' || ch == '/' ||
ch == '(' || ch == ')' || ch == '=')
return true;
else
return false;
}
//运算符的优先关系
//'+', '-', '*', '/', '(', ')', '#'
char OprRelation[7][7] = {{'>', '>', '<', '<', '<', '>', '>'}, //'+'
{'>', '>', '<', '<', '<', '>', '>'}, //'-'
{'>', '>', '>', '>', '<', '>', '>'}, //'*'
{'>', '>', '>', '>', '<', '>', '>'}, //'/'
{'<', '<', '<', '<', '<', '=', ' '}, //'('
{'>', '>', '>', '>', ' ', '>', '>'}, //')'
{'<', '<', '<', '<', '<', ' ', '='}};//'#'
/**
这个是用来获取每一个操作符的优先级
*/
int ConvertToIndex(char opr)
{
int index;
switch (opr)
{
case '+':
index = 0;
break;
case '-':
index = 1;
break;
case '*':
index = 2;
break;
case '/':
index = 3;
break;
case '(':
index = 4;
break;
case ')':
index = 5;
break;
case '=':
index = 6;
break;
}
return index;
}
/**
这个是用来获取连个字符的优先级
*/
char Precede(char opr1, char opr2)
{
int index1 = ConvertToIndex(opr1);
int index2 = ConvertToIndex(opr2);
return OprRelation[index1][index2];
}
/**
这个是用来对两个数进行求值
*/
double Operate(double opnd1, char op, double opnd2)
{
double ret;
switch(op)
{
case '+':
ret = opnd1 + opnd2;
break;
case '-':
ret = opnd1 - opnd2;
break;
case '*':
ret = opnd1 * opnd2;
break;
case '/':
ret = opnd1 / opnd2;
break;
}
return ret;
}
//算符优先算法
double CaculateExpression(string exp)
{
stack<char> optr; //只处理+ - # / ()运算
stack<double> opnd; //只处理0-9的整数运算
char ch;
int i = 0;
optr.push('=');
ch = exp[i++];
bool flag = true;
//如果##配对,表达式求值完成
while (flag&&(ch != '=' || optr.top() != '='))
{
if (!IsOperator(ch))
{
string f,g;
f=exp[i-1];
g.append(f);
while(!IsOperator(exp[i])){
f=exp[i];
g.append(f);
++i;
}
double value = atof(g.c_str());
//操作数入栈
opnd.push(value);
ch = exp[i++];
}
else
{
//比较栈顶操作符和新取得的操作符的优先关系
switch (Precede(optr.top(), ch))
{
case '<'://栈顶优先权低
optr.push(ch);
ch = exp[i++];
break;
case '='://括号配对,栈顶括号弹出
optr.pop();
if(exp.length()==i){
flag=false;
}else{
ch = exp[i++];
}
break;
case '>'://栈顶优先权高,先弹出,计算,结果操作数入栈
char op = optr.top();
optr.pop();
double num2 = opnd.top();//第二个操作数在前
opnd.pop();
double num1 = opnd.top();
opnd.pop();
double ret = Operate(num1, op, num2);
opnd.push(ret);
break;
}
}
}//end of while
//操作数栈的唯一元素即为计算结果
return opnd.top();
}
void cifafenxi()
{
map<string, int> keys;
init_keys("a.txt", keys);
string prog;
read_prog("b.txt", prog);
vector< _2tup > tups;
string token, id;
string::size_type pos = 0;//size_type属于string标准库,作用可看做相当于unsigned·int
int row = 1;
_2tup tu;
int no = 0;
// freopen("CON", "w", stdout);//结果在控制台上输出
freopen("c.txt","w",stdout);
do
{
tu = scanner(prog, pos, keys, row);
switch (tu.id)
{
case -1://返回的是错误
++no;
cout << no << ": ";
cout << "Error in row" << row << "!" << '<' << tu.token<< "," << tu.id << '>' << endl;
tups.push_back(tu);
break;
case -2:
++row;
// cout << '<' << tu.token<< "," << tu.id << '>' << endl;
break;
default:
s=prog;
cout << '(' << tu.id<< "," << tu.token << ')' << endl;
tups.push_back(tu);
break;
}
}
while (pos < prog.size());
}
void yufafenxi()//语法分析
{
freopen("CON", "w", stdout);//结果在控制台上输出
flag=advance();
if(flag)
{
expressionAnalysis();
}
if(flag!=-1 && !conterr)
{
cout<<"正确:"<<s<<endl;
cout<<CaculateExpression(s)<<endl;
}
}
int main()
{
cifafenxi();
yufafenxi();
return 0;
}