?? 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;
}
/*
* 出錯處理,打印出錯位置和錯誤編碼
*/
void error(int n)
{
char space[81];
memset(space,32,81); //ASC碼32為空格
space[cc-1]=0; //出錯時當前符號已經讀完,所以cc-1
printf("****%s!%d\n", space, n);
fprintf(fa1,"****%s!%d\n", space, n);
err++;
}
/*
* 生成虛擬機代碼
*
* x: instruction.f;
* y: instruction.l;
* z: instruction.a;
*/
int gen(enum fct x, int y, int z )
{
if (cx >= cxmax)
{
printf("Program too long"); /* 程序過長 */
return -1;
}
code[cx].f = x;
code[cx].l = y;
code[cx].a = z;
cx++;
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);
}
}
}
/* 通過過程基址求上l層過程的基址 */
int base(int l, int* s, int b)
{
int b1;
b1 = b;
while (l > 0)
{
b1 = s[b1];
l--;
}
return b1;
}
/*
* 解釋程序
*/
void interpret()
{
int p, b, t; /* 指令指針,指令基址,棧頂指針 */
struct instruction i; /* 存放當前指令 */
int s[stacksize]; /* 棧 */
printf("start pl0\n");
t = 0;
b = 0;
p = 0;
s[0] = s[1] = s[2] = 0;
do {
i = code[p]; /* 讀當前指令 */
p++;
switch (i.f)
{
case lit: /* 將a的值取到棧頂 */
s[t] = i.a;
t++;
break;
case opr: /* 數學、邏輯運算 */
switch (i.a)
{
case 0:
t = b;
p = s[t+2];
b = s[t+1];
break;
case 1:
s[t-1] = -s[t-1];
break;
case 2:
t--;
s[t-1] = s[t-1]+s[t];
break;
case 3:
t--;
s[t-1] = s[t-1]-s[t];
break;
case 4:
t--;
s[t-1] = s[t-1]*s[t];
break;
case 5:
t--;
s[t-1] = s[t-1]/s[t];
break;
case 6:
s[t-1] = s[t-1]%2;
break;
case 8:
t--;
s[t-1] = (s[t-1] == s[t]);
break;
case 9:
t--;
s[t-1] = (s[t-1] != s[t]);
break;
case 10:
t--;
s[t-1] = (s[t-1] < s[t]);
break;
case 11:
t--;
s[t-1] = (s[t-1] >= s[t]);
break;
case 12:
t--;
s[t-1] = (s[t-1] > s[t]);
break;
case 13:
t--;
s[t-1] = (s[t-1] <= s[t]);
break;
case 14:
printf("%d", s[t-1]);
fprintf(fa2, "%d", s[t-1]);
t--;
break;
case 15:
printf("\n");
fprintf(fa2,"\n");
break;
case 16:
printf("?");
fprintf(fa2, "?");
scanf("%d", &(s[t]));
fprintf(fa2, "%d\n", s[t]);
t++;
break;
}
break;
case lod: /* 取相對當前過程的數據基地址為a的內存的值到棧頂 */
s[t] = s[base(i.l,s,b)+i.a];
t++;
break;
case sto: /* 棧頂的值存到相對當前過程的數據基地址為a的內存 */
t--;
s[base(i.l, s, b) + i.a] = s[t];
break;
case cal: /* 調用子過程 */
s[t] = base(i.l, s, b); /* 將父過程基地址入棧 */
s[t+1] = b; /* 將本過程基地址入棧,此兩項用于base函數 */
s[t+2] = p; /* 將當前指令指針入棧 */
b = t; /* 改變基地址指針值為新過程的基地址 */
p = i.a; /* 跳轉 */
break;
case inte: /* 分配內存 */
t += i.a;
break;
case jmp: /* 直接跳轉 */
p = i.a;
break;
case jpc: /* 條件跳轉 */
t--;
if (s[t] == 0)
{
p = i.a;
}
break;
}
} while (p != 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;
constdeclarationdo(&tx, lev, &dx);
/* dx的值會被constdeclaration改變,使用指針 */
while (sym == comma) //comma為逗號
{
getsymdo;
constdeclarationdo(&tx, lev, &dx);
}
if (sym == semicolon) //semicolon為分號
{
getsymdo;
}
else
{
error(5); /*漏掉了逗號或者分號*/
}
}
if (sym == varsym) /* 收到變量聲明符號,開始處理變量聲明 */
{
getsymdo;
vardeclarationdo(&tx, lev, &dx);
while (sym == comma)
{
getsymdo;
vardeclarationdo(&tx, lev, &dx);
}
if (sym == semicolon)
{
getsymdo;
}
else
{
error(5); /*漏掉了逗號或者分號*/
}
}
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);
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;
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 addr=%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); /*分程序沒有補救集合 */
testdo(fsys, nxtlev, 8); /* 檢測后跟符號正確性 */
listcode(cx0); /* 輸出代碼 */
return 0;
}
/*
* 常量聲明處理
*/
int constdeclaration(int* ptx, int lev, int* pdx)
{
if (sym == ident)
{
getsymdo;
if (sym==eql || sym==becomes) //eql為等于,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); /* var后應是標識 */
}
return 0;
}
/*
* 語句處理
*/
int statement(bool* fsys, int* ptx, int lev)
{
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -