?? pl0.cpp
字號:
if(q==SYM_TO)//to默認(rèn)執(zhí)行11號操作
gen(OPR,0,11);
else
gen(OPR,0,13);
cx2=cx;//記下當(dāng)前代碼分配位置
gen(JPC,0,0);//生成條件跳轉(zhuǎn)指令,跳轉(zhuǎn)位置暫時(shí)填0,分析完語句后再填寫
code[cx1].a=cx;//把剛才填0的跳轉(zhuǎn)位置改成當(dāng)前位置
getsym();
statement(fsys);
gen(JMP,0,cx1+1);//循環(huán)跳轉(zhuǎn)到cx1+1位置,即再次進(jìn)行邏輯判斷
code[cx2].a=cx;//把剛才填0的跳轉(zhuǎn)位置改成當(dāng)前位置
}
}
else
if(sym ==SYM_REPEAT) //重復(fù)語句
{
cx1 = cx; //記下當(dāng)前代碼分配位置,這是repeat語句的開始位置
getsym();
set1 = createset(SYM_SEMICOLON, SYM_UNTIL, SYM_NULL);
set = uniteset(set1, fsys);
statement(set);
while (sym == SYM_SEMICOLON || inset(sym, statbegsys))
{
if (sym == SYM_SEMICOLON) //判別是否為‘;’
getsym();
else
error(10);
statement(set);
}
destroyset(set1);
destroyset(set);
if (sym == SYM_UNTIL)
{
getsym();
condition(fsys);
gen(JPC, 0, cx1);//生成條件跳轉(zhuǎn)指令,跳轉(zhuǎn)位置填cx1
}
else
error(29);
}
else
test(fsys, phi, 19); //至此一個(gè)語句處理完成,一定會遇到fsys集中的符號,如果沒有遇到,就報(bào)出19號錯(cuò)
}
/*************************************************************************/
void expression(symset fsys) //表達(dá)式分析處理
{
int addop;
symset set;
set = uniteset(fsys, createset(SYM_PLUS, SYM_MINUS, SYM_NULL));
if (sym == SYM_PLUS || sym == SYM_MINUS)//一個(gè)表達(dá)式可能會由加號或減號開始,表示正負(fù)號
{
addop = sym;//把當(dāng)前的正號或負(fù)號保存起來,以便下面生成相應(yīng)代碼
getsym();// 獲取一個(gè)token
term(set); //正負(fù)號后面應(yīng)該是一個(gè)項(xiàng),調(diào)term子程序分析
if (addop == SYM_MINUS) //如果保存下來的符號是負(fù)號
gen(OPR, 0, 1); //生成一條1號操作指令:取反運(yùn)算
}
else //如果不是由正負(fù)號開頭,就應(yīng)是一個(gè)項(xiàng)開頭
term(set);//調(diào)用term子程序分析項(xiàng)
while (sym == SYM_PLUS || sym == SYM_MINUS) //項(xiàng)后應(yīng)是加運(yùn)算或減運(yùn)算
{
addop = sym; //把運(yùn)算符保存下來
getsym(); //獲取下一個(gè)token,加減運(yùn)算符后應(yīng)跟的是一個(gè)項(xiàng)
term(set); //調(diào)term子程序分析項(xiàng)
if (addop == SYM_PLUS) //如果項(xiàng)與項(xiàng)之間的運(yùn)算符是加號
gen(OPR, 0, 2); //生成2號操作指令:加法
else //否則是減法
gen(OPR, 0, 3); //生成3號操作指令:減法
}
destroyset(set);
}
/*************************************************************************/
void term(symset fsys) //項(xiàng)分析處理,fsys如果出錯(cuò)可用來恢復(fù)語法分析的符號集合
{
int mulop;
symset set;
set = uniteset(fsys, createset(SYM_TIMES, SYM_SLASH, SYM_NULL));
factor(set); //每一個(gè)項(xiàng)都應(yīng)該由因子開始,因此調(diào)用factor子程序分析因子
while (sym == SYM_TIMES || sym == SYM_SLASH) //一個(gè)因子后應(yīng)當(dāng)遇到乘號或除號
{
mulop = sym; //保存當(dāng)前運(yùn)算符
getsym(); //獲取下一個(gè)token
factor(set); //運(yùn)算符后應(yīng)是一個(gè)因子,故調(diào)factor子程序分析因子
if (mulop == SYM_TIMES) //如果剛才遇到乘號
gen(OPR, 0, 4); //生成乘法指令
else
gen(OPR, 0, 5);//不是乘號一定是除號,生成除法指令
}
destroyset(set);
}
/*************************************************************************/
void factor(symset fsys) //因子分析處理,fsys如果出錯(cuò)可用來恢復(fù)語法分析的符號集合
{
void expression();
int i;
symset set;
test(facbegsys, fsys, 24); // 開始因子處理前,先檢查當(dāng)前token是否在facbegsys集合中
//如果不是合法的token,報(bào)出24號錯(cuò)誤
while (inset(sym, facbegsys)) //循環(huán)處理因子
{
if (sym == SYM_IDENTIFIER) //如果遇到的是標(biāo)識符
{//查符號表,找到當(dāng)前標(biāo)識符在符號表中的位置
if ((i = position(id)) == 0) //如果查符號表返回為0,表示沒有找到標(biāo)識符
error(11); // Undeclared identifier.
else
{
switch (table[i].kind) //如果在符號表中找到了當(dāng)前標(biāo)識符的位置,開始生成相應(yīng)代碼
{
mask* mk;
case ID_CONSTANT:
gen(LIT, 0, table[i].value); //如果這個(gè)標(biāo)識符對應(yīng)的是常量,值為val,生成lit指令,把val放到棧頂
break;
case ID_VARIABLE:
mk = (mask*) &table[i];
gen(LOD, level - mk->level, mk->address);//如果標(biāo)識符是變量名,生成lod指令
break;//把位于距離當(dāng)前層level的層的偏移地址為adr的變量放到棧頂
case ID_PROCEDURE:
error(21); //如果在因子處理中遇到的標(biāo)識符是過程名,出錯(cuò)了,報(bào)出21號錯(cuò)
break;
}
}
getsym();//獲取下一token,繼續(xù)循環(huán)處理
}
else
if (sym == SYM_NUMBER) //如果因子處理時(shí)遇到數(shù)字
{
if (num > MAXADDRESS)//如果數(shù)字的大小超過允許最大值amax
{
error(30);
num = 0;//把數(shù)字按0值處理
}
gen(LIT, 0, num); //生成lit指令,把這個(gè)數(shù)值字面常量放到棧頂
getsym(); //獲取下一token
}
else
if (sym == SYM_LPAREN) // 如果遇到的是左括號
{
getsym(); //獲取一個(gè)token
set = uniteset(createset(SYM_RPAREN, SYM_NULL), fsys);
// expression(set); //遞歸調(diào)用expression子程序分析一個(gè)子表達(dá)式
destroyset(set);
if (sym == SYM_RPAREN)//子表達(dá)式分析完后,應(yīng)遇到右括號
getsym(); //如果的確遇到右括號,讀取下一個(gè)token
else
error(22);
}
else
test(fsys, createset(SYM_LPAREN, SYM_NULL), 23); //一個(gè)因子處理完畢,遇到的token應(yīng)在fsys集合中
//如果不是,報(bào)出23號錯(cuò),并找到下一個(gè)因子的開始,使語法分析可以繼續(xù)運(yùn)行下去
}
}
/*************************************************************************/
void condition(symset fsys) //條件分析處理,fsys如果出錯(cuò)可用來恢復(fù)語法分析的符號集合
{
int relop; //用于臨時(shí)記錄token的內(nèi)容
symset set;
if (sym == SYM_ODD) //如果是odd運(yùn)算符
{
getsym(); //獲取下一個(gè)token
expression(fsys); //對odd的表達(dá)式進(jìn)行處理計(jì)算
gen(OPR, 0, 6); //生成6號操作指令:奇偶判斷運(yùn)算
}
else //如果不是odd運(yùn)算符
{
set = uniteset(relset, fsys);
expression(set); //對表達(dá)式左部進(jìn)行處理計(jì)算
destroyset(set);
if (! inset(sym, relset)) // 如果token不是邏輯運(yùn)算符中的一個(gè)
error(20);
else
{
relop = sym; //記錄下當(dāng)前的邏輯運(yùn)算符
getsym(); //獲取下一個(gè)token
expression(fsys); //對表達(dá)式右部進(jìn)行處理計(jì)算
switch (relop) //如果剛才的運(yùn)算符是下面的一種
{
case SYM_EQU: //等號:產(chǎn)生8號判等指令
gen(OPR, 0, 8);
break;
case SYM_NEQ: //不等號:產(chǎn)生9號判不等指令
gen(OPR, 0, 9);
break;
case SYM_LSS: //小于號:產(chǎn)生10號判小指令
gen(OPR, 0, 10);
break;
case SYM_GEQ: //大于等號號:產(chǎn)生11號判不小于指令
gen(OPR, 0, 11);
break;
case SYM_GTR: //大于號:產(chǎn)生12號判大于指令
gen(OPR, 0, 12);
break;
case SYM_LEQ: //小于等于號:產(chǎn)生13號判不大于指令
gen(OPR, 0, 13);
break;
}
}
}
}
/***************************************
*通過靜態(tài)鏈求出數(shù)據(jù)區(qū)基地址的函數(shù)
****************************************/
int base(int stack[], int currentLevel, int levelDiff) //levelDiff要求的數(shù)據(jù)區(qū)所在層與當(dāng)前層的層差
{
int b = currentLevel;
while (levelDiff>0)
{
b = stack[b];
levelDiff--;
}
return b;//把找到的要求的數(shù)據(jù)區(qū)基址返回
}
/*************************************************************************/
void interpret() //PL/0編譯器產(chǎn)生的類PCODE目標(biāo)代碼解釋運(yùn)行過程
{
int pc; // pc為程序指令指針,指向下一條要運(yùn)行的代碼
int stack[STACKSIZE]; //stack為棧式計(jì)算機(jī)的數(shù)據(jù)內(nèi)存區(qū)
int top; //top為棧頂寄存器,類PCODE是在一種假想的棧式計(jì)算上運(yùn)行的,這個(gè)變量記錄這個(gè)計(jì)算機(jī)的當(dāng)前棧頂位置
int b; // b為基址指針,指向每個(gè)過程被調(diào)用時(shí)數(shù)據(jù)區(qū)中分配給它的局部變量數(shù)據(jù)段基址
instruction i; // i變量中存放當(dāng)前在運(yùn)行的指令
printf("\n開始執(zhí)行PL/0程序:\n");
fprintf(outfile, "\n開始執(zhí)行PL/0程序:\n");
pc = 0; //從0號代碼開始執(zhí)行程序
b = 1; // 數(shù)據(jù)段基址為1
top = 0; //程序開始運(yùn)行時(shí)棧頂寄存器置0
stack[1] = stack[2] = stack[3] = 0; //數(shù)據(jù)內(nèi)存中為SL,DL,RA三個(gè)單元均為0,標(biāo)識為主程序
do
{ //開始依次運(yùn)行程序目標(biāo)代碼
i = code[pc];//獲取一行目標(biāo)代碼,指令指針加一,指向下一條代碼
pc=pc+1;
switch (i.f) //如果i的f,即指令助記符是下面的某種情況,執(zhí)行不同的功能
{
case LIT: //如果是lit指令
stack[++top] = i.a; //該單元的內(nèi)容存放i指令的a操作數(shù),即實(shí)現(xiàn)了把常量值放到運(yùn)行棧棧頂
break;
case OPR: //如果是opr指令
switch (i.a) // 根據(jù)a操作數(shù)不同,執(zhí)行不同的操作
{
case 0: // 0號操作為從子過程返回操作
top = b - 1; //釋放這段子過程占用的數(shù)據(jù)內(nèi)存空間
pc = stack[top + 3]; //把指令指針取到RA的值,指向的是返回地址
b = stack[top + 2]; //把數(shù)據(jù)段基址取到DL的值,指向調(diào)用前子過程的數(shù)據(jù)段基址
break;
case 1: //1號操作為棧頂數(shù)據(jù)取反操作
stack[top] = -stack[top]; //對棧頂數(shù)據(jù)進(jìn)行取反
break;
case 2: //2號操作為棧頂兩個(gè)數(shù)據(jù)加法操作
top--; //棧頂指針下移
stack[top] =stack[top] + stack[top + 1]; //把兩單元數(shù)據(jù)相加存入棧頂
break;
case 3: //3號操作為棧頂兩個(gè)數(shù)據(jù)減法操作
top--; //棧頂指針下移
stack[top] =stack[top] - stack[top + 1]; //把兩單元數(shù)據(jù)相減存入棧頂
break;
case 4: //4號操作為棧頂兩個(gè)數(shù)據(jù)乘法操作
top--; //棧頂指針下移
stack[top]=stack[top] * stack[top + 1]; //把兩單元數(shù)據(jù)相乘存入棧頂
break;
case 5: //5號操作為棧頂兩個(gè)數(shù)據(jù)除法操作
top--; //棧頂指針下移
if (stack[top + 1] == 0)
{
fprintf(stderr, "\n運(yùn)行錯(cuò)誤:被零除!\n");
break;
}
stack[top]=stack[top] / stack[top + 1]; //把兩單元數(shù)據(jù)相整除存入棧頂
break;
case 6: //6號操作為判奇操作
stack[top] =(stack[top] % 2); //數(shù)據(jù)棧頂?shù)闹凳瞧鏀?shù)則把棧頂值置1,否則置0
break;
case 8: //8號操作為棧頂兩個(gè)數(shù)據(jù)判等操作
top--; //棧頂指針下移
stack[top] = (stack[top] == stack[top + 1]); //判等,相等棧頂置1,不等置0
break;
case 9: //9號操作為棧頂兩個(gè)數(shù)據(jù)判不等操作
top--; //棧頂指針下移
stack[top] = (stack[top] != stack[top + 1]); //判不等,不等棧頂置1,相等置0
break;
case 10: //10號操作為棧頂兩個(gè)數(shù)據(jù)判小于操作
top--; //棧頂指針下移
stack[top] = (stack[top] < stack[top + 1]); //判小于,如果下面的值小于上面的值,棧頂置1,否則置0
break;
case 11: //11號操作為棧頂兩個(gè)數(shù)據(jù)判大于等于操作
top--; //棧頂指針下移
stack[top] = (stack[top] >= stack[top + 1]); //判大于等于,如果下面的值大于等于上面的值,棧頂置1,否則置0
break;
case 12: //12號操作為棧頂兩個(gè)數(shù)據(jù)判大于操作
top--; //棧頂指針下移
stack[top] = (stack[top] > stack[top + 1]); //判大于,如果下面的值大于上面的值,棧頂置1,否則置0
break;
case 13: //13號操作為棧頂兩個(gè)數(shù)據(jù)判小于等于操作
top--; //棧頂指針下移
stack[top] = (stack[top] <= stack[top + 1]);//判小于等于,如果下面的值小于等于上面的值,棧頂置1,否則置0
break;
}
break;
case LOD: // 如果是lod指令:將變量放到棧頂
stack[++top] = stack[base(stack, b, i.l) + i.a];
//棧頂上移,開辟空間,通過數(shù)據(jù)區(qū)層差l和偏移地址a找到變量的數(shù)據(jù),存入上面開辟的新空間(即棧頂)
break;
case STO: //如果是sto指令
stack[base(stack, b, i.l) + i.a] = stack[top]; //把棧頂?shù)闹荡嫒胛恢迷跀?shù)據(jù)區(qū)層差l偏移地址a的變量內(nèi)存
//printf("%d\n", stack[top]);
fprintf(outfile, "%d\n", stack[top]);
top--; //棧項(xiàng)下移,釋放空間
break;
case CAL: //如果是cal指令
stack[top + 1] = base(stack, b, i.l); //在棧頂壓入靜態(tài)鏈SL
stack[top + 2] = b; //然后壓入當(dāng)前數(shù)據(jù)區(qū)基址,作為動態(tài)鏈DL
stack[top + 3] = pc; //最后壓入當(dāng)前的斷點(diǎn),作為返回地址RA
b = top + 1; //把當(dāng)前數(shù)據(jù)區(qū)基址指向SL所在位置
pc = i.a; //從a所指位置開始繼續(xù)執(zhí)行指令,即實(shí)現(xiàn)了程序執(zhí)行的跳轉(zhuǎn)
break;
case INT: //如果是int指令
top += i.a; //棧頂上移a個(gè)空間,即開辟a個(gè)新的內(nèi)存單元
break;
case JMP: //如果是jmp指令
pc = i.a; //把jmp指令操作數(shù)a的值作為下一次要執(zhí)行的指令地址,實(shí)現(xiàn)無條件跳轉(zhuǎn)
break;
case JPC: //如果是jpc指令
if (stack[top] == 0)//判斷棧頂值
pc = i.a; //如果是0就跳轉(zhuǎn),否則不跳轉(zhuǎn)
top--; //釋放棧頂空間
break;
case RED://如果是red指令
//把棧頂?shù)闹荡嫒胛恢迷跀?shù)據(jù)區(qū)層差l偏移地址a的變量內(nèi)存
printf("輸入:\n");
scanf("%d",&stack[base(stack, b, i.l) + i.a]);
break;
case WRT://如果是wrt指令
printf("輸出:%d\n", stack[top]);
fprintf(outfile, "輸出:%d\n", stack[top]);
top++;//棧頂上移,開辟空間
break;
}
}while (pc!=0);
printf("PL/0程序運(yùn)行結(jié)束!\n\n");
fprintf(outfile, "PL/0程序運(yùn)行結(jié)束!\n");
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -