#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <map>
using namespace std;
/********************************************************************
/PL0的编译程序 C++版
/
/词法分析 语法分析 符号表
/
/词法分析过程中
/遇到.号就立即结束,无论后面是否有内容都忽略
/遇到非法字符,中断分析并给出错误报告
/遇到超过14个字母的单词,截断成14个字母的,如果他不是数字再截断成10个字母的并给出错误报告
/遇到数字开头的标识符 中断分析并给出错误报告
/
/语法分析过程中
/利用词法分析的结果进行分析
/严格按照PL0程序定义来编写
/
/<程序> ::= <程序首部> <分程序>.
/<程序首部> ::= PROGRAM <标识符>;
/<分程序> ::= [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句部分>
/<常量说明部分> ::= CONST <常量定义>{,<常量定义>};
/<常量定义> ::= <标识符>=<无符号整数>
/<变量说明部分> ::= VAR <标识符>{,<标识符>};
/<过程说明部分> ::= <过程首部>;<分程序>;【原课件中没有最后的分号,经分析应该有分号】
/<过程首部> ::= PROCEDURE <标识符>
/<语句部分> ::= <语句>|<复合语句>
/<复合语句> ::= BEGIN <语句>{;<语句>} END【符合语句应该注意的是,END前距离END最近的那条语句一定没有分号,其他语句必须有分号】
/<语句>::= <赋值语句>|<条件语句>|<当型 循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句>
/<赋值语句> ::= <标识符>:=<表达式>
/<读语句> ::= READ(<标识符>{,<标识符>})
/<写语句> ::= WRITE(<表达式>{,<表达式>})
/<过程调用语句> ::= CALL <标识符>【原课件中有分号,实际不应该有】
/<条件语句> ::= IF <条件> THEN <语句>
/<当型循环语句> ::= WHILE <条件> DO <语句>
/<因子> ::= <标识符>|<常量>|(<表达式>)
/<项> ::= <因子>{<乘法运算符><因子>}
/<乘法运算符> ::= *|/
/<表达式> ::= [+|-]<项>{<加法运算符><项>}
/<加法运算符> ::= +|-
/<条件> ::= <表达式><关系运算符><表达式>|ODD <表达式>
/<关系运算符> ::= #|=|>|>=|<|<=
/
/如果上述的任意一个步骤出了问题都会有错误提示,并指出是在源文件中的第几行,是哪一个定义出了问题
/当一个<语句>【复合语句除外】判断成功之后,在词法分析的结果找到这个语句的开始和结束,并输出这个语句是什么语句
/语法分析的实际操作类似一个走迷宫的搜索问题,找到一个可行的方向就前进,直到走到把所有单词都分析完,或者走不通了,一层层回溯返回FALSE给出错误信息
/
/符号表
/符号表的建立是在语法分析的深度优先搜索的基础上完成的
/基于深度优先搜索的特点当一个过程分析完,直接就能得到它的层级
/变量的LEVEL等于定义该变量的过程的LEVEL+1
/每个过程的变量的ADR都重新从3开始递增
/常量没有LEVEL,没有ADR,
/变量和常量都没有SIZE
/当程序的变量分析完就得到了符号表中最近插入的过程的SIZE【SIZE等于该过程的最后一个变量的ADR+1,若该过程没有变量则等于3】
/
*******************************************************************/
typedef struct t{
string name,kind;
int val,lev,adr,size;
}Table;
bool isChengXu(int lev);
bool isFenChengXu(int lev);
bool isChengXuShouBu();
bool isChangLiangShuoMing();
bool isBianLiangShuoMing();
bool isGuoChengShuoMing(int lev);
bool isYuJuBuFen();
bool isChangLiangDingYi();
bool isGuoChengShouBu(int lev);
bool isYuJu();
bool isFuHeYuJu();
bool isFuZhiYuJu();
bool isWhileDoYuJu();
bool isIfYuJu();
bool isCallYuJu();
bool isWriteYuJu();
bool isReadYuJu();
bool isTiaoJian();
bool isYinZi();
bool isXiang();
bool isBiaoDaShi();
void printYuFa(int x,int y,string statement);//输出语法分析的结果
void addtotable(string name,string kind,int val,int lev,int adr,int size);//把记录加入符号表
int stoi(string s);//字符串转化成数字
string itos(int n);//数字转化成字符串
int error(int e,int eline);//指出在eline行有错误e
bool isNumber(string s);//判断一个字符串是不是一个数字
string strtoupper(string s);//把字符串转换为大写
string strtolower(string s);//把字符串转换为小写
int lvkongge(string mSourse,int &i);//虑空格,遇到文件末尾结束,返回-1
string getnext(string mSourse,int &i);//从源文件中识别一个单词并返回
bool cifafenxi(string mSourse);//词法分析的主函数,执行虑空格操作,然后用getnext函数获取下一个单词进行分析,依次循环知道lvkongge函数返回-1
void initmp();//初始化保留字界符的查找表,
bool nexteql(string s);//从词法分析的结果顶部取出一个单词,判断s是否与之相等,不相等返回FALSE,相等返回TRUE并且顶部指针指向词法分析结果的下一个单词
void printYuFa(int x,int y,string statement);//输出语句,在词法分析的结果数组中下标号从x到y是一个statement语句,遍历输出这个语句
void printtable();//输出符号表
void printErrors();//输出错误报告
map<string,string> words;//保留字,界符等等,的对照表
string wQueue[200][2];//词法分析的最终结果,模拟成一个队列【wQueue[i][0]是第i个位置的单词,wQueue[i][1]是第i个单词的类别】
int whead=0,wtail=0;//队列的头,尾指针
int wline[200]={0},line=1;//单词的行号,与wQueue对应
string name;//每一次调用nexteqls函数都会改变,具体看nexteqls函数
string errors[100];//存储的错误信息
int etop=0;
Table table[100];
int tabletop=0,padr=1,pradr=3,plev=-1,ltx=0;
void addtotable(string name,string kind,int val,int lev,int adr,int size){//添加一条信息到符号表
table[tabletop].name=name;
table[tabletop].kind=kind;
table[tabletop].val=val;
table[tabletop].lev=lev;
table[tabletop].adr=adr;
table[tabletop++].size=size;
if(kind=="PROCEDURE"){
plev=lev,pradr=3;
if(tabletop>0){
table[ltx].size=table[tabletop-2].adr==-1?3:(1+table[tabletop-2].adr);
}
ltx=tabletop-1;
}
}
string find(string s){
int i=0;
while(i<tabletop){
if(table[i].name==s){
return table[i].kind;
}
i++;
}
return "@_@";
}
int stoi(string s){//把字符串转换成整数
int i=-1;
int r=0;
while(s[++i]){
r*=10;
r+=s[i]-'0';
}
return r;
}
string itos(int n){//把整数n转换成string型
string s;
char c[10]="";
int l=8;
c[9]=0;
while(n>=10){
c[l--]=n%10+'0';
n/=10;
}
c[l--]=n+'0';
s=c+(++l);
return s;
}
int error(int e,int eline) { //错误处理
switch(e){
case 0:{
errors[etop++]=itos(e)+": "+itos(eline)+"行有非法字符";
break;
}
case 1:{
errors[etop++]=itos(e)+": "+itos(eline)+"行有超过14个字母的单词";
break;
}
case 2:{
errors[etop++]=itos(e)+": "+itos(eline)+"行有数字开头的标识符";
break;
}
case 3:{
errors[etop++]=itos(e)+": "+itos(eline)+"行有超过10个字母的标识符";
break;
}
case 4:{
errors[etop++]=itos(e)+": "+itos(eline)+"行程序结尾没有.";
break;
}
case 5:{
errors[etop++]=itos(e)+": "+itos(eline)+"行程序首部标识符后面没有;";
break;
}
case 6:{
errors[etop++]=itos(e)+": "+itos(eline)+"行程序首部PRAGRAM后面没有标识符";
break;
}
case 7:{
errors[etop++]=itos(e)+": "+itos(eline)+"行没有程序首部";
break;
}
case 8:{
errors[etop++]=itos(e)+": "+itos(eline)+"行分程序后缺少语句部分";
break;
}
case 9:{
errors[etop++]=itos(e)+": "+itos(eline)+"行常量说明的,字符后面有错误";
break;
}
case 10:{
errors[etop++]=itos(e)+": "+itos(eline)+"行常量说明后面没有;结尾";
break;
}
case 11:{
errors[etop++]=itos(e)+": "+itos(eline)+"行常量定义有错误";
break;
}
case 12:{
errors[etop++]=itos(e)+": "+itos(eline)+"行变量说明多了,";
break;
}
case 13:{
errors[etop++]=itos(e)+": "+itos(eline)+"行变量说明没有;结尾";
break;
}
case 14:{
errors[etop++]=itos(e)+": "+itos(eline)+"行VAR后面没有定义的标识符";
break;
}
case 15:{
errors[etop++]=itos(e)+": "+itos(eline)+"行分程序后面没有;结尾";
break;
}
case 16:{
errors[etop++]=itos(e)+": "+itos(eline)+"行过程说明后面没有分程序";