?? pl0.c
字號:
/*
*測試當前符號是否合法
*
*在某一部分(如一條語句,一個表達式)將要結束時時我們希望下一個符號屬于某集合
*(該部分的后跟符號) test 負責這項檢測,并且負責當檢測不通過時的補救措施
*程序在需要檢測時指定當前需要的符號集合和補救用的集合(如之前未完成部分的后跟
*符號),以及不通過時的錯誤號
*
*S1:我們需要的符號
*s2:如果不是我們需要的,則需要一個補救用的集合
*n:錯誤號
*/
int test(bool* s1,bool* s2,int n)
{
if(! inset(sym,s1))
{
error(n);
/*當檢測不通過時,不停獲取符號,直到它屬于需要的集合或補救的集合*/
while((! inset(sym,s1))&&(! inset(sym,s2)))
{
getsymdo;
}
}
return 0;
}
/*
*編譯程序主體
*
*lev:當前分程序所在層
*tx:名字表當前尾指針
*fsys:當前模塊后跟符號集合
*/
int block(int lev,int tx,bool* fsys)
{
int i;
int dx; /*名字分配到的相對地址*/
int tx0; /*保留初始tx*/
int cx0; /*保留初始cx*/
bool nxtlev[symnum]; /*在下級函數的參數中,符號集合均為值參,但由于使用數組
實現,傳遞進來的是指針,為防止下級函數改變上級函數的
集合,開辟新的空間傳遞給下級函數*/
dx=3;
tx0=tx; /*記錄本層名字的初始位置*/
table[tx].adr=cx;
gendo(jmp,0,0);
if(lev > levmax)
{
error(32);
}
do{
if(sym==constsym) /*收到常量聲明符號,開始處理常量聲明*/
{
getsymdo;
do{
constdeclarationdo(&tx,lev,&dx); /*dx的值會被constdeclaration改變,使用
指針*/
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);/*procedure后應為標識符*/
}
if(sym==semicolon)
{
getsymdo;
}
else
{
error(5);/*漏掉了分號*/
}
memcpy(nxtlev,fsys,sizeof(bool)*symnum); /* fsys 當前模塊的后跟符號集 */
nxtlev[semicolon]=true;
if(-1==block(lev+1,tx,nxtlev))
{
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;
testdo(nxtlev,declbegsys,7);
}while(inset(sym,declbegsys)); /*直到沒有聲明符號*/
code[table[tx0].adr].a=cx; /*開始生成當前過程代碼*/
table[tx0].adr=cx; /*當前過程代碼地址*/
table[tx0].size=dx; /*聲明部分中每增加一條聲明都會給dx增加1,聲明部分已經結束,dx就是當前過程數據的size*/
cx0=cx;
gendo(inte,0,dx); /*生成分配內存代碼*/
if(tableswitch) /*輸出名字表*/
{
printf("TABLE:\n");
if(tx0+1>tx)
{
printf("NULL\n");
}
for(i=tx0+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(fas,"%d const %s",i,table[i].name);
fprintf(fas,"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].adr);
fprintf(fas,"%d var %s",i,table[i].name);
fprintf(fas,"lev=%d addr=%d\n",table[i].level,table[i].adr);
break;
case procedur:
printf("%d proc%s",i,table[i].name);
printf("lev=%d addr=%d size=%d\n",table[i].level,table[i].adr,table[i].size);
fprintf(fas,"%d proc%s",i,table[i].name);
fprintf(fas,"lev=%d adr=%d size=%d \n",table[i].level,table[i].adr,table[i].size);
break;
}
}
printf("\n");
}
/*語句后跟符號為分號或end*/
memcpy(nxtlev,fsys,sizeof(bool)*symnum);/*每個后跟符號集和都包含上層后跟符號集和,以便補救*/
nxtlev[semicolon]=true;
nxtlev[endsym]=true;
statementdo(nxtlev,&tx,lev);
gendo(opr,0,0); /*每個過程出口都要使用的釋放數據段命令*/
memset(nxtlev,0,sizeof(bool)*symnum); /*分程序沒有補救集合*/
test(fsys,nxtlev,8); /*檢測后跟符號正確性*/
listcode(cx0); /*輸出代碼*/
return 0;
}
/*
*在名字表中加入一項
*
*k:名字種類const,var or procedure
*ptx:名字表尾指針的指針,為了可以改變名字表尾指針的數值
*lev:名字所在的層次,以后所有的lev都是這樣
*pdx:為當前應分配的變量的相對地址,分配后要增加1
*/
void enter (enum object k,int *ptx,int lev, int *pdx)
{
(*ptx)++;
strcpy(table[(*ptx)].name,id); /*全局變量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; /*過程名的ADR域 為反填,此處不用填寫*/
break;
}
}
/*
*查找名字的位置
*找到則返回在名字表中的位置,否則返回0
*
*idt: 要查找的名字
*tx::當前名字表尾指針
*/
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 constdeclaration(int * ptx,int lev,int * pdx)
{
if(sym==ident)
{
getsymdo;
if(sym==eql ||sym==becomes)
{
if(sym==becomes)
{
error(1); /*把=寫出成了:=*/
}
getsymdo;
if(sym==number)
{
enter(constant,ptx,lev,pdx);
getsymdo;
}
else
{
error(2); /*常量說明=后應是數字*/
}
}
else
{
error(3); /*常量說明標識后應是=*/
}
}
else
{
error(4); /*const后應是標識*/
}
return 0;
}
/*
*
*/
int vardeclaration(int * ptx,int lev,int * pdx)
{
if(sym==ident)
{
enter(variable,ptx,lev,pdx);//填寫名字表
getsymdo;
}
else
{
error(4);
}
return 0;
}
/*
*輸入目標代碼清單
*/
void listcode(int cx0)
{
int i;
if (listswitch)
{
for(i=cx0;i<cx;i++)
{
printf("%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);
fprintf(fa,"%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);
}
}
}
/*
*語句處理
*/
int statement(bool* fsys,int * ptx,int lev)
{
int i,cx1,cx2;
enum symbol sym2;
bool nxtlev[symnum];
if(sym==ident) /* 標識符開始*/
{
i=position(id,*ptx); // ptx 名字表尾指針
if(i==0)
{
error(11);
}
else
{
if(table[i].kind!=variable) //不是變量
{
error(12);
i=0;
}
else //是變量
{
getsymdo;
if(sym==becomes||sym==pluseq||sym==minuseq||sym==plusone||sym==minusone)
{
sym2=sym;
getsymdo;
gendo(lod,lev-table[i].level,table[i].adr);
}
else
{
error(13);
}
//擴充 ++ 和--
if(sym2==plusone||sym2==minusone)/* 準備按照a++、a--語句處理,與read類似*/
{
if(i!=0)
{
if(sym2==plusone)
{
gendo(lit,0,1); //將常量1取到棧頂s[t]
gendo(opr,0,2); //將棧頂下一個數s[t-1]+1,即+s[t]
gendo(sto,lev-table[i].level,table[i].adr); //棧頂的內容放入table[i].adr
}
if(sym2==minusone)
{
gendo(lit,0,1); //同上
gendo(opr,0,3); //s[t-1]=s[t-1]-s[t]
gendo(sto,lev-table[i].level,table[i].adr);
}
}
}
else
{
memcpy(nxtlev,fsys,sizeof(bool)* symnum);
expressiondo(nxtlev,ptx,lev);
if(i!=0)
{
if(sym2==becomes)
gendo(sto,lev-table[i].level,table[i].adr);
//擴充+=功能
if(sym2==pluseq)
{
gendo(opr,0,2); //將棧頂下一個數s[t-1]+s[t],并將結果存入s[t-1]
gendo(sto,lev-table[i].level,table[i].adr);
}
//擴充-=功能
if(sym2==minuseq)
{
gendo(opr,0,3); //s[t-1]=s[t-1]-s[t]
gendo(sto,lev-table[i].level,table[i].adr);
}
}
}//else
}
}
}
else
{
if(sym==readsym) /* 從鍵盤讀入*/
{
getsymdo;
if(sym!=lparen) /* 左括號*/
{
error(34);
}
else
{
do{
getsymdo;
if(sym==ident)
{
i=position(id, *ptx);
}
else
{
i=0;
}
if(i==0)
{
error(35);
}
else
{
gendo(opr,0,16);
gendo(sto,lev-table[i].level,table[i].adr); /* 儲存到變量*/
}
getsymdo;
}while (sym==comma); /*一條read語句可讀多個變量 */
}
if(sym!=rparen)
{
error(33); /* 格式錯誤,應是右括號*/
while(!inset(sym,fsys))/* 出錯補救,直到收到上層函數的后跟符號*/
{
getsymdo;
}
}
else
{
getsymdo;
}
}
else
{
if(sym==writesym) /* 準備按照write語句處理,與read類似*/
{
getsymdo;
if(sym==lparen)
{
do{
getsymdo;
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[rparen]=true;
nxtlev[comma]=true; /* write的后跟符號為)or,*/
expressiondo(nxtlev,ptx,lev);/* 調用表達式處理,此處與read不同,read為給變量賦值*/
gendo(opr,0,14);/* 生成輸出指令,輸出棧頂的值*/
}while(sym==comma);
if(sym!=rparen)
{
error(33);/* write()應為完整表達式*/
}
else
{
getsymdo;
}
}
gendo(opr,0,15); /* 輸出換行*/
}
else
{
if(sym==callsym) /* 準備按照call語句處理*/
{
getsymdo;
if(sym!=ident)
{
error(14); /*call后應為標識符*/
}
else
{
i=position(id,*ptx);
if(i==0)
{
error(11); /*過程未找到*/
}
else
{
if(table[i].kind==procedur)
{
gendo(cal,lev-table[i].level,table[i].adr); /*生成call指令*/
}
else
{
error(15); /*call后標識符應為過程*/
}
}
getsymdo;
}
}
else
{
if(sym==ifsym) /*準備按照if語句處理*/
{
getsymdo;
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[thensym]=true;
nxtlev[dosym]=true; /*后跟符號為then或do*/
conditiondo(nxtlev,ptx,lev); /*調用條件處理(邏輯運算)函數*/
if(sym==thensym)
{
getsymdo;
}
else
{
error(16); /*缺少then*/
}
cx1=cx; /*保存當前指令地址*/
gendo(jpc,0,0); /*生成條件跳轉指令,跳轉地址暫寫0*/
memcpy(nxtlev,fsys,sizeof(bool)*symnum); //添加后跟符號
nxtlev[elsesym]=true;
//若無else語句
statementdo(nxtlev,ptx,lev); /*處理then后的語句*/
code[cx1].a=cx; /*經statement處理后,cx為then后語句執行完的位置,它正是前面未定的跳轉地址*/
//若有else語句
if(sym==elsesym)
{
cx2=cx;
getsymdo;
gendo(jmp,0,0); //if處理完了,跳轉到最后,但是地址未知,故寫零
code[cx1].a=cx; //為假時的跳轉入口處
statementdo(fsys,ptx,lev);
code[cx2].a=cx; //同沒有else語句一樣,修改跳轉地址
}
}
else
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -