一. 实验目的
写一个简单的程序如:
add(2, 2)
subtract(4, 2)
add(2, subtract(4, 2))
将它生成中间代码
二. 实验要求
给定一个简单语言的文法描述,本程序是该语言的编译器前端。
输入一个符合该文法规则的源文件,输出三地址形式的中间代码。
具体功能有词法分析,语法分析,分析流程显示,错误提示等。
三. 实验内容
解析:就是将原始代码转换成代码的抽象表示。
转换:是以这个抽象表示为基础,做编译器想做的任何事情
中间代码生成:就是将转换后的抽象表示变成新的代码
代码实现:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stack>
#include <stdlib.h>
using namespace std;
char src[1000010]; //存储源代码
char TokenList_kind[1010][100]; //词法单元流 之 类别
int TokenList_value[1010]; //词法单元流 之 值
char WordList[1010][100]; //符号表 -- 由token_value指向
int LineList[1010]; //记录每一个token对应的行数 -- 由token_value指向
int TokenListPoint; //词法单元流指针
int WordListPoint; //符号表指针
int WordsPoint; //语法分析时的词法单元流指针
int tmpcnt; //三地址语句中寄存器的编号
int ExpTable[11][8] = { //用 表驱动法 读取表达式 ,状态转换表
2, -1, 1, -1, -1, -1, -1, 9,
2, -1, -1, -1, -1, -1, -1, 9,
2, -1, -1, 3, -1, -1, -1, 9,
4, 5, -1, -1, -1, -1, -1, 9,
4, -1, 8, -1, 6, -1, 10, 9,
-1, 5, 8, -1, 6, -1, 10, 9,
4, 5, -1, -1, -1, 7, -1, 9,
4, 5, -1, -1, -1, -1, -1, 9,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 8, -1, 6, -1, 10, 9
};
/*
文法
1 Program->BEGIN Stmt-List END
2 Stmt-List->Stmt Stmt-List'
3 Stmt-List'->Stmt Stmt-List' | .
4 Stmt->Assign-stmt
5 Assign-stmt->ID = Expr
6 Expr->Term Expr'
7 Expr'->Add-Op Term Expr' | .
8 Term->Factor Term'
9 Term'->Multiple-Op Factor Term' | .
10 Factor->( Expr ) | ID | NUM
11 Add-Op->+ | -
12 Multiple-Op->* | /
预测分析表
非终结符号 输入符号
BEGIN ‘+’ ‘-’ ‘*’ ‘/’ ( ) ‘=’ ID NUM END $
Program 1
Stmt-List 2
Stmt-List' 3 .
Stmt 4
Assign-stmt 5
Expr 6 6 6
Expr' 7 7 . . .
Term 8 8 8
Term' . . 9 9 . . .
Factor 10_1 10_210_3
Add-Op 11_1 11_2
Multiple-Op 12_1 12_2
*/
char PreTab[12][12][100]={ //存储预测分析表
{"BEGIN Stmt-List END","","","","","","","","","","",""},
{"","","","","","","","","Stmt Stmt-List'","","",""},
{"","","","","","","","","Stmt Stmt-List'","",".",""},
{"","","","","","","","","Assign-stmt","","",""},
{"","","","","","","","","ID = Expr","","",""},
{"","","","","","Term Expr'","","","Term Expr'","Term Expr'","",""},
{"","Add-Op Term Expr'","Add-Op Term Expr'","","","",".","",".","",".",""},
{"","","","","","Factor Term'","","","Factor Term'","Factor Term'","",""},
{"",".",".","Multiple-Op Factor Term'","Multiple-Op Factor Term'","",".","",".","",".",""},
{"","","","","","( Expr )","","","ID","NUM","",""},
{"","+","-","","","","","","","","",""},
{"","","","*","/","","","","","","",""}
};
char Product[23][50]={ //记录产生式出现的字符串
"Program", //0
"Stmt-List", //1
"Stmt-List'", //2
"Stmt", //3
"Assign-stmt", //4
"Expr", //5
"Expr'", //6
"Term", //7
"Term'", //8
"Factor", //9
"Add-Op", //10
"Multiple-Op", //11
"BEGIN", //12
"+", //13
"-", //14
"*", //15
"/", //16
"(", //17
")", //18
"=", //19
"ID", //20
"NUM", //21
"END" //22
};
//语法树节点
struct Node{
Node(char na[]){ //构造函数
strcpy(name,na);
wp = 0;
brother = NULL;
next = NULL;
}
char name[50];
int wp; //终结符在token流中的位置
Node* brother; //指向下一个兄弟节点
Node* next; //指向当前节点的孩子节点
}*root,*now,*p;
void Init()
{
memset(src,0,sizeof(src)); //初始化源代码字符数组
memset(TokenList_kind,0,sizeof(TokenList_kind)); //初始化词法单元流
memset(TokenList_value,0,sizeof(TokenList_value)); //初始化词法单元流
memset(WordList,0,sizeof(WordList)); //初始化符号表
TokenListPoint = 1;
WordListPoint = 1;
WordsPoint = 1;
//初始化指针
root = NULL;
now = NULL;
p = NULL;
tmpcnt = 1;
}
//--------------- 词法分析 start ---------------
void AddToken(char kind[],char value[],int line) //将<类别,值>放入token流中
{
strcpy(TokenList_kind[TokenListPoint],kind);
TokenList_value[TokenListPoint++] = WordListPoint;
strcpy(WordList[WordListPoint],value);
LineList[WordListPoint++] = line;
}
void strsub(char str1[],int start,int len,char str2[]) //截取str1的子字符串给str2
{
int i=0,j;
for(j=0;j<len;j++){
str2[i++] = str1[start+j];
}
str2[i] = '\0';
}
void InputString() //从文件中读取源代码,同时过滤注释,一行只能放置一条语句
{
//文件读入
FILE* fs = fopen(".\\src.txt","rb"); //源代码
if(fs==NULL){
printf("源代码文件 src.txt 不存在\n");
return ;
}
char s[10010]={0};
//fscanf(fs,"%s",src);
while(fgets(s,10010,fs)){
if(sscanf(s,"%s",s)==-1){ //没有读到字符串,将s清空
s[0]='\0';
continue;
}
//过滤注释
if(s[0]=='/' && s[1]=='/')
continue;
int i;
for(i=0;s[i];i++)
if(s[i]=='/' && s[i+1]=='/')
break;
s[i]='\0';
strcat(src,s); //连接到源代码字符串后
strcat(src," "); //连接一个空白符
}
int len = strlen(src);
len--;
src[len] = '\0';
}
bool getBEGIN(int &i,int &line) //读取“BEGIN”
{
char tmp[6];
strsub(src,i,5,tmp);
if(strcmp(tmp,"BEGIN")==0){
i = i+5;
AddToken("BEGIN","BEGIN",line); //添加token,<类别,值>
return true;
}
else
return false;
}
bool getBLANK(int &i) //读取“空白符”==>' '
{
if(src[i]==' '){
i++;
return true;
}
else
return false;
}
bool getEND(int &i,int &line) //读取“END”
{
char tmp[4];
strsub(src,i,3,tmp);
if(strcmp(tmp,"END")==0){
i = i+3;
AddToken("END","END",line); //添加token,<类别,值>
return true;
}
else
return false;
}
bool getExp(int &i,int &line) //读取表达式,遇到' '结束
{
int status=0;
char tmp[10010]={0};
char t[2]={0};
int j=0;
stack <char> ss;
while(status!=8){
if(status==-1) //跳到错误的状态号,返回false
return false;
if(status==9) //跳到了错误状态,返回false
return false;
//根据src[i]确定下一个状态,直到抵达结束状态 8
if( ('a'<=src[i] && src[i]<='z') || ('A'<=src[i] && src[i]<='Z') ){
//读取到字母
status = ExpTable[status][0];
tmp[j++] = src[i++];
}
else if('0'<=src[i] && src[i]<='9'){
//读取到数字
status = ExpTable[status][1];
tmp[j++] = src[i++];
}
else{
switch(src[i]){
case ' ': //空白符
status = ExpTable[status][2];
if(tmp[0]!='\0'){
//如果是后来读到空白符,说明表达式该结束了
//将读取的最后一个单词放入token
if(j!=0){ //说明之前是一个单词或数字,否则是一个),)已经将最后一个单词放入token流中了,所以不需要处理它
if( ('a'<=tmp[0] && tmp[0]<='z') || ('A'<=tmp[0] && tmp[0]<='Z') )
AddToken("ID",tmp,line); //将这个字符代表的单词放入token流中
else if( '0'<=tmp[0] && tmp[0]<='9' )
AddToken("NUM",tmp,line); //将这个字符代表的单词放入token流中
j=0;
}
}
line++;
i++;
break;
case '=': // =
status = ExpTable[status][3];
tmp[j] = '\0';
AddToken("ID",tmp,line); //=前面一定是标识符,放入token流
j=0;
AddToken("=","=",line); //将当前的=也放入token流
i++;
break;
case '+': //OP
case '-':
case '*':
case '/':
status = ExpTable[status][4];
tmp[j] = '\0';
if( ('a'<=tmp[0] && tmp[0]<='z') || ('A'<=tmp[0] && tmp[0]<='Z') ) //如果运算符前是字母,则说明是标识符
AddToken("ID",tmp,line);
else if( '0'<=tmp[0] && tmp[0]<='9' )
AddToken("NUM",tmp,line);
j=0;
t[0] = src[i];
t[1] = '\0';
AddToken(t,t,line); //将运算符放入token流
i++;
break;
case '(': // (
status = ExpTable[status][5];
AddToken("(","(",line); //将(放入token流
ss.push('(');
i++;
break;
case ')': // )
status = ExpTable[status][6];
tmp[j] = '\0';
if( ('a'<=tmp[0] && tmp[0]<='z') || ('A'<=tmp[0] && tmp[0]<='Z') ) //如果)前是字母,则说明是标识符,即ID
AddToken("ID",tmp,line);
else if( '0'<=tmp[0] && tmp[0]<='9' )
AddToken("NUM",tmp,line);
j=0;
AddToken(")",")",line); //将(放入token流
if(ss.empty()) //括号不匹配
return false;
else
ss.pop();
i++;
break;
default: //其它
status = ExpTable[status][7];
i++;
break;
}
}
}
if(status==8){ //正确跳出
/*
if(ss.empty()) //括号匹配
return true;
else
return false;
*/
return true;
}
else
return false;
}
bool Lex() //进行词法分析
{
printf("词法分析......\n");
int i=0;
int line = 1;
InputString();
try{
getBEGIN(i,line)?1:throw 1;
getBLANK(i)?line++:throw 2;
while(1){ //读取表达式
if(src[i]=='\0') //还没检测到END,程序就结束了
throw 3;
char tmp[4];
strsub(src,i,3,tmp); //截取字符串
if(strcmp(tmp,"END")==0){
//如果检测到END,跳出循环
break;
}
//读取表达式
getExp(i,line)?1:throw 4;
}
getEND(i,line)?1:throw 3;
if(src[i]!='\0') //如果END结束标志之后还有输入符号,说明出错误了
throw 5;
}
catch(int err){
printf("【词法错误】\n");
//计算行号
int errline = 1;
int j;
for(j=0;j<=i;j++)
if(src[j]==' ')
errline++;
switch(err){
case 1:
printf("ERROR 1 (第%d行) : 没有读取到开始标识 BEGIN!\n",errline);
printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
printf("\t\t");
for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
printf(" ");
printf("^\n");
printf("\n");
return false;
case 2:
printf("ERROR 2 (第%d行) : 没有读取到空白符!\n",errline);
printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
printf("\t\t");
for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
printf(" ");
printf("^\n");
printf("\n");
return false;
case 3:
printf("ERROR 3 (第%d行) : 没有读取到结束标识 END!\n",errline);
printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
printf("\t\t");
for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
printf(" ");
printf("^\n");
printf("\n");
printf("\n");
return false;
case 4:
printf("ERROR 4 (第%d行) : 表达式错误。例如:标识符有误!\n",errline);
printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
printf("\t\t");
for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
printf(" ");
printf("^\n");
printf("\n");
return false;
case 5:
printf("ERROR 5 (第%d行) : BEGIN...END 代码段格式错误!\n",errline);
printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
printf("\t\t");
for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
printf(" ");
printf("^\n");
printf("\n");
return false;
default:break;
}
}
printf("没有词法错误\n");
printf("\n");
return true;
}
void printTokenList() //输出token流
{
int i=1;
printf("单词流:\n");
printf("<\t类别\t,值\t>\n");
for(;i<TokenListPoint;i++){
printf("<\t%s\t,%s\t>\n",TokenList_kind[i],WordList[TokenList_value[i]]);
}
printf("\n");
}
//--------------- 词法分析 end ---------------
//--------------- 语法分析 start ---------------
//生成语法分析树
void OutStack(stack <char*> z) //输出栈中内容的前两个
{
char t[200]={0};
int j=0;
while(!z.empty()){
if(j==2)
break;
if(j==1)
strcat(t,",");
strcat(t,z.top());
z.pop();
j++;
}
strcat(t,"$");
printf("%23s",t);
}
void OutRightStr() //输出当前token流中前两个
{
char t[200]={0};
int i,j=0;
for(i = WordsPoint;i<WordListPoint;i++){
if(j==2)
break;
char tt[200]={0};
sprintf(tt,"<%s,%s>",TokenList_kind[i],WordList[TokenList_value[i]]);
strcat(t,tt);
j++;
}
printf("%23s$",t);
}
void OutAction(char action[]) //输出动作
{
printf(" %s\n",action);
}
bool seltab(int row,char f[])
{
if(strcmp(TokenList_kind[WordsPoint],"BEGIN")==0){
strcpy(f,PreTab[row][0]);
}
else if(strcmp(TokenList_kind[WordsPoint],"+")==0){
strcpy(f,PreTab[row][1]);
}
else if(strcmp(TokenList_kind[WordsPoint],"-")==0){
strcpy(f,PreTab[row][2]);
}
else if(strcmp(TokenList_kind[WordsPoint],"*")==0){
strcpy(f,PreTab[row][3]);
}
else if(strcmp(TokenList_kind[WordsPoint],"/")==0){
strcpy(f,PreTab[row][4]);
}
else if(strcmp(TokenList_kind[WordsPoint],"(")==0){
strcpy(f,PreTab[row][5]);
}
else if(strcmp(TokenList_kind[WordsPoint],")")==0){
strcpy(f,PreTab[row][6]);
}
else if(strcmp(TokenList_kind[WordsPoint],"=")==0){
strcpy(f,PreTab[row][7]);
}
else if(strcmp(TokenList_kind[WordsPoint],"ID")==0){
strcpy(f,PreTab[row][8]);
}
else if(strcmp(TokenList_kind[WordsPoint],"NUM")==0){
strcpy(f,PreTab[row][9]);
}
else if(strcmp(TokenList_kind[WordsPoint],"END")==0){
strcpy(f,PreTab[row][10]);
}
else if(strcmp(TokenList_kind[WordsPoint],"$")==0){
strcpy(f,PreTab[row][11]);
}
else{
return false;
}
if(f[0]=='\0') //确定的表位置为空
return false;
return true;
}
bool Parse() //语法分析阶段。输入是token流,输出分析结果
{
stack <char*> z;
stack <Node*> nz;
z.push(*Product);
root = new Node("Program");
now = root;
printf("词法分析......\n");
printf("【分析流程】\n");
printf("%22s%24s%22s\n","栈","输入","动作");
char action[100]={0};
try{
while(!z.empty() || WordsPoint<WordListPoint){ //栈和输入串中只剩结束符号(栈空 or 指向'\0')时退出循环
//输出当前分析结果
OutStack(z); //输出栈中内容
OutRightStr(); //输出剩余输入字符串
OutAction(action); //输出动作
memset(action,0,sizeof(action));
//预处理。例:匹配e。预处理:将e出栈,输入指针后移。
//还没结束栈就空了
if(z.empty())
throw 1; //非法跳出
if(strcmp(z.top(),TokenList_kind[WordsPoint])==0){ //栈顶元素==指针指向字符,匹配成功
//语义动作 - 构造语法树
while(!now->brother){ //回到有下一个兄弟节点的节点为止
if(nz.empty()){
if(now==root) //如果回到了根节点
goto label;
else
throw 1;
}
now = nz.top();
nz.pop();
}
now = now->brother;
label:
//准备输出字符串 action
strcat(action,"匹配");
strcat(action,z.top());
//出栈、指针后移
if(!z.empty())
z.pop();
if(WordsPoint<WordListPoint)
WordsPoint++;
}
else{ //不相等,输出推导
//确定推导
char f[200]={0};
if(strcmp(z.top(),"Program")==0){
if(!seltab(0,f)) //从表中确定推导串
throw 2; //没有找到对应的推导
}
else if(strcmp(z.top(),"Stmt-List")==0){
if(!seltab(1,f)) //从表中确定推导串
throw 2; //没有找到对应的推导
}
else if(strcmp(z.top(),"Stmt-List'")==0){
if(!seltab(2,f)) //从表中确定推导串
throw 2; //没有找到对应的推导
}
else if(strcmp(z.top(),"Stmt")==0){
if(!seltab(3,f)) //从表中确定推导串
throw 2; //没有找到对应的推导
}
else if(strcmp(z.top(),"Assign-stmt")==0){
if(!seltab(4,f)) //从表中确定推导串
throw 2; //没有找到对应的推导
}
else if(strcmp(z.top(),"Expr")==0){
if(!seltab(5,f)) //从表中确定推导串
throw 2;
}
else if(strcmp(z.top(),"Expr'")==0){
if(!seltab(6,f)) //从表中确定推导串
throw 2;
}
else if(strcmp(z.top(),"Term")==0){
if(!seltab(7,f)) //从表中确定推导串
throw 2;
}
else if(strcmp(z.top(),"Term'")==0){
if(!seltab(8,f)) //从表中确定推导串
throw 2;
}
else if(strcmp(z.top(),"Factor")==0){
if(!seltab(9,f)) //从表中确定推导串
throw 2;
}
else if(strcmp(z.top(),"Add-Op")==0){
if(!seltab(10,f)) //从表中确定推导串
throw 2;
}
else if(strcmp(z.top(),"Multiple-Op")==0){
if(!seltab(11,f)) //从表中确定推导串
throw 2;
}
else{
throw 2;
}
//准备输出字符串 action
strcat(action,"输出");
strcat(action,z.top());
strcat(action,"->");
strcat(action,f);
//将栈顶字符串记录下来后用
char proleft[50];
//将栈顶元素出栈并将推导入栈
if(!z.empty()){
strcpy(proleft,z.top());
z.pop();
}
else
throw 1;
char tmp[100];
//如果推导出来的是空,即f->.,不作处理
if(f[0]=='.'){
nz.push(now);
now->next = new Node(".");
now = now->next; //now指向当前产生式右边的第一个字符串
while(!now->brother){ //回到有下一个兄弟节点的节点为止
if(nz.empty()){
if(now==root) //如果回到了根节点
goto label;
else
throw 1;
}
now = nz.top();
nz.pop();
}
now = now->brother;
continue;
}
stack <char*> tz; //临时的栈
//正向输入到临时栈中
while(sscanf(f,"%s",tmp)!=-1){
//语义动作 - 创建语法树
if(strcmp(proleft,now->name)==0){
nz.push(now); //将当前节点记录下来
now->next = new Node(tmp);
now = now->next; //now指向当前产生式右边的第一个字符串
p = now;
}
else{
p->brother = new Node(tmp);
p = p->brother;
}
char* pos = strstr(f,tmp);
strcpy(f,pos+strlen(tmp));
if(strcmp(tmp,"Program")==0){
tz.push(*(Product));
}
else if(strcmp(tmp,"Stmt-List")==0){
tz.push(*(Product+1));
}
else if(strcmp(tmp,"Stmt-List'")==0){
tz.push(*(Product+2));
}
else if(strcmp(tmp,"Stmt")==0){
tz.push(*(Product+3));
}
else if(strcmp(tmp,"Assign-stmt")==0){
tz.push(*(Product+4));
}
else if(strcmp(tmp,"Expr")==0){
tz.push(*(Product+5));
}
else if(strcmp(tmp,"Expr'")==0){
tz.push(*(Product+6));
}
else if(strcmp(tmp,"Term")==0){
tz.push(*(Product+7));
}
else if(strcmp(tmp,"Term'")==0){
tz.push(*(Product+8));
}
else if(strcmp(tmp,"Factor")==0){
tz.push(*(Product+9));
}
else if(strcmp(tmp,"Add-Op")==0){
tz.push(*(Product+10));
}
else if(strcmp(tmp,"Multiple-Op")==0){
tz.push(*(Product+11));
}
else if(strcmp(tmp,"BEGIN")==0){
tz.push(*(Product+12));
}
else if(strcmp(tmp,"+")==0){
tz.push(*(Product+13));
}
else if(strcmp(tmp,"-")==0){
tz.push(*(Product+14));
}
else if(strcmp(tmp,"*")==0){
tz.push(*(Product+15));
}
else if(strcmp(tmp,"/")==0){
tz.push(*(Product+16));
}
else if(strcmp(tmp,"(")==0){
tz.push(*(Product+17));
}
else if(strcmp(tmp,")")==0){
tz.push(*(Product+18));
}
else if(strcmp(tmp,"=")==0){
tz.push(*(Product+19));
}
else if(strcmp(tmp,"ID")==0){
tz.push(*(Product+20));
}
else if(strcmp(tmp,"NUM")==0){
tz.push(*(Product+21));
}
else if(strcmp(tmp,"END")==0){
tz.push(*(Product+22));
}
else{
throw 1;
}
}
//反向输出到真正的栈中
while(!tz.empty()){
if(strcmp(tz.top(),"Program")==0){
z.push(*(Product));
}
else if(strcmp(tz.top(),"Stmt-List")==0){
z.push(*(Product+1));
}
else if(strcmp(tz.top(),"Stmt-List'")==0){
z.push(*(Product+2));
}
else if(strcmp(tz.top(),"Stmt")==0){
z.push(*(Product+3));
}
else if(strcmp(tz.top(),"Assign-stmt")==0){
z.push(*(Product+4));
}
else if(strcmp(tz.top(),"Expr")==0){
z.push(*(Product+5));
}
else if(strcmp(tz.top(),"Expr'")==0){
z.push(*(Product+6));
}
else if(strcmp(tz.top(),"Term")==0){
z.push(*(Product+7));
}
else if(strcmp(tz.top(),"Term'")==0){
z.push(*(Product+8));
}
else if(strcmp(tz.top(),"Factor")==0){
z.push(*(Product+9));
}
else if(strcmp(tz.top(),"Add-Op")==0){
z.push(*(Product+10));
}
else if(strcmp(tz.top(),"Multiple-Op")==0){
z.push(*(Product+11));
}
else if(strcmp(tz.top(),"BEGIN")==0){
z.push(*(Product+12));
}
else if(strcmp(tz.top(),"+")==0){
z.push(*(Product+13));
}
else if(strcmp(tz.top(),"-")==0){
z.push(*(Product+14));
}
else if(strcmp(tz.top(),"*")==0){
z.push(*(Product+15));
}
else if(strcmp(tz.top(),"/")==0){
z.push(*(Product+16));
}
else if(strcmp(tz.top(),"(")==0){
z.push(*(Product+17));
}
else if(strcmp(tz.top(),")")==0){
z.push(*(Product+18));
}
else if(strcmp(tz.top(),"=")==0){
z.push(*(Product+19));
}
else if(strcmp(tz.top(),"ID")==0){
z.push(*(Product+20));
}
else if(strcmp(tz.top(),"NUM")==0){
z.push(*(Product+21));
}
else if(strcmp(tz.top(),"END")==0){
z.push(*(Product+22));
}
else{
throw 1;
}
tz.pop();
}
}
}
if(z.empty() && WordsPoint >= WordListPoint){ //正常退出循环
//输出最后一行分析结果
OutStack(z); //输出栈中内容
OutRightStr(); //输出剩余输入字符串
OutAction(action); //输出动作
}
else{ //非正常情况
throw 1;
}
}
catch(int err){
printf("\n");
printf("【语法错误】\n");
switch(err){
case 1:
printf("ERROR 1 (第%d行) : 非法跳出!\n",LineList[WordsPoint]);
printf("\n");
return false;
case 2:
printf("ERROR 2 (第%d行) : 没有找到 %s 对应的推导!\n",LineList[WordsPoint],z.top());
printf("\n");
return false;
default:
break;
}
}
printf("没有语法错误\n");
printf("\n");
return true;
}
//--------------- 语法分析 end ---------------
//--------------- 生成三地址代码 start ---------------
//对语法分析树进行后序遍历,执行语义规则,一遍扫描之后,树根的code即为三地址代码
void setWP(Node* cur) //设置每一个叶子节点的wp指针
{
if(!cur->next){
if(cur->name[0]=='.')
return ;
cur->wp = WordsPoint++;
return ;
}
Node* p = cur->next;
while(p){
setWP(p);
p = p->brother;
}
}
char* getNext(Node* cur,FILE* fo)
{
//递归出口
if(!cur->next){
if(cur->name[0]=='.'
|| cur->name[0]=='('
|| cur->name[0]==')'){ //忽略空. 和 ( 和 )
char* t = new char[2];
t[0]='\0';
return t;
}
return WordList[TokenList_value[cur->wp]];
}
if(strcmp(cur->name,"Program")==0){
fprintf(fo,"%s\r\n",getNext(cur->next,fo));
getNext(cur->next->brother,fo);
fprintf(fo,"%s\r\n",getNext(cur->next->brother->brother,fo));
char* tmp = new char[2];
tmp[0] = '\0';
return tmp;
}
else if(strcmp(cur->name,"Assign-stmt")==0){
char* tmp = new char[2];
tmp[0] = '\0';
fprintf(fo,"%s=%s\r\n",getNext(cur->next,fo),getNext(cur->next->brother->brother,fo));
return tmp;
}
else if(strcmp(cur->name,"Term")==0){
char* tmp = new char[150];
tmp = getNext(cur->next->brother,fo);
if(tmp[0]=='*' || tmp[0]=='/'){
fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next,fo),tmp);
sprintf(tmp,"t%d",tmpcnt++);
return tmp;
}
}
else if(strcmp(cur->name,"Expr")==0){
char* tmp = new char[150];
tmp = getNext(cur->next->brother,fo);
if(tmp[0]=='+' || tmp[0]=='-'){
fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next,fo),tmp);
sprintf(tmp,"t%d",tmpcnt++);
return tmp;
}
}
else if(strcmp(cur->name,"Term'")==0){
char* tmp = new char[150];
if(cur->next->brother!=NULL){
p = cur->next->brother->brother;
if(p->next->brother!=NULL){
tmp = getNext(cur->next->brother->brother,fo);
if(tmp[0]=='*' || tmp[0]=='/'){
if(*getNext(cur->next,fo)=='/'){ //如果最前面的是‘-’,后面的运算符应该是反的
if(tmp[0]=='/')
tmp[0]='*';
else
tmp[0]='/';
}
fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next->brother,fo),tmp);
sprintf(tmp,"%st%d",getNext(cur->next,fo),tmpcnt++);
return tmp;
}
}
}
}
else if(strcmp(cur->name,"Expr'")==0){
char* tmp = new char[150];
if(cur->next->brother!=NULL){
p = cur->next->brother->brother;
if(p->next->brother!=NULL){
tmp = getNext(cur->next->brother->brother,fo);
if(tmp[0]=='+' || tmp[0]=='-'){
if(*getNext(cur->next,fo)=='-'){ //如果最前面的是‘-’,后面的运算符应该是反的
if(tmp[0]=='-')
tmp[0]='+';
else
tmp[0]='-';
}
fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next->brother,fo),tmp);
sprintf(tmp,"%st%d",getNext(cur->next,fo),tmpcnt++);
return tmp;
}
}
}
}
char * s = new char[150]; //new一个字符串,存储这个节点的结果
memset(s,0,sizeof(s));
Node* p = cur->next;
while(p){
strcat(s,getNext(p,fo));
p = p->brother;
}
return s;
}
void get3AddrCode()
{
WordsPoint = 1;
FILE* fo = fopen(".\\out.txt","wb");
if(fo==NULL){
printf("三地址代码生成文件 out.txt 打开失败!\n");
return ;
}
setWP(root);
printf("生成三地址语句......\n");
getNext(root,fo);
}
//--------------- 生成三地址代码 end ---------------
int main()
{
bool f=true;
Init();
if(!Lex()) //词法分析
f=false;
//printTokenList();
if(!Parse()) //语法分析
f=false;
if(f) //都通过了才能生成三地址代码
get3AddrCode(); //生成三地址代码
return 0;
}
src.txt的内容:
BEGIN
a=b*(c+2)
END
结果: