写在开头:
编译真的是一个很难的东西,课上完,题是会写了,代码是一点写不来,我这代码还是在先人的代码的基础上改编的,真是绷不住了。然后编译这个过程相对于我们用户来说也是很透明的,以至于不管你写了多少代码,你基本还是不知道它是怎么将你的代码转换成正确,简化过的汇编语言。但没有这玩意我们就用不了高级语言,所以还是要向研究编译过程的前人致以崇高的敬意。
声明:本人c++入门水平,佬们没必要浪费时间看这坨代码。
如果有任何违规的地方,请第一时间联系我,我会立即删除本文。
输入:PL/0源程序所在的文件。 输出:关键字、专用符号以及其它标记。
本实验实现的PL/0的基本词法如下:
关键字: begin、call、const、do、end、if、odd、procedure、read、then、var、while、write;
专用符号: + , - , * , / , ( , ) , =(逻辑判断符号,等于) , , , .(程序结束标志) , #(不等于) , ; , := , <= , >=
其它标记:id num
分别给以上关键词,专用符号,其他标记标号,用以简化输出。
关键字对应1~13号,id对应100号,num对应200号,专用符号对应:‘+’(407),‘-’(408),‘*’(409),‘/’(410),‘(’(502),‘)’(503),‘=’(401),
‘,’(504),‘.’(0),'#'(406),';'(501),':='(511),'<='(404),'<'(405),'>='(402),'>'(403)
ID = letter (letter/digit)*
NUM = digit digit*
letter = a|b|...|z|A|B|...|Z|
ditit= 0|1|...|9
此处用来说明代码中的主要函数:1.Scan函数:这是对程序进行词法分析的主要函数,用来确定接下来的词是否为:关键词or数字常量or专用符号or什么都不是。2.main函数:将文件中的内容提取出来,对文件中的每个词进行词法分析,每分析完一个词就按照该词的种类进行输出。
程序中先判断这个句语句中每个单元为关键字、常数、运算符、界符,对与不同的单词符号给出不同编码形式的编码,用以区分之。
文件内的PL0代码:
const m=7, n=85;
var x,y,z,q,r;
procedure multiply;
var a,b;
begin
a:=x; b:=y; z:=0;
while b>0 do
begin
if odd b then z:=z+a;
a:=2*a; b:=b/2;
end;
write(a,b);
end;
procedure divide;
var w;
begin
r:=x; q:=0; w:=y;
while w<=r do w:=2*w;
while w>y do
begin
q:=2*q; w:=w/2;
if w<=r then
begin
r:=r-w;
q:=q+1;
end;
end;
write(r,w);
end;
procedure gcd;
var f,g;
begin
f:=x;
g:=y;
while f#g do
begin
if f<g then g:=g-f;
if g<f then f:=f-g;
end;
write(f,g);
end;
begin
x:=m; y:=n; call multiply;
x:=25; y:=3; call divide;
read(x,y); call gcd;
end.
程序的源代码:
#include<iostream>
#include<string>
#include<fstream>
#include<sstream>
using namespace std;
int i,j,k,flag,number,status;
/*status用来判断字符串是否为关键词!*/
char ch;
string words = "";
string keywords[13] = {"begin","call","const","do","end","if","odd","procedure","read","then","var","while","write"};
string program;
int Scan(string program)
{
words = "";
number = 0; status = 0;
j = 0;ch = program[i++];
while(ch == ' ' or ch == '\n' or ch =='\r')/*跳过空格和换行符*/
{
ch = program[i++];
}
/*如果是字符串*/
if ((ch >= 'a') && (ch <= 'z' ))
{
while (((ch >= 'a') && (ch <= 'z'))||((ch >= '0') && (ch <= '9')))
{
words += ch;
ch=program[i++];
}
i--;
for (k = 0; k < 13; k++)
if (words.compare(keywords[k]) == 0)
switch(k)
{
case 0:{//begin
flag = 1;
status = 1;
break;
}
case 1:{//call
flag = 2;
status = 1;
break;
}
case 2:{//const
flag = 3;
status = 1;
break;
}
case 3:{//do
flag = 4;
status = 1;
break;
}
case 4:{//end
flag = 5;
status = 1;
break;
}
case 5:{//if
flag = 6;
status = 1;
break;
}
case 6:{//odd
flag = 7;
status = 1;
break;
}
case 7:{//procedure
flag = 8;
status = 1;
break;
}
case 8:{//read
flag = 9;
status = 1;
break;
}
case 9:{//then
flag = 10;
status = 1;
break;
}
case 10:{//var
flag = 11;
status = 1;
break;
}
case 11:{//while
flag = 12;
status = 1;
break;
}
case 12:{//write
flag = 13;
status = 1;
break;
}
}
if (status == 0)
{
flag = 100;
}
}
/*如果是数字*/
else if (ch >= '0' && ch <= '9')
{
number = 0;
while (ch >= '0' && ch <= '9' )
{
number = number*10+(ch-'0');
ch= program[i++];
}
flag = 200;
i--;
}
/*其他的一些特殊符号*/
else switch (ch)
{
case '=':{//相等
words+= ch;
flag = 401;
break;
}
case '>':{// >= or >
words += ch;
ch= program[i++];
if (ch == '=')
{
words += ch;
flag = 402;
}
else
{
i--;
flag = 403;
}
break;
}
case '<':{// <= or <
words += ch;
ch= program[i++];
if (ch == '=')
{
words += ch;
flag = 404;
}
else
{
i--;
flag = 405;
}
break;
}
case '#':{// #不等于
words += ch;
flag = 406;
break;
}
case '+':{// +
words += ch;
flag= 407;
break;
}
case '-':{// -
words += ch;
flag = 408;
break;
}
case '*':{// *
words += ch;
flag = 409;
break;
}
case '/':{// /
words += ch;
flag= 410;
break;
}
case ':':{// :=(赋值)
words += ch;
ch = program[i++];
if(ch == '=')
{
words += ch;
flag = 511;
}
else
{
flag = -1;
}
break;
}
case ';':{// ;
words += ch;
flag = 501;
break;
}
case '(':{// (
words += ch;
flag = 502;
break;
}
case ')':{// )
words += ch;
flag = 503;
break;
}
case ',':{// ,
words += ch;
flag = 504;
break;
}
case '.':{// .
words += ch;
flag = 0;
break;
}
default:{
flag = -1;
break;
}
}
return flag;
}
int main()
{
ifstream file("/Users/zpt/code/cpphomework/PL0语句.txt");
if(!file.is_open())
{
cerr<<"无法打开文件"<<endl;
return -1;
}
stringstream buffer;
buffer <<file.rdbuf();
program = buffer.str();
file.close();
i = 0;
do{
flag = Scan(program);
if (flag == 200)
{
cout<<flag<<" , "<<number<<endl;;
}
else if (flag == -1)
{
cout<<flag<<" , error words:"<<words<<endl;
}
else
{
cout<<flag<<" , "<<words<<endl;
}
}while (flag != 0);
return 0;
}
关键词实际上是按照字典序排的,可以用折半查找来提高查找效率。
输入:PL/0源程序所在的文件。 输出:将错误信息输出到语法错误文件中,输出语法树。
对于已给PL/0语言文法,利用递归子程序法,编制语法分析程序。
主要函数有:
1.void error(int n);根据n的不同,输出不同的错误信息。
2.int getsym();读取一个词
3.int getch();读取一个字符
4.void init();对一些要用到的数组进行初始化,如:ssym存储专用字符;word存储关键字以方便匹配;wsym存储关键词的枚举类型,用来表示关键词的类型等;
6.int constdeclaration(int* ptx,int lev,int *pdx);对于常量定义部分的处理函数
7.int vardeclaration(int *ptx,int lev,int* pdx);对于变量声明部分的处理函数
8.int position(char* idt,int tx);查找变量名
9.int inset(int e,bool* s);返回对应的e号的终结符是否属于此部分的First集合
10.int addset(bool* sr,bool* s1,bool* s2,int n);将两个First集合求并集
11.int subset(bool* sr,bool* s1,bool* s2,int n);将两个First集合求差
12.int mulset(bool * sr,bool* s1,bool* s2,int n);将两个First集合求交集
13.int test(bool* s1,bool*s2,int n);测试下一个词是否属于First集合,若不属于,则报错,并一直查找下一个词直到下一个词属于First集合。
14.int factor(bool* fsys,int* ptx,int lev);因子(一个具体的非终结符)的处理
15.int term(bool* fsys,int* ptx,int lev);项(一个具体的非终结符)的处理
16.int expression_r(bool* fsys,int *ptx,int lev);表达式(一个具体的非终结符)的处理
17.int condition(bool* fsys,int* ptx,int lev);条件语句的处理
18.int statement(bool* fsys,int* ptx,int lev);对于以每种关键词开头的语句的处理
19.int block(int lev,int tx,bool* fsys);分程序(一个具体的非终结符)的处理
PL/0语法如下:
非终结符太多了,自顶下降分析的可能性就更多了,而且还有层的嵌套,所以摆了。
文件内的PL0代码:
const m=7, n=85;
var x,y,z,q,r;
procedure ; (这行少了标识符)
var a,b;
begin
a:=x; b:=y; z:=0;
while b>0 do
begin
if odd b then z:=z+a;
a:=2*a; b:=b/2;
end;
write(a,b);
end;
procedure divide;
var w;
begin
r:=x; q:=0; w:=y;
while w<=r do w:=2*w;
while w>y do
begin
q:=2*q; w:=w/2;
if w<=r then
begin
r:=r-w;
q:=q+1;
end;
end;
write(r,w);
end;
procedure gcd;
var f,g;
begin
f:=x;
g:=y;
while f#g do
begin
if f<g then g:=g-f;
if g<f then f:=f-g;
end;
write(f,g);
end;
begin
x:=m; y:=n; call multiply; (因为之前的过程定义少了标识符,所以这个表示符未定义)
x:=25; y:=3; call divide;
read(x,y); call gcd;
. (这行少了end)
程序的源代码:
LP0头文件:
#ifndef LP0_h
#define LP0_h
#define norw 13//关键字的个数
#define txmax 100//名字表的容量
#define nmax 14//数字的最大位数
#define al 10//符号的最大长度
#define amax 2047//地址上界
#define levmax 3//最大允许的嵌套声明层数
#define cxmax 200//最多的虚拟机代码数
#define one_line_max_character_num 105//一行的字符个数的上线,用于限制line(缓冲区数组)的大小
enum symbol{
//枚举类型:
//nul=0,ident=1,number=2,plus=3,minus=4
//times=5,依次类推,procsym=31
nul, ident, number,
//下面的表示的是系统的算数运算符以及逻辑运算符,知道意思就可以
plus, minus, times,//+,-,*
slash, oddsym, eql, neq,// /,判断是否为奇数,=,#
lss, leq, gtr, geq, lparen,// <,<=,>,>=,(
rparen, comma, semicolon, period, becomes,//) , , , ; , . , :=
//下面的表示是系统的保留字
beginsym, endsym, ifsym, thensym, whilesym,
writesym, readsym, dosym, callsym, constsym,
varsym, procsym,
};
#define symnum 32
enum object{
constant,
variable,
procedur,
};
enum fct{
lit, opr, lod,
sto, cal, inte,
jmp, jpc,
};//不用
#define fctnum 8//不用
struct instruction
{
enum fct f;//虚拟机代码指令
int l;//引用层与声明层的层差
int a;//根据f的不同而不同,参考课本
};//不用
FILE* fas;//输出名字表
FILE* fa;//输出虚拟机代码
FILE* fa1;//输出源文件及其各行对应的首地址
FILE* fa2;//输出结果
bool listswitch;
bool tableswitch;
char ch;//获取字符的缓冲区
int tx = 0;//当前符号表的下标
enum symbol sym;
char id[al+1];
int num;
int cc,ll;//cc表示当前字符的位置
int cx;//虚拟机代码指针
char line[81];//读取行缓冲区
char a[al+1];//临时符号,多出的一个字节用于表示字符串的结尾
struct instruction code [cxmax];//存放虚拟机代码的数组
char word[norw][al];//保留字
enum symbol wsym[norw];//保留字对应的符号值
enum symbol ssym[256];//单符号的符号值
char mnemonic [fctnum][5];//虚拟机代码指令的名称
bool declbegsys[symnum];//表示声明开始的符号集合
bool statbegsys[symnum];//表示语句开始的符号集合
bool facbegsys[symnum];//表示因子开始的符号集合
//名字表结构
struct tablestruct
{
char name[al];//名字
enum object kind;//类型:const,var,array,procedure
int val;//数值,仅const使用
int level;//所处层
int adr;//地址
int size;//需分配的数据空间
};
struct tablestruct table[txmax];//名字表
FILE* fin;
FILE* fout;
char fname[al];
int err;//错误计数器,没出一次错误,其加一
#define getsymdo if(-1==getsym())return -1
#define getchdo if(-1==getch())return -1
#define testdo(a,b,c) if(-1==test(a,b,c))return -1
#define gendo(a,b,c) if(-1==gen(a,b,c))return -1
#define expressiondo(a,b,c) if(-1==expression_r(a,b,c))return -1
#define factordo(a,b,c) if(-1==factor(a,b,c))return -1
#define termdo(a,b,c) if(-1==term(a,b,c))return -1
#define conditiondo(a,b,c) if(-1==condition(a,b,c))return -1
#define statementdo(a,b,c) if(-1==statement(a,b,c))return -1
#define constdeclarationdo(a,b,c) if(-1==constdeclaration(a,b,c))return -1
#define vardeclarationdo(a,b,c) if(-1==vardeclaration(a,b,c))return -1
void error(int n);
int getsym();
int getch();
void init();
int gen(enum fct x,int y,int z);
int test(bool*s1,bool*s2,int n);
int inset(int e,bool*s);
int addset(bool*sr,bool*s1,bool*s2,int n);
int subset(bool*sr,bool*s1,bool*s2,int n);
int mulset(bool*sr,bool*s1,bool*s2,int n);
int block(int lev,int tx,bool* fsys);
void interpret();
int factor(bool* fsys,int* ptx,int lev);
int term(bool*fsys,int*ptx,int lev);
int condition(bool*fsys,int*ptx,int lev);
int expression_r(bool*fsys,int*ptx,int lev);
int statement(bool*fsys,int*ptx,int lev);
void listcode(int cx0);
int vardeclaration(int* ptx,int lev, int* pdx);
int constdeclaration(int* ptx,int lev, int* pdx);
int position(char* idt,int tx);
void enter(enum object k,int* ptx,int lev,int* pdx);
int base(int l,int* s,int b);
#endif /* LP0_h */
main函数:
#include <iostream>
#include "LP0.h"
#include <string>
#include<fstream>
#include<sstream>
std::ofstream outfile("/Users/zpt/code/cpphomework/语法分析结果.txt");
std::ifstream infile("/Users/zpt/code/cpphomework/PL0语句.txt");
int main()
{
if(!outfile.is_open())
{
std::cerr <<"打开输出文件失败"<<std::endl;
return -1;
}
if(!infile.is_open())
{
std::cerr <<"打开输入文件失败"<<std::endl;
return -1;
}
bool nxtlev[symnum];
init();
err = 0;
cc=cx=ll=0;
ch=' ';
if(-1 != getsym())
{
addset(nxtlev, declbegsys, statbegsys, symnum);
nxtlev[period] = true;
if(-1 == block(0, 0, nxtlev))
{
outfile<<std::endl;
return 0;
}
if(sym != period)
{
error(9);
}
if(err == 0)
{
outfile<<"编译成功"<<std::endl;
}
else
{
outfile<<"Errors in pl/0 program"<<std::endl;
}
}
outfile<<std::endl;
infile.close();
outfile.close();
return 0;
}
void error(int n)
{
char space[100];
memset(space, 32, 100);
space[cc-1] = 0;
switch(n)
{
case 1:
{
strcpy(space,"Error 01: 常数说明中“=”写成“:=”");
break;
}
case 2:
{
strcpy(space,"Error 02: 常数说明中的“=”后应为数字");
break;
}
case 3:
{
strcpy(space,"Error 03: 常数说明中的标识符后应是“=”");
break;
}
case 4:
{
strcpy(space,"Error 04: const,var,procedure后应为标识符");
break;
}
case 5:
{
strcpy(space,"Error 05: 漏掉了‘,’或‘;’");
break;
}
case 6:
{
strcpy(space,"Error 06: 过程说明后的符号不正确(应是语句开始符或过程开始符)");
break;
}
case 7:
{
strcpy(space,"Error 07: 应是语句开始符");
break;
}
case 8:
{
strcpy(space,"Error 08: 过程体内语句部分的后跟符不正确");
break;
}
case 9:
{
strcpy(space,"Error 09: 程序结尾丢了句号‘.’");
break;
}
case 10:
{
strcpy(space,"Error 10: 语句之间漏了‘;’");
break;
}
case 11:
{
strcpy(space,"Error 11: 标识符未定义");
break;
}
case 12:
{
strcpy(space,"Error 12: 赋值语句中,赋值号左部标识符属性应是标识符");
break;
}
case 13:
{
strcpy(space,"Error 13: 赋值语句左部标识符应是赋值号‘:=’");
break;
}
case 14:
{
strcpy(space,"Error 14: call后应为标识符");
break;
}
case 15:
{
strcpy(space,"Error 15: call后标识符属性应为过程");
break;
}
case 16:
{
strcpy(space,"Error 16: 条件语句中丢了then");
break;
}
case 17:
{
strcpy(space,"Error 17: 丢了end或;");
break;
}
case 18:
{
strcpy(space,"Error 18: while型循环语句中丢了do");
break;
}
case 19:
{
strcpy(space,"Error 19: 语句后的标识符不正确");
break;
}
case 20:
{
strcpy(space,"Error 20: 应为关系运算符");
break;
}
case 21:
{
strcpy(space,"Error 21: 表达式内标识符属性不能是过程");
break;
}
case 22:
{
strcpy(space,"Error 22: 表达式中漏掉了右括号‘)’");
break;
}
case 23:
{
strcpy(space,"Error 23: 因子后的非法符号");
break;
}
case 24:
{
strcpy(space,"Error 24: 表达式开始符不能是此符号");
break;
}
case 25:
{
strcpy(space,"Error 25: 文件在不该结束的地方结束了");
break;
}
case 26:
{
strcpy(space,"Error 26: 结束符出现在不该结束的地方");
break;
}
case 27:
{
strcpy(space,"Error 27: 过程嵌套层数太多");
break;
}
case 28:
{
strcpy(space,"Error 28: repeat语句中缺少until");
break;
}
case 29:
{
strcpy(space,"Error 29: write语句中漏掉了右括号‘)’");
break;
}
case 30:
{
strcpy(space,"Error 30: 数组缺少右括号‘]’");
break;
}
case 31:
{
strcpy(space,"Error 31: 数越界");
break;
}
case 32:
{
strcpy(space,"Error 32: read语句括号中标识符不是变量");
break;
}
case 33:
{
strcpy(space,"Error 33: read语句中漏掉了左括号‘(’");
break;
}
case 34:
{
strcpy(space,"Error 34: read语句中漏掉了右括号‘)’");
break;
}
case 35:
{
strcpy(space,"Error 35: 数组维数应为数字");
break;
}
case 36:
{
strcpy(space,"Error 36: 数组缺少左括号‘[’");
break;
}
case 37:
{
strcpy(space,"Error 37: 数组越界");
break;
}
case 38:
{
strcpy(space,"Error 38: 变量名称过长");
break;
}
}
outfile<<"****"<<space<<std::endl;
err++;
}
void init()
{
int i;
for(i=0;i<=255;i++)
{
ssym[i] = nul;
}
ssym['+'] = plus;
ssym['-'] = minus;
ssym['*'] = times;
ssym['/'] = slash;
ssym['('] = lparen;
ssym[')'] = rparen;
ssym['='] = eql;
ssym[','] = comma;
ssym['.'] = period;
ssym['#'] = neq;
ssym[';'] = semicolon;
strcpy(&(word[0][0]), "begin");
strcpy(&(word[1][0]), "call");
strcpy(&(word[2][0]), "const");
strcpy(&(word[3][0]), "do");
strcpy(&(word[4][0]), "end");
strcpy(&(word[5][0]), "if");
strcpy(&(word[6][0]), "odd");
strcpy(&(word[7][0]), "procedure");
strcpy(&(word[8][0]), "read");
strcpy(&(word[9][0]), "then");
strcpy(&(word[10][0]), "var");
strcpy(&(word[11][0]), "while");
strcpy(&(word[12][0]), "write");
wsym[0] = beginsym;
wsym[1] = callsym;
wsym[2] = constsym;
wsym[3] = dosym;
wsym[4] = endsym;
wsym[5] = ifsym;
wsym[6] = oddsym;
wsym[7] = procsym;
wsym[8] = readsym;
wsym[9] = thensym;
wsym[10] = varsym;
wsym[11] = whilesym;
wsym[12] = writesym;
for(i=0;i<symnum;i++)
{
declbegsys[i]=false;
statbegsys[i]=false;
facbegsys[i]=false;
}
declbegsys[constsym]=true;
declbegsys[varsym]=true;
declbegsys[procsym]=true;
statbegsys[beginsym]=true;
statbegsys[callsym]=true;
statbegsys[ifsym]=true;
statbegsys[whilesym]=true;
facbegsys[ident]=true;
facbegsys[number]=true;
facbegsys[lparen]=true;
}
int getch()
{
if(cc == ll)
{
ll=0;
cc=0;
outfile<<cx;
ch=' ';
while(ch!=10)
{
infile.get(ch);
if(infile.eof())
{
line[ll] = 0;
break;
}
outfile<<ch;
line[ll] = ch;
ll++;
}
outfile<<std::endl;
}
ch = line[cc];
cc++;
return 0;
}
int getsym()
{
int i,j,k;
while(ch==' '||ch==10||ch==9)
{
getchdo;
}
//是单词吗?
if(ch>='a'&&ch<='z')// *******有点不一样
{
k=0;
do
{
if(k<al)//没超过这个长度都读入
{
a[k] = ch;
}
k++;
getchdo;
}while((ch>='a'&&ch<='z')||(ch>='0'&&ch<='9'));
if(k>al)//超过这个长度了,报错
{
error(38);
k = al;
}
a[k] = 0;
strcpy(id, a);
i = 0;
j = norw-1;
do
{
k = (i+j)/2;
if(strcmp(id, word[k])<=0)
j = k-1;
if(strcmp(id, word[k])>=0)
i = k+1;
}while(i<=j);
if(i-1>j)
sym = wsym[k];
else
sym = ident;
}
else
{
//是数字吗?
if(ch>='0'&&ch<='9')
{
k = 0;
num = 0;
sym = number;
do
{
num=10*num+ch-'0';
k++;
getchdo;
}while(ch>='0'&&ch<='9');
k--;
if(k+1>nmax)
{
error(30);
}
}
else
{
//是赋值吗?
if(ch==':')
{
getchdo;
if(ch=='=')
{
sym = becomes;
getchdo;
}
else
{
sym = nul;
}
}
else
{
//是小于系列吗?
if(ch=='<')
{
getchdo;
if(ch=='=')
{
sym = leq;
getchdo;
}
else
sym = lss;
}
else
{
//是大于系列吗?
if(ch=='>')
{
getchdo;
if(ch=='=')
{
sym = geq;
getchdo;
}
else
sym = gtr;
}
else
{
sym = ssym[ch];
if(sym!=period)
getchdo;
}
}
}
}
}
return 0;
}
void enter(enum object k,int* ptx,int lev,int*pdx)
{
(*ptx)++;
strcpy(table[*ptx].name,id);
table[(*ptx)].kind = k;
switch(k)
{
case constant:
{
if(num>amax)
{
error(31);
num = 0;
}
table[*ptx].val = num;
break;
}
case variable:
{
table[*ptx].level = lev;
table[*ptx].adr = *pdx;
(*pdx)++;
break;
}
case procedur:
{
table[*ptx].level = lev;
break;
}
}
}
int constdeclaration(int* ptx,int lev,int *pdx)
{
if(sym == ident)
{
getsymdo;
if(sym == eql||sym == becomes)
{
if(sym == becomes)//const中,=写成了:=
error(1);
getsymdo;
if(sym == number)
{
enter(constant, ptx, lev, pdx);
getsymdo;
}
else
error(2);
}
else
error(3);
}
else
error(4);
return 0;
}
int vardeclaration(int *ptx,int lev,int* pdx)
{
if(sym == ident)
{
enter(variable, ptx, lev, pdx);
getsymdo;
}
else
{
error(4);
}
return 0;
}
int position(char* idt,int tx)
{
int i;
strcpy(table[0].name,idt);
i = tx;
while(strcmp(table[i].name, idt) != 0)
i--;
return i;
}
int inset(int e,bool* s)
{
return s[e];
}
int addset(bool* sr,bool* s1,bool* s2,int n)//集合取并集
{
int i;
for(i = 0;i<n;i++)
{
sr[i] = s1[i]||s2[i];
}
return 0;
}
int subset(bool* sr,bool* s1,bool* s2,int n)//集合减法
{
int i;
for(i=0;i<n;i++)
{
sr[i]=s1[i]&&(! s2[i]);
}
return 0;
}
int mulset(bool * sr,bool* s1,bool* s2,int n)//集合取交集
{
int i;
for(i=0;i<n;i++)
{
sr[i]=s1[i]&&s2[i];
}
return 0;
}
int test(bool* s1,bool*s2,int n)
{
if(!inset(sym, s1))
{
error(n);
while((!inset(sym, s1))&&(!inset(sym, s2)))
{
getsymdo;
}
}
return 0;
}
int factor(bool* fsys,int* ptx,int lev)
{
int i;
bool nxtlev[symnum];
testdo(facbegsys, fsys, 24);
while(inset(sym, facbegsys))
{
if(sym == ident)
{
i = position(id,*ptx);
if(i == 0)
{
error(11);
}
else
{
switch(table[i].kind)
{
case constant:
{
//产生四元式
break;
}
case variable:
{
//产生四元式
break;
}
case procedur:
{
error(21);
break;
}
}
}
getsymdo;
}
else
{
if(sym == number)
{
if(num>amax)
{
error(31);
num = 0;
}
//产生四元式
getsymdo;
}
else
{
if(sym == lparen)
{
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[rparen] = true;
expressiondo(nxtlev, ptx, lev);
if(sym == rparen)
{
getsymdo;
}
else
{
error(22);
}
}
test(fsys, facbegsys, 23);
}
}
}
return 0;
}
int term(bool* fsys,int* ptx,int lev)
{
enum symbol mulop;
bool nxtlev[symnum];
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[times] = true;
nxtlev[slash] = true;
factordo(nxtlev, ptx, lev);
while(sym == times||sym == slash)
{
mulop = sym;
getsymdo;
factor(nxtlev, ptx, lev);
if(mulop == times)
{
//产生乘法四元式
}
else
{
//产生除法四元式
}
}
return 0;
}
int expression_r(bool* fsys,int *ptx,int lev)
{
enum symbol addop;
bool nxtlev[symnum];
if(sym == plus||sym == minus)
{
addop = sym;
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[plus] = true;
nxtlev[minus] = true;
termdo(nxtlev, ptx, lev);
if(addop == minus)
{
//产生四元式
}
}
else
{
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[plus] = true;
nxtlev[minus] = true;
termdo(nxtlev, ptx, lev);
}
while(sym == plus||sym == minus)
{
addop = sym;
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[plus] = true;
nxtlev[minus] = true;
termdo(nxtlev,ptx,lev);
if(addop == plus)
{
//产生四元式
}
else
{
//产生四元式
}
}
return 0;
}
int condition(bool* fsys,int* ptx,int lev)
{
enum symbol relop;
bool nxtlev[symnum];
if(sym == oddsym)
{
getsymdo;
expressiondo(fsys, ptx, lev);
//创建四元式
}
else
{
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[eql] = true;
nxtlev[neq] = true;
nxtlev[lss] = true;
nxtlev[leq] = true;
nxtlev[gtr] = true;
nxtlev[geq] = true;
expressiondo(nxtlev, ptx, lev);
if(sym != eql&&sym !=neq&&sym != lss&&sym != leq&&sym != gtr&&sym !=geq)
{
error(20);
}
else
{
relop = sym;
getsymdo;
expressiondo(fsys, ptx, lev);
switch(relop)
{
case eql:
{
//产生四元式
break;
}
case neq:
{
//产生四元式
break;
}
case lss:
{
//产生四元式
break;
}
case geq:
{
//产生四元式
break;
}
case gtr:
{
//产生四元式
break;
}
case leq:
{
//产生四元式
break;
}
default:
{
//无事发生
break;
}
}
}
}
return 0;
}
int statement(bool* fsys,int* ptx,int lev)
{
int i,cx1,cx2;
bool nxtlev[symnum];
if(sym == ident)
{
i = position(id, *ptx);
if(i == 0)
{
error(11);
}
else
{
if(table[i].kind != variable)
{
error(12);
i = 0;
}
else
{
getsymdo;
if(sym == becomes)
{
getsymdo;
}
else
{
error(13);
}
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
expressiondo(nxtlev, ptx, lev);
if(i != 0)
{
//产生四元式
}
}
}
}
else
{
if(sym == readsym)
{
getsymdo;
if(sym != lparen)
{
error(33);//read无左括号为33
}
else
{
do
{
getsymdo;
if(sym == ident)
{
i = position(id, *ptx);
}
else
{
i = 0;
}
if(i == 0)
{
error(11);
}
else
{
//产生四元式
}
getsymdo;
}while(sym == comma);
}
if(sym != rparen)
{
error(34);
while(!inset(sym, fsys))
{
getsymdo;
}
}
else
{
getsymdo;
}
}
else
{
if(sym == writesym)
{
getsymdo;
if(sym != lparen)
{
error(39);//write无左括号
}
else
{
do
{
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[rparen] = true;
nxtlev[comma] = true;
expressiondo(nxtlev, ptx, lev);
//产生四元式
}while(sym == comma);
if(sym != rparen)
{
error(29);
}
else
{
getsymdo;
}
}
}
else
{
if(sym == callsym)
{
getsymdo;
if(sym != ident)
{
error(14);
}
else
{
i = position(id, *ptx);
if(i == 0)
{
error(11);
}
else
{
if(table[i].kind == procedur)
{
//创建四元式
}
else
{
error(15);
}
}
getsymdo;
}
}
else
{
if(sym == ifsym)
{
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[thensym] = true;
nxtlev[dosym] = true;
conditiondo(nxtlev, ptx, lev);
if(sym == thensym)
{
getsymdo;
}
else
{
error(16);
}
cx1 = cx;
//产生四元式
statement(fsys, ptx, lev);
}
else
{
if(sym == beginsym)
{
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[semicolon] = true;
nxtlev[endsym] = true;
statement(nxtlev, ptx, lev);
while(inset(sym, statbegsys)||sym == semicolon)
{
if(sym == semicolon)
{
getsymdo;
}
else
{
error(10);
}
statement(nxtlev, ptx, lev);
}
if(sym == endsym)
{
getsymdo;
}
else
{
error(17);
}
}
else
{
if(sym == whilesym)
{
cx1 = cx;
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[dosym] = true;
condition(nxtlev, ptx, lev);
cx2 = cx;
if(sym == dosym)
{
getsymdo;
}
else
{
error(18);
}
statement(fsys, ptx, lev);
//产生四元式
}
else
{
memset(nxtlev, 0, sizeof(bool)*symnum);
testdo(fsys, nxtlev, 19);
}
}
}
}
}
}
}
return 0;
}
int block(int lev,int tx,bool* fsys)
{
int i,dx,tx0,cx0;
bool nxtlev[symnum];
dx = 3;
tx0 = tx;
table[tx].adr = cx;
//产生四元式
if(lev>levmax)
error(27);
do
{
if(sym == constsym)
{
getsymdo;
do
{
constdeclarationdo(&tx, lev, &dx);
while(sym == comma)
{
getsymdo;
constdeclarationdo(&tx, lev, &dx);
}
if(sym == semicolon)
{
getsymdo;
}
else
{
error(5);
}
}while(sym == ident);
}
if(sym == varsym)
{
getsymdo;
do
{
vardeclarationdo(&tx, lev, &dx);
while(sym == comma)
{
getsymdo;
vardeclarationdo(&tx, lev, &dx);
}
if(sym == semicolon)
{
getsymdo;
}
else
{
error(5);
}
}while(sym == ident);
}
while(sym == procsym)
{
getsymdo;
if(sym == ident)
{
enter(procedur, &tx, lev, &dx);
getsymdo;
}
else
{
error(4);
}
if(sym == semicolon)
{
getsymdo;
}
else
{
error(5);
}
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[semicolon] = true;
if(block(lev+1, tx, nxtlev) == -1)
{
return -1;
}
if(sym == semicolon)
{
getsymdo;
memcpy(nxtlev, statbegsys, sizeof(bool)*symnum);
nxtlev[ident] = true;
nxtlev[procsym] = true;
testdo(nxtlev, fsys, 6);
}
else
{
error(5);
}
}
memcpy(nxtlev, statbegsys, sizeof(bool)*symnum);
nxtlev[ident] = true;
nxtlev[period] = true;
test(nxtlev, declbegsys, 7);
}while(inset(sym, declbegsys));
table[tx0].adr = cx;
table[tx0].size = dx;
cx0 = cx;
//产生四元式
if(tx0+1>tx)
{
outfile<<"NULL"<<std::endl;
}
for(i = tx0+1;i<=tx;i++)
{
switch(table[i].kind)
{
case constant:
{
outfile<<i<<" const "<<table[i].name<<":";
outfile<<"val="<<table[i].val<<std::endl;
break;
}
case variable:
{
outfile<<i<<" var "<<table[i].name<<":";
outfile<<"lev="<<table[i].level<<" addr="<<table[i].adr<<std::endl;
break;
}
case procedur:
{
outfile<<i<<" proc "<<table[i].name<<":";
outfile<<"lev="<<table[i].level<<" addr="<<table[i].adr<<" size="<<table[i].size<<std::endl;
break;
}
}
outfile<<std::endl;
}
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[semicolon] = true;
nxtlev[endsym] = true;
statementdo(nxtlev, &tx, lev);
//产生四元式
memset(nxtlev, 0, sizeof(bool)*symnum);
testdo(fsys, nxtlev, 8);
//列举代码
return 0;
}
语法分析的语法树没有实现(有一说一,这种图形不用特殊的库是输出不出来的吧)