您的当前位置:首页正文

编译原理课程实验

2024-11-13 来源:个人技术集锦

写在开头:

编译真的是一个很难的东西,课上完,题是会写了,代码是一点写不来,我这代码还是在先人的代码的基础上改编的,真是绷不住了。然后编译这个过程相对于我们用户来说也是很透明的,以至于不管你写了多少代码,你基本还是不知道它是怎么将你的代码转换成正确,简化过的汇编语言。但没有这玩意我们就用不了高级语言,所以还是要向研究编译过程的前人致以崇高的敬意。

声明:本人c++入门水平,佬们没必要浪费时间看这坨代码。

如果有任何违规的地方,请第一时间联系我,我会立即删除本文。

实验一:词法分析

1.输入输出格式

输入:PL/0源程序所在的文件。 输出:关键字、专用符号以及其它标记。

2.实现过程

本实验实现的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

3.主体结构的说明

此处用来说明代码中的主要函数:1.Scan函数:这是对程序进行词法分析的主要函数,用来确定接下来的词是否为:关键词or数字常量or专用符号or什么都不是。2.main函数:将文件中的内容提取出来,对文件中的每个词进行词法分析,每分析完一个词就按照该词的种类进行输出。

4.实现原理

程序中先判断这个句语句中每个单元为关键字、常数、运算符、界符,对与不同的单词符号给出不同编码形式的编码,用以区分之。

5.实现过程

1.流程图:

2.核心代码:

文件内的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;
}

6.有待提升的地方

关键词实际上是按照字典序排的,可以用折半查找来提高查找效率。

实验语法分析

1.输入输出格式

输入:PL/0源程序所在的文件。 输出:将错误信息输出到语法错误文件中,输出语法树。

2.实现过程

对于已给PL/0语言文法,利用递归子程序法,编制语法分析程序。

3.主体结构的说明

主要函数有:

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);分程序(一个具体的非终结符)的处理

4.实现原理

PL/0语法如下:

5.实现过程 

1.流程图:

非终结符太多了,自顶下降分析的可能性就更多了,而且还有层的嵌套,所以摆了。

2.核心代码:

文件内的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;
}

6.有待提升的地方

语法分析的语法树没有实现(有一说一,这种图形不用特殊的库是输出不出来的吧)

显示全文