乐观的阿珍 2016-12-11 10:54 采纳率: 0%
浏览 1513

PL0编译器调用procedure无限循环

如题,自己参照网上的例子做了一个C语言的PL0编译器,能跑通,但是遇到调用procedure的时候,就会一直循环无限调用,查错查了好久,还是没有找到,希望有大神能为我解答一下!谢谢~
代码如下,有点长。。
#include
#include
#include
#include
using namespace std;

#define MAXERR 20//最多错误次数
#define AL 12//标识符最大长度
#define NORW 14//保留字个数
#define NUMMAX 14//最大数字位数
#define TXMAX 100//符号表容量
#define AMAX 2048//地址上界
#define CXMAX 200//最多的虚拟机代码数
#define stacksize 500//运行时数据栈元素最多为500个
#define symnum 32
#define fctnum 8

enum symbol //符号
{
nul, ident, number, pluss, minuss,
times, slash, oddsym, eql, neq,
lss, leq, gtr, geq, lparen,
rparen, comma, semicolon, period, becomes,
beginsym, endsym, ifsym, thensym, elsesym,
whilesym, writesym, readsym, dosym, callsym,
constsym, varsym, procsym,
};

enum object //符号表类型
{
constant, variable, procedure,
};

enum fct //虚拟机指令
{
LIT, OPR, LOD, STO, CAL, INT, JMP, JPC,
};

struct instruction //虚拟机代码结构
{
enum fct f;//虚拟机指令
int l;//引用层与声明层层次差
int a;//根据f的不同而不同
};

FILE * fin;
FILE * fout;
FILE * fv;//虚拟机代码
FILE * fo;//源代码
FILE * fr;//代码运行结果
FILE * ft;//符号表

char fname[AL];
char ch;//存放当前字符
int cc, ll;//getch计数器,cc表示ch的位
int cx;//虚拟机代码指针
int num;//当前数字
int err;//错误计数器
char a[AL+1];//临时符号
char id[AL+1];//当前ident
char line[81];//行缓冲区
char word[NORW][AL];//保留字
enum symbol sym;//当前符号
enum symbol wsym[NORW];//保留字对应符号值
enum symbol ssym[256];//单字符符号值
struct instruction code[CXMAX];//存放虚拟机代码的数组
char mnemonic[fctnum][5];//虚拟机代码指令名称
bool declbegsys[symnum];//表示声明开始的符号集合
bool statbegsys[symnum];//表示语句开始的符号集合
bool facbegsys[symnum];//表示因子开始的符号集合

struct tablestruct //符号表结构
{
char name[AL];//名字
enum object kind;//类型
int val;//数值
int level;//所处层
int addr;//地址
int size;//需要分配的数据区空间
};

struct tablestruct table[TXMAX];//符号表

void init();
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);
void error(int n);
void getsym();
void getch();
void gen(enum fct x, int y, int z);
void test(bool* s1, bool* s2, int n);
void block(int lev, int tx, bool* fsys);
void enter(enum object k, int* ptx, int lev, int* pdx);
int position(char* idt, int tx);
void constdeclaration(int* ptx, int lev, int* pdx);
void vardeclaration(int* ptx, int lev, int* pdx);
void listcode(int cx0);
void statement(bool* fsys, int* ptx, int lev);
void expression(bool* fsys, int* ptx, int lev);
void term(bool* fsys, int* ptx, int lev);
void factor(bool* fsys, int* ptx, int lev);
void condition(bool* fsys, int* ptx, int lev);
void interpret();
int base(int l, int* s, int b);

void init()
{
int i;
for(i=0; i<255; i++) //单字符符号
{
ssym[i] = nul;
}
ssym['+'] = pluss;
ssym['-'] = minuss;
ssym['*'] = times;
ssym['/'] = slash;
ssym['('] = lparen;
ssym[')'] = rparen;
ssym['='] = eql;
ssym[','] = comma;
ssym['.'] = period;
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]), "else");
strcpy(&(word[5][0]), "end");
strcpy(&(word[6][0]), "if");
strcpy(&(word[7][0]), "odd");
strcpy(&(word[8][0]), "procedure");
strcpy(&(word[9][0]), "read");
strcpy(&(word[10][0]), "then");
strcpy(&(word[11][0]), "var");
strcpy(&(word[12][0]), "while");
strcpy(&(word[13][0]), "write");

//保留字符号
wsym[0] = beginsym;
wsym[1] = callsym;
wsym[2] = constsym;
wsym[3] = dosym;
wsym[4] = elsesym;
wsym[5] = endsym;
wsym[6] = ifsym;
wsym[7] = oddsym;
wsym[8] = procsym;
wsym[9] = readsym;
wsym[10] = thensym;
wsym[11] = varsym;
wsym[12] = whilesym;
wsym[13] = writesym;

//指令名称
strcpy(&(mnemonic[LIT][0]), "LIT");
strcpy(&(mnemonic[OPR][0]), "OPR");
strcpy(&(mnemonic[LOD][0]), "LOD");
strcpy(&(mnemonic[STO][0]), "STO");
strcpy(&(mnemonic[CAL][0]), "CAL");
strcpy(&(mnemonic[INT][0]), "INT");
strcpy(&(mnemonic[JMP][0]), "JMP");
strcpy(&(mnemonic[JPC][0]), "JPC");

//符号集
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 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;
}

//error处理:输出报错位置以及错误编号
void error(int n)
{
cc--;//出错时当前符号已经读完,cc-1
//printf("错误编号:%d\n",n);
cout<<"错误编号:"< fprintf(fo, "错误编号:%d\n", n);
err++;
if(err > MAXERR)
{
exit(1);
}
}

//读取字符
void getch()
{
if(cc == ll)//判断缓冲区中是否有字符,若无字符,则读入下一行字符到缓冲区中
{
if(feof(fin))
{
cout<<"程序不完整"<<endl;
exit(1);
}
ll = 0; cc = 0;
printf("%d ", cx);
fprintf(fo, "%d ", cx);
ch = ' ';
while(ch != 10)//读取一行字符到缓冲区
{
//fscanf(fin,"%c",&ch)
if(EOF == fscanf(fin, "%c", &ch))
{
line[ll] = 0;
break;
}
printf("%c", ch);
//cout<<ch;
fprintf(fo, "%c", ch);
line[ll] = ch;
ll++;
}
}
ch = line[cc];
cc++;
}

//词法分析
void getsym()
{
int i, j, k;
while(ch==' ' || ch==10 || ch==9)//过滤掉空格、换行符
{
getch();
}
if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
{
i = 0;
do{
if(i < AL)
{
a[i] = ch;
i++;
}
getch();
} while((ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || (ch>='0' && ch<='9'));
a[i] = 0;
strcpy(id, a);
/*
for(j = 0; j < 13; j++)
{
if(strcmp(id, word[i]) == 0)
break;
}
*/
//改为用二分法查找保留字
j = 0;
k = NORW - 1;
do {
i=(j + k) / 2;
if(strcmp(id, word[i])<=0)
{
k = i - 1;
}
if(strcmp(id, word[i])>=0)
{
j = i + 1;
}

    } while(j <= k);
    if(j - 1 > k)//单词为保留字
    {
        sym = wsym[i];
    }
    else//单词为标识符
    {
        sym = ident;
    }
}
else
{
    if(ch>='0' && ch<='9')//单词为数字
    {
        i = 0;
        num = 0;
        sym = number;
        do {
            num = 10 * num + ch - '0';
            i++;
            getch();
        } while(ch>='0' && ch<='9'); //获取数字的值
        i--;
        if(i > NUMMAX)//数字位数太大
        {
            error(30);
        }
    }
    else
    {
        if(ch == ':')//检测赋值符号
        {
            getch();
            if(ch == '=')
            {
                sym = becomes;
                getch();
            }
            else
            {
                sym = nul;//不能识别的符号
            }
        }
        else
        {
            if(ch == '<')//检测小于或小于等于符号以及不等号
            {
                getch();
                if(ch == '=')
                {
                    sym = leq;
                    getch();
                }
                else if(ch=='>')//检测不等号
                {
                    sym = neq;//构成不等号<>
                    getch();
                }
                else
                {
                    sym = lss;
                }
            }
            else
            {
                if(ch == '>')//检测大于或大于等于符号
                {
                    getch();
                    if(ch == '=')
                    {
                        sym = geq;
                        getch();
                    }
                    else
                    {
                        sym = gtr;
                    }
                }
                else
                {
                    sym = ssym[ch];//当符号不满足上述条件时,全部按照单字符号处理
                    if(sym != period)
                    {
                        getch();
                    }
                }
            }
        }
    }
}

}

//生成P-code即虚拟机代码
void gen(enum fct x, int y, int z )
{
if (cx >= CXMAX)
{
cout<<"虚拟机代码长度过长!"< exit(1);
}
if ( z >= AMAX)
{
cout<<"地址偏移越界!"<<endl;
exit(1);
}

code[cx].f = x;
code[cx].l = y;
code[cx].a = z;
cx++;

}

//测速当前符号单词是否合法
void test(bool* s1, bool* s2, int n)
{
if(!inset(sym, s1))
{
error(n);//当检测不通过时,不停获取符号,直到它属于S1或S2
while((!inset(sym, s1)) && (!inset(sym, s2)))
{
getsym();
}
}
}

//分程序分析处理
void block(int lev, int tx, bool* fsys)
{
int i;
int dx;//名字分配到的相对地址
int tx0;//保留初始tx
int cx0;//保留初始cx
bool nxtlev[symnum];
dx = 3;//分别存放SL,DL和返回地址
tx0 = tx;//本层标识符初始位置
table[tx].addr = cx;//当前层代码开始位置
gen(JMP, 0, 0);//生成跳转指令
do{
if(sym == constsym)//常量声明符号,处理常量声明
{
getsym();

        do{
            constdeclaration(&tx, lev, &dx);
            while(sym == comma)//逗号,继续读取
            {
                getsym();
                constdeclaration(&tx, lev, &dx);
            }
            if(sym == semicolon)//分号,结束读取
            {
                getsym();
            }
            else
            {
                error(5);//漏掉逗号或者分号
            }
        }while(sym == ident);
    }
    if(sym == varsym)//变量声名符号,处理变量声名
    {
        getsym();

        do{
            vardeclaration(&tx, lev, &dx);
            while(sym == comma)//逗号,继续读取
            {
                getsym();
                vardeclaration(&tx, lev, &dx);
            }
            if(sym == semicolon)//分号,结束读取
            {
                getsym();
            }
            else
            {
                error(5);//漏掉逗号或者分号
            }
        }while(sym == ident);
    }

    while(sym == procsym)//过程声名符号,处理过程声名
    {
        getsym();

        if(sym == ident)
        {
            enter(procedure, &tx, lev, &dx);//过程名字
            getsym();
        }
        else
        {
            error(4);//procedure后应为标识符
        }
        if(sym == semicolon)//分号,结束读取
        {
            getsym();
        }
        else
        {
            error(5);//漏掉分号
        }
        memcpy(nxtlev, fsys, sizeof(bool)* symnum);
        nxtlev[semicolon]=true;
        block(lev+1, tx, nxtlev);//递归

        if(sym == semicolon)
        {
            getsym();
            memcpy(nxtlev, statbegsys, sizeof(bool)* symnum);
            nxtlev[ident]=true;
            nxtlev[procsym]=true;
            test(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));//直到没有声明符号
code[table[tx0].addr].a = cx;//开始生成当前过程代码
table[tx0].addr = cx;//当前过程代码地址
table[tx0].size = dx;//dx为当前过程数据的size

cx0 = cx;
gen(INT, 0, dx);//生成分配内存代码
//输出符号表
for(i = 1; i <= tx; i++)
{
    switch(table[i].kind)
    {
        case constant:
            printf("%d const %s", i, table[i].name);
            printf("val=%d\n", table[i].val);
            fprintf(ft, "%d const %s", i, table[i].name);
            fprintf(ft, "val=%d\n", table[i].val);
            break;
        case variable:
            printf("%d var %s", i, table[i].name);
            printf("lev=%d addr=%d\n", table[i].level, table[i].addr);
            fprintf(ft, "%d var %s", i, table[i].name);
            fprintf(ft, "lev=%d addr=%d\n", table[i].level, table[i].addr);
            break;
        case procedure:
            printf("%d proc %s", i, table[i].name);
            printf("lev=%d addr=%d size=%d\n", table[i].level,table[i].addr, table[i].size);
            fprintf(ft, "%d proc %s", i, table[i].name);
            fprintf(ft, "lev=%d adr=%d size=%d \n", table[i].level,table[i].addr, table[i].size);
            break;
    }
}
printf("\n");
fprintf(ft, "\n");
//语句后跟分号或end
memcpy(nxtlev, fsys, sizeof(bool)* symnum);//每个后跟符号集和都包含上层后跟符号集和,以便补救
nxtlev[semicolon] = true;
nxtlev[endsym] = true;
statement(nxtlev, &tx, lev);
gen(OPR, 0, 0); //每个过程出口都要使用的释放数据段命令
memset(nxtlev, 0, sizeof(bool)* symnum); //分程序没有补救集合
test(fsys, nxtlev, 8);//检测后跟符号正确性
listcode(cx0);//输出代码

}

//登录符号表
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)].addr = (*pdx);
(*pdx)++;
break;
case procedure://过程
table[(*ptx)].level = lev;
break;
}
}

//查找标识符在符号表的位置
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;
}

//常量定义处理
void constdeclaration(int* ptx, int lev,int* pdx)
{
if(sym == ident)
{
getsym();
if((sym == eql) || (sym == becomes))
{
if(sym == becomes)
{
error(1);//应该是=而不是:=
}
getsym();
if(sym == number)
{
enter(constant, ptx, lev, pdx);//填写符号表
getsym();
}
else
{
error(2);//=后应为数
}
}
else
{
error(3);//标识符后应为=
}
}
else
{
error(4);//const后应为标识符
}
}

//变量声明处理
void vardeclaration(int* ptx ,int lev, int* pdx)
{
if(sym == ident)
{
enter(variable, ptx, lev, pdx);//填写符号表
getsym();
}
else
{
error(4);//var后应为标识符
}
}

//列出P-code指令清单
void listcode(int cx0)
{
int i;
printf("\n");
for(i=cx0; i<cx; i++)
{
printf("%d %s %d %d\n", i, mnemonic[code[i].f], code[i].l,code[i].a);
fprintf(fv,"%d %s %d %d\n", i, mnemonic[code[i].f], code[i].l, code[i].a);
}
}

//语句部分分析处理
void 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
{
getsym();
if(sym == becomes)
{
getsym();
memcpy(nxtlev, fsys, sizeof(bool)
symnum);
expression(nxtlev, ptx, lev);
if(i != 0)
{
gen(STO, lev-table[i].level, table[i].addr);
}
}
else
{
error(13);//应为赋值运算符:=
}
}
}
}
else
{
if(sym == readsym)//按照read语句处理
{
getsym();
if(sym != lparen)
{
error(40);//应为左括号
}
else
{
do{
getsym();
if(sym == ident)
{
i = position(id, ptx);//查找要读的变量
}
else
{
i = 0;
}
if(i == 0)
{
error(35);//read括号中标识符未声明
}
else
{
gen(OPR, 0, 15);//生成输入指令
gen(STO, lev-table[i]. level, table[i].addr);//将栈顶内容存到变量中
}
getsym();
}while(sym == comma);//读多个变量
}
if(sym!=rparen)
{
error(33);//应为右括号
while(!inset(sym, fsys))//出错补救,直到收到上层函数的后跟符号
{
getsym();
}
}
else
{
getsym();
}
}
else
{
if(sym==writesym)//按照write语句处理
{
getsym();
if(sym != lparen)
{
error(40);//应为左括号
}
else
{
do{
getsym();
memcpy(nxtlev, fsys, sizeof(bool)
symnum);
nxtlev[rparen] = true;
nxtlev[comma] = true;//write后符号为)或,
expression(nxtlev, ptx, lev);//调用表达式处理
gen(OPR, 0, 13);//生成输出指令,输出栈顶的值
gen(OPR, 0, 14);//换行
}while(sym == comma);//输出多个
if(sym != rparen)
{
error(33);//应为右括号
}
else
{
getsym();
}
}
}
else
{
if(sym == callsym)//按照call语句处理
{
getsym();
if(sym != ident)
{
error(14);//call后应为标识符
}
else
{
i=position(id, ptx);
if(i == 0)
{
error(11); //过程未声明
}
else
{
if(table[i].kind == procedure)
{
gen(CAL, lev-table[i].level, table[i].addr);//生成call指令
}
else
{
error(15);//不可调用常量或变量
}
}
getsym();
}
}
else
{
if(sym == ifsym)//按照if语句处理
{
getsym();
memcpy(nxtlev, fsys, sizeof(bool)
symnum);
nxtlev[thensym] = true;
nxtlev[dosym] = true;//if后符号为then或do
condition(nxtlev, ptx, lev);//调用条件处理
if(sym == thensym)
{
getsym();
}
else
{
error(16);//应为then
}
cx1 = cx;//当前指令地址
gen(JPC, 0, 0);//生成条件跳转指令
statement(fsys, ptx, lev);//处理then下面的语句

                    if(sym==elsesym)//处理else语句
                    {
                        getsym();
                        cx2 = cx;
                        code[cx1].a=cx+1;//cx+1为then语句执行后的else语句的位置
                        gen(JMP, 0, 0);
                        statement(fsys, ptx, lev);
                        code[cx2].a = cx;//cx为else后语句执行完的位置
                    }
                    else
                    {
                        code[cx1].a = cx;//cx为then后面语句执行                                                  完的位置,它正是前面未定的跳转地址*/
                    }
                }
                else
                {
                    if(sym==beginsym)//按照复合语句处理
                    {
                        getsym();
                        memcpy(nxtlev, fsys, sizeof(bool)* symnum);
                        nxtlev[semicolon]=true;
                        nxtlev[endsym]=true;//begin后符号为:或end
                        statement(nxtlev, ptx, lev);//处理begin和end之间的语句
                        while((inset(sym, statbegsys)) || (sym == semicolon))
                        {
                            if(sym = semicolon)
                            {
                                getsym();
                            }
                            else
                            {
                                error(10);//语句之间没有分号
                            }
                            statement(nxtlev, ptx, lev);
                        }//循环处理
                        if(sym == endsym)
                        {
                            getsym();
                        }
                        else
                        {
                            error(17);//应为分号或end
                        }
                    }
                    else
                    {
                        if(sym == whilesym)//按照while语句处理
                        {
                            cx1 = cx;//判断条件操作位置
                            getsym();
                            memcpy(nxtlev, fsys, sizeof(bool)* symnum);
                            nxtlev[dosym]=true;//while后符号为do
                            condition(nxtlev, ptx, lev);//调用条件处理
                            cx2 = cx;//循环体的结束的下一个位置
                            gen(JPC, 0, 0);//生成条件跳转
                            if(sym == dosym)
                            {
                                getsym();
                            }
                            else
                            {
                                error(18);//应为do
                            }
                            statement(fsys, ptx, lev);
                            gen(JMP, 0, cx1);//重新判断条件
                            code[cx2].a = cx;
                        }
                    }
                }
            }
        }
    }
}
memset(nxtlev, 0, sizeof(bool)* symnum);//语句结束无补救集合
test(fsys, nxtlev, 19);//检测语句结束的正确性

}

//表达式分析处理
void expression(bool* fsys, int* ptx, int lev)
{
enum symbol sign;//正负号
bool nxtlev[symnum];

if((sym == pluss) || (sym == minuss))//开头的正负号
{
    sign = sym;
    getsym();
    memcpy(nxtlev, fsys, sizeof(bool)* symnum);
    nxtlev[pluss] = true;
    nxtlev[minuss] = true;
    term(nxtlev, ptx, lev);//对项进行处理
    if(sign == minuss)
    {
        gen(OPR, 0, 1);//如果开头为负号,生成取负指令
    }
}
else
{
    memcpy(nxtlev, fsys, sizeof(bool)* symnum);
    nxtlev[pluss] = true;
    nxtlev[minuss] = true;
    term(nxtlev, ptx, lev);//对项进行处理
}
while((sym == pluss) || (sym == minuss))
{
    sign = sym;
    getsym();
    memcpy(nxtlev, fsys, sizeof(bool)* symnum);
    nxtlev[pluss] = true;
    nxtlev[minuss] = true;
    term(nxtlev, ptx, lev);//对项进行处理
    if(sign == pluss)
    {
        gen(OPR, 0, 2);//加法
    }
    else
    {
        gen(OPR, 0, 3);//减法
    }
}

}

//项分析处理
void term(bool*fsys, int ptx, int lev)
{
enum symbol sign;//乘除法符号
bool nxtlev[symnum];
memcpy(nxtlev, fsys, sizeof(bool)
symnum);
nxtlev[times] = true;
nxtlev[slash] = true;
factor(nxtlev, ptx, lev);//对因子进行处理
while((sym == times) || (sym == slash))
{
sign = sym;
getsym();
factor(nxtlev, ptx, lev);
if(sign == times)
{
gen(OPR, 0, 4);//乘法
}
else
{
gen(OPR, 0, 5);//除法
}
}
}

//因子分析处理
void factor(bool* fsys, int* ptx, int lev)
{
int i;
bool nxtlev[symnum];
test(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:
gen(LIT, 0, table[i].val);//常量入栈
break;
case variable:
gen(LOD, lev-table[i].level, table[i].addr);//变量入栈
break;
case procedure:
error(21);//表达式内不能有过程标识符
break;
}
}
getsym();
}
else
{
if(sym == number) //因子为数字的时候
{
if(num > AMAX)
{
error(31);//过界报错
num = 0;
}
gen(LIT, 0, num);
getsym();
}
else
{
if(sym == lparen)//因子为表达式的时候
{
getsym();
memcpy(nxtlev, fsys, sizeof(bool)
symnum);
nxtlev[rparen] = true;
expression(nxtlev, ptx, lev);
if(sym == rparen)
{
getsym();
}
else
{
error(22);//没有右括号
}
}
//test(fsys, facbegsys, 23);//一个因子处理完毕,遇到的单词应在fsys集合中 ,如果不是,报错并找到下一个因子的开始,使语法分析继续运行
}
}
memset(nxtlev, 0, sizeof(bool) * symnum);
nxtlev[lparen] = true;
test(fsys, facbegsys, 23);//一个因子处理完毕,遇到的单词应在fsys集合中 ,如果不是,报错并找到下一个因子的开始,使语法分析继续运行
}
}

//条件分析处理
void condition(bool* fsys, int* ptx, int lev)
{
enum symbol sign;
bool nxtlev[symnum];
if(sym == oddsym)
{
getsym();
expression(fsys, ptx, lev);
gen(OPR, 0, 6);
}
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;
expression(nxtlev, ptx, lev);
if((sym!=eql)&&(sym!=neq)&&(sym!=lss)&&(sym!=leq)&&(sym!=gtr)&&(sym!=geq))
{
error(20);//应为关系运算符
}
else
{
sign = sym;
getsym();
expression(fsys, ptx, lev);
switch(sign)
{
case eql:
gen(OPR, 0, 7);
break;
case neq:
gen(OPR, 0, 8);
break;
case lss:
gen(OPR, 0, 9);
break;
case gtr:
gen(OPR, 0, 10);
break;
case leq:
gen(OPR, 0, 11);
break;
case geq:
gen(OPR, 0, 12);
break;
}
}
}
}

//P-code解释执行程序
void interpret()
{
int p = 0;//指令指针
int b = 1;//指令基址
int t = 0;//栈顶指针
struct instruction i;//存放当前指令
int s[stacksize];//栈
cout<<"执行PL0:"< fprintf(fr, "执行PL0:\n");
s[0] = 0;
s[1] = 0; s[2] = 0; s[3] = 0;
do{
i = code[p];//读当前指令
p++;
switch(i.f)
{
case LIT://将a的值取到栈顶
t++;
s[t]=i.a;
break;
case OPR://数字逻辑运算
switch(i.a)
{
case 0://函数调用后返回
t = b - 1;
p = s[t+3];
b = s[t+2];
break;
case 1://取反
s[t] = -s[t];
break;
case 2://栈顶两个元素相加
t--;
s[t] = s[t] + s[t+1];
break;
case 3://栈顶两个元素相减
t--;
s[t] = s[t] - s[t+1];
break;
case 4://栈顶两个元素相乘
t--;
s[t] = s[t] * s[t+1];
break;
case 5://栈顶两个元素相除
t--;
s[t] = s[t] / s[t+1];
break;
case 6://栈顶元素奇偶判断
s[t] = s[t] % 2;
break;
case 7://栈顶两个元素是否相等
t--;
s[t] = (s[t] == s[t+1]);
break;
case 8://栈顶两个元素是否不等
t--;
s[t] = (s[t] != s[t+1]);
break;
case 9://小于
t--;
s[t] = (s[t] break;
case 10://大于
t--;
s[t] = (s[t] > s[t+1]);
break;
case 11://小于等于
t--;
s[t] = (s[t] <= s[t+1]);
break;
case 12://大于等于
t--;
s[t] = (s[t] >= s[t+1]);
break;
case 13://输出栈顶值
printf("%d", s[t]);
fprintf(fr, "%d", s[t]);
t--;
break;
case 14://输出换行符
printf("\n");
fprintf(fr, "\n");
break;
case 15://读入
t++;
printf("输入:");
fprintf(fr, "输入:");
scanf("%d", &(s[t]));
fprintf(fr, "%d\n", s[t]);
break;
}
break;
case LOD://取相对当前过程的数据基地址为a的内存的值到栈顶
t++;
s[t] = s[base(i.l, s, b) + i.a];
break;
case STO://栈顶的值存到相对当前过程的数据基地址为a的内存
s[base(i.l, s, b) + i.a] = s[t];
t--;
break;
case CAL://调用子程序
s[t+1] = base(i.l, s,b);
s[t+2] = b;
s[t+3] = p;
b = t + 1;
p = i.a;
break;
case INT://分配内存
t += i.a;
break;
case JMP://直接跳转
p=i.a;
break;
case JPC://条件跳转
if(s[t] == 0)
{
p = i.a;
}
t--;
break;
}
}while(p != 0);
printf("PL0结束\n");
fprintf(fr, "PL0结束\n");
}
//通过静态链求出数据区基地址
int base(int l,int* s, int b)
{
int b1;
b1 = b;
while(l > 0)
{
b1 = s[b1];
l--;
}
return b1;
}

int main()
{
bool nxtlev[symnum];
cout<<"*****PL0编译器*****"<<endl;
cout<<"输出文件中,fv为虚拟机代码,fo为源代码,fr为运行结果,ft为符号表"<<endl;
cout<<"请输入pl0文件:"<<endl;
scanf("%s", fname);
fin = fopen(fname, "r");
if(fin == NULL)
{
cout<<"无法打开文件!" <<endl;
exit(1);
}
if(fgetc(fin) == EOF)
{
cout<<"文件为空!" <<endl;
exit(1);
}
rewind(fin);

fo = fopen("fo.txt", "w");
init();
err = 0;
cc = ll = cx = 0;
ch=' ';

getsym();
fv = fopen("fv.txt", "w");
ft = fopen("ft.txt", "w");
addset(nxtlev, declbegsys, statbegsys, symnum);
nxtlev[period]=true;

block(0, 0, nxtlev);//调用编译程序

fclose(fv);
fclose(fo);
fclose(ft);
fclose(fin);
printf("\n");

if(sym != period)
{
    error(9);//应为句号
}
if(err == 0)
{
    cout<<"*****************************"<<endl;
    fr = fopen("fr.txt", "w");
    interpret();
    fclose(fr);
}
else
{
    printf("程序出错!");
}
fclose(fin);
printf("\n");
getchar();

}

  • 写回答

1条回答 默认 最新

  • dabocaiqq 2016-12-17 06:40
    关注
    评论

报告相同问题?

悬赏问题

  • ¥50 易语言把MYSQL数据库中的数据添加至组合框
  • ¥20 求数据集和代码#有偿答复
  • ¥15 关于下拉菜单选项关联的问题
  • ¥20 java-OJ-健康体检
  • ¥15 rs485的上拉下拉,不会对a-b<-200mv有影响吗,就是接受时,对判断逻辑0有影响吗
  • ¥15 使用phpstudy在云服务器上搭建个人网站
  • ¥15 应该如何判断含间隙的曲柄摇杆机构,轴与轴承是否发生了碰撞?
  • ¥15 vue3+express部署到nginx
  • ¥20 搭建pt1000三线制高精度测温电路
  • ¥15 使用Jdk8自带的算法,和Jdk11自带的加密结果会一样吗,不一样的话有什么解决方案,Jdk不能升级的情况