PL0擴展一維數組array

PL0語言數組變量類型文法可定義爲:

Var <數組變量名> ’(‘<下界>,<上界>’)’

其中<下界>,<上界>是常量名或無符號數

引用格式可爲:C(1),c(a),C(a+b),C(b+C(1))

頭文件修改:

1、增加冒號符號(增加colon,symnum+1)

/* 符號 */
enum symbol {
    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,	elsesym,	forsym,	   tosym, 
	colon
};
#define symnum 36

2、定義名字表中的數組類型(添加array)

enum object {
    constant,
    variable,
    procedur,
    array       //add
};

3、添加虛擬機代碼(增加sta,lda,arrcheck,且fctnum+3)

enum fct {
	lit, opr, lod,
	sto, cal, inte,
	jmp, jpc, sta,
	lda, arrcheck
};
#define fctnum 11

4、修改名字表結構(增加數組上界startid)

/* 名字表結構 */
struct tablestruct
{
    char name[al];      /* 名字 */
    enum object kind;   /* 類型:const, var, array or procedure */
    int val;            /* 數值,僅const使用 */
    int level;          /* 所處層,僅const不使用 */
    int adr;            /* 地址,僅const不使用 */
    int size;           /* 需要分配的數據區空間, 僅procedure使用 */
    int startid;        /*數組的上界*/
};

源文件修改:

1、增加指令(sta,lda,arrcheck)

	/* 設置指令名稱 */
	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[inte][0]), "int");
	strcpy(&(mnemonic[jmp][0]), "jmp");
	strcpy(&(mnemonic[jpc][0]), "jpc");
	strcpy(&(mnemonic[sta][0]), "sta");
	strcpy(&(mnemonic[lda][0]), "lda");
	strcpy(&(mnemonic[arrcheck][0]), "arrcheck");

2、修改冒號檢測(365行附近)

if (ch == ':')      /* 檢測賦值符號 */
{
	getchdo;
	if (ch == '=')
	{
		sym = becomes;
		getchdo;
	}
	else
	{
		sym = colon;  /* 此處改爲colon */
	}
}

3、增加array名字表輸出(只需增加case array就行 ):620行附近

switch (table[i].kind)
{
case constant:
	...
	break;
case variable:
    ...
	break;
case procedur:
	...
	break;
case array:
	printf("    %d arr     %s   ", i, table[i].name);
	printf("lev=%d addr=%d size=%d startid=%d\n", table[i].level, table[i].adr, table[i].size, table[i].startid);
	fprintf(fas, "    %d arr    %s   ", i, table[i].name);
	fprintf(fas, "lev=%d addr=%d size=%d startid=%d\n", table[i].level, table[i].adr, table[i].size, table[i].startid);
	break;
}

4、修改enter函數(增加array處理)

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 array:
		table[(*ptx)].level = lev;
		table[(*ptx)].adr = (*pdx);
		break;
	case procedur:  /* 過程名字 */
		table[(*ptx)].level = lev;
		break;
	}
}

5、修改變量聲明處理函數vardeclaration(增加數組處理)

int vardeclaration(int* ptx, int lev, int* pdx)
{
	if (sym == ident)
	{
		// 填寫名字表並改變堆棧幀計數器
		int startid = 0, endid = 0;
		enter(variable, ptx, lev, pdx);//填寫名字表
		(*pdx)++;
		getsymdo;
		if (sym == lparen) {
			getsymdo;
			switch (sym) {
			case ident:
				startid = table[position(id, *ptx)].val;
				break;
			case number:
				startid = num;
				break;
			case plus:
				getsymdo;
				startid = num;
				break;
			case minus:
				getsymdo;
				startid = -num;
				break;
			}
			table[(*ptx)].adr = table[(*ptx)].adr - startid;
			table[(*ptx)].startid = startid;
			getsymdo;
			if (sym != colon) {
				error(30);
			}
			else {
				getsymdo;
				switch (sym) {
				case ident:
					endid = table[position(id, *ptx)].val;
					table[(*ptx)].size = endid - startid + 1;
					break;
				case number:
					endid = num + 1;
					table[(*ptx)].size = endid - startid + 1;
					break;
				case plus:
					getsymdo;
					endid = num + 1;
					table[(*ptx)].size = endid - startid + 1;
					break;
				case minus:
					getsymdo;
					endid = -num + 1;
					table[(*ptx)].size = endid - startid + 1;
					break;
				}
				table[(*ptx)].kind = array;
				(*pdx) = (*pdx) + endid - startid + 1;	//計算數組中的各自dx
				getsymdo;
				getsymdo;
			}
		}
	}
	else
	{
		error(4);
	}
	return 0;
}

6、數組的賦值處理(修改statement函數的外層【if (sym == ident) 】):840行附近


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;
				memcpy(nxtlev, fsys, sizeof(bool) * symnum);
				expressiondo(nxtlev, ptx, lev); /* 處理賦值符號右側表達式 */
				if (i != 0)
				{
					/* expression將執行一系列指令,但最終結果將會保存在棧頂,執行sto命令完成賦值 */
					gendo(sto, lev - table[i].level, table[i].adr);
				}
			}
			else if (sym == lparen) {		// 數組啦...
				getsymdo;
				memcpy(nxtlev, fsys, sizeof(bool) * symnum);
				expressiondo(nxtlev, ptx, lev);
				// parseExpression將產生一系列指令,但最終結果將會保存在棧頂,執行sto命令完成賦值
				//在expression最後已經有這個了:nextSym();	//一個)
				getsymdo;	//一個:=
				//後面和var賦值相同,除了最後生成的語句
				getsymdo;
				memcpy(nxtlev, fsys, sizeof(bool) * symnum);
				expressiondo(nxtlev, ptx, lev);
				// parseExpression將產生一系列指令,但最終結果將會保存在棧頂,執行sto命令完成賦值
				gendo(sta, lev - table[i].level, table[i].adr);
			}
			else
			{
				error(13);  /* 沒有檢測到賦值符號 */
			}
				
		}
	}//if (i == 0)
}

7、數組的read操作(修改statement的【if (sym == readsym)】內的第一個else裏的都...while語句):900行附近

do {
	getsymdo;
	if (sym == ident)
	{
		i = position(id, *ptx); /* 查找要讀的變量 */
	}
	else
	{
		i=0;
	}
	if (i == 0)
	{
		error(35);  /* read()中應是聲明過的變量名 */
	}
	else
	{
		if (table[i].kind == constant || table[i].kind == procedur) {
			error(32);		// read()中的標識符不是變量
		}
		else {
			getsymdo;
			if (sym != lparen) {			//非數組,即變量
				gendo(opr, 0, 16);
				gen(sto, lev - table[i].level, table[i].adr);
			}
			else {		//TODO 數組
				getsymdo;
				memcpy(nxtlev, fsys, sizeof(bool) * symnum);
				nxtlev[rparen] = true;
				expressiondo(nxtlev, ptx, lev);
				int ltmp = lev - table[i].level;
				int adrtmp = table[i].adr;
				gendo(arrcheck, table[i].startid, table[i].size);
				gendo(jpc, 0, 0);
				gendo(opr, 0, 16);
				gendo(sta, ltmp, adrtmp);
				getsymdo;
			}
		}
	}

} while (sym == comma); /* 一條read語句可讀多個變量 */

8、修改factor函數(增加case array)

switch (table[i].kind)
{
case constant:  /* 名字爲常量 */
	gendo(lit, 0, table[i].val);    /* 直接把常量的值入棧 */
	break;
case variable:  /* 名字爲變量 */
	gendo(lod, lev-table[i].level, table[i].adr);   /* 找到變量地址並將其值入棧 */
	break;
case procedur:  /* 名字爲過程 */
	error(21);  /* 不能爲過程 */
	break;
case array:
	getsymdo;
	if (sym == lparen)
	{					//是數組
		int ltmp = lev - table[i].level;
		int adrtmp = table[i].adr;
		getsymdo;
		memcpy(nxtlev, fsys, sizeof(bool) * symnum);
		nxtlev[rparen] = true;
		expressiondo(nxtlev, ptx, lev);
		gendo(lda, ltmp, adrtmp);
		//getsymdo;							
	}
	if (sym == rparen)
	{
		//getsymdo;
	}
	break;
}

9、定義指令操作(定義指令sta,lda,arrcheck):源文件末尾能看到這些指令

case jmp:   /* 直接跳轉 */
	...
	break;
case jpc:   /* 條件跳轉 */
	...
	break;
case sta:                        // 棧頂的值存到數組下標爲a的內存
	t--;
	s[base(i.l, s, b) + i.a + s[t - 1]] = s[t];
	t--;
	break;
case lda:
	s[t - 1] = s[base(i.l, s, b) + i.a + s[t - 1]];       //對數組的讀取 第二個S[T]是放入偏移地址的				
	break;
case arrcheck:
	s[t] = i.a;
	if ((s[t - 1] < i.l) || (s[t - 1] > s[t] + i.l - 1))
	{
		printf("Error:Out of the array's size!\n");
		fprintf(fa2, "Error:Out of the array's size!\n");
		s[t] = 0;
	}
	else {
		s[t] = 1;
	}
	t++;
	break;

測試文件:

const c=3;
var b(2:c);
begin
  read(b(3));
  write(b(3));
end.

擴展完成代碼:

頭文件:

/*
 * PL/0 complier program for win32 platform (implemented in C)
 *
 * The program has been test on Visual C++ 6.0,  Visual C++.NET and
 * Visual C++.NET 2003,  on Win98,  WinNT,  Win2000,  WinXP and Win2003
 *
 */

typedef enum {
    false,
    true
} bool;


#define norw 16     /* 關鍵字個數 */
#define txmax 100   /* 名字表容量 */
#define nmax 14     /* number的最大位數 */
#define al 10       /* 符號的最大長度 */
#define amax 2047   /* 地址上界*/
#define levmax 3    /* 最大允許過程嵌套聲明層數 [0,  levmax]*/
#define cxmax 500   /* 最多的虛擬機代碼數 */

/* 符號 */
enum symbol {
    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,	elsesym,	forsym,	   tosym, 
	colon
};
#define symnum 36

/* 名字表中的類型 */
enum object {
    constant,
    variable,
    procedur,
    array       //add
};

/* 虛擬機代碼 */
enum fct {
	lit, opr, lod,
	sto, cal, inte,
	jmp, jpc, sta,
	lda, arrcheck
};
#define fctnum 10

/* 虛擬機代碼結構 */
struct instruction
{
    enum fct f; /* 虛擬機代碼指令 */
    int l;      /* 引用層與聲明層的層次差 */
    int a;      /* 根據f的不同而不同 */
};

FILE* fas;  /* 輸出名字表 */
FILE* fa;   /* 輸出虛擬機代碼 */
FILE* fa1;  /* 輸出源文件及其各行對應的首地址 */
FILE* fa2;  /* 輸出結果 */
bool listswitch;    /* 顯示虛擬機代碼與否 */
bool tableswitch;   /* 顯示名字表與否 */
char ch;            /* 獲取字符的緩衝區,getch 使用 */
enum symbol sym;    /* 當前的符號 */
char id[al+1];      /* 當前ident, 多出的一個字節用於存放0 */
int num;            /* 當前number */
int cc, ll;          /* getch使用的計數器,cc表示當前字符(ch)的位置 */
int cx;             /* 虛擬機代碼指針, 取值範圍[0, cxmax-1]*/
char line[81];      /* 讀取行緩衝區 */
char a[al+1];       /* 臨時符號, 多出的一個字節用於存放0 */
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 or procedure */
    int val;            /* 數值,僅const使用 */
    int level;          /* 所處層,僅const不使用 */
    int adr;            /* 地址,僅const不使用 */
    int size;           /* 需要分配的數據區空間, 僅procedure使用 */
	int startid;        /*數組的上界*/
};

struct tablestruct table[txmax]; /* 名字表 */

FILE* fin;
FILE* fout;
char fname[al];
int err; /* 錯誤計數器 */

/* 當函數中會發生fatal error時,返回-1告知調用它的函數,最終退出程序 */
#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(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(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);

 源文件:

/*
 * PL/0 complier program for win32 platform (implemented in C)
 *
 * The program has been test on Visual C++ 6.0, Visual C++.NET and
 * Visual C++.NET 2003, on Win98, WinNT, Win2000, WinXP and Win2003
 *
 * 使用方法:
 * 運行後輸入PL/0源程序文件?
 * 回答是否輸出虛擬機代碼
 * 回答是否輸出名字表
 * fa.tmp輸出虛擬機代碼
 * fa1.tmp輸出源文件及其各行對應的首地址
 * fa2.tmp輸出結?
 * fas.tmp輸出名字表
 */

#include <stdio.h>

#include "pl0.h"
#include "string.h"

/* 解釋執行時使用的棧 */
#define stacksize 500


int main()
{
	bool nxtlev[symnum];

	printf("Input pl/0 file?   ");
	scanf("%s", fname);     /* 輸入文件名 */

	fin = fopen(fname, "r");

	if (fin)
	{
		printf("List object code?(Y/N)");   /* 是否輸出虛擬機代碼 */
		scanf("%s", fname);
		listswitch = (fname[0]=='y' || fname[0]=='Y');

		printf("List symbol table?(Y/N)");  /* 是否輸出名字表 */
		scanf("%s", fname);
		tableswitch = (fname[0]=='y' || fname[0]=='Y');

		fa1 = fopen("fa1.tmp", "w");
		fprintf(fa1,"Input pl/0 file?   ");
		fprintf(fa1,"%s\n",fname);

		init();     /* 初始化 */

		err = 0;
		cc = cx = ll = 0;
		ch = ' ';

		if(-1 != getsym())
		{
			fa = fopen("fa.tmp", "w");
			fas = fopen("fas.tmp", "w");
			addset(nxtlev, declbegsys, statbegsys, symnum);
			nxtlev[period] = true;

			if(-1 == block(0, 0, nxtlev))   /* 調用編譯程序 */
			{
				fclose(fa);
				fclose(fa1);
				fclose(fas);
				fclose(fin);
				printf("\n");
				return 0;
			}
			fclose(fa);
			fclose(fa1);
			fclose(fas);

			if (sym != period)
			{
				error(9);
			}

			if (err == 0)
			{
				fa2 = fopen("fa2.tmp", "w");
				interpret();    /* 調用解釋執行程序 */
				fclose(fa2);
			}
			else
			{
				printf("Errors in pl/0 program");
			}
		}

		fclose(fin);
	}
	else
	{
		printf("Can't open file!\n");
	}

	printf("\n");
	return 0;
}

/*
* 初始化
*/
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]), "else");
	strcpy(&(word[5][0]), "end");
	strcpy(&(word[6][0]), "for");
	strcpy(&(word[7][0]), "if");
	strcpy(&(word[8][0]), "odd");
	strcpy(&(word[9][0]), "procedure");
	strcpy(&(word[10][0]), "read");
	strcpy(&(word[11][0]), "then");
	strcpy(&(word[12][0]), "to");
	strcpy(&(word[13][0]), "var");
	strcpy(&(word[14][0]), "while");
	strcpy(&(word[15][0]), "write");
	

	/* 設置保留字符號 */
	wsym[0] = beginsym;
	wsym[1] = callsym;
	wsym[2] = constsym;
	wsym[3] = dosym;
	wsym[4] = elsesym;
	wsym[5] = endsym;
	wsym[6] = forsym;
	wsym[7] = ifsym;
	wsym[8] = oddsym;
	wsym[9] = procsym;
	wsym[10] = readsym;
	wsym[11] = thensym;
	wsym[12] = tosym;
	wsym[13] = varsym;
	wsym[14] = whilesym;
	wsym[15] = 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[inte][0]), "int");
	strcpy(&(mnemonic[jmp][0]), "jmp");
	strcpy(&(mnemonic[jpc][0]), "jpc");
	strcpy(&(mnemonic[sta][0]), "sta");
	strcpy(&(mnemonic[lda][0]), "lda");
	strcpy(&(mnemonic[arrcheck][0]), "arrcheck");
	/* 設置符號集 */
	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;
}

/*
*   出錯處理,打印出錯位置和錯誤編碼
*/
void error(int n)
{
	char space[81];
	memset(space,32,81);

	space[cc-1]=0; //出錯時當前符號已經讀完,所以cc-1

	printf("****%s!%d\n", space, n);
	fprintf(fa1,"****%s!%d\n", space, n);

	err++;
}

/*
* 漏掉空格,讀取一個字符。
*
* 每次讀一行,存入line緩衝區,line被getsym取空後再讀一行
*
* 被函數getsym調用。
*/
int getch()
{
	if (cc == ll)
	{
		if (feof(fin))
		{
			printf("program incomplete");
			return -1;
		}
		ll=0;
		cc=0;
		printf("%d ", cx);
		fprintf(fa1,"%d ", cx);
		ch = ' ';
		while (ch != 10)
		{
			//fscanf(fin,"%c", &ch)
			//richard
			if (EOF == fscanf(fin,"%c", &ch))
			{
				line[ll] = 0;
				break;
			}
			//end richard
			printf("%c", ch);
			fprintf(fa1, "%c", ch);
			line[ll] = ch;
			ll++;
		}
		printf("\n");
		fprintf(fa1, "\n");
	}
	ch = line[cc];
	cc++;
	return 0;
}

/*
* 詞法分析,獲取一個符號
*/
int getsym()
{
	int i,j,k;

	/* the original version lacks "\r", thanks to foolevery */
	while (ch==' ' || ch==10 || ch==13 || ch==9)  /* 忽略空格、換行、回車和TAB */
	{
		getchdo;
	}
	if (ch>='a' && ch<='z')
	{           /* 名字或保留字以a..z開頭 */
		k = 0;
		do {
			if(k<al)
			{
				a[k] = ch;
				k++;
			}
			getchdo;
		} while (ch>='a' && ch<='z' || ch>='0' && ch<='9');
		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')
		{           /* 檢測是否爲數字:以0..9開頭 */
			k = 0;
			num = 0;
			sym = number;
			do {
				num = 10*num + ch - '0';
				k++;
				getchdo;
			} while (ch>='0' && ch<='9'); /* 獲取數字的值 */
			k--;
			if (k > nmax)
			{
				error(30);
			}
		}
		else
		{
			if (ch == ':')      /* 檢測賦值符號 */
			{
				getchdo;
				if (ch == '=')
				{
					sym = becomes;
					getchdo;
				}
				else
				{
					sym = colon;  /* 此處改爲colon */
				}
			}
			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];     /* 當符號不滿足上述條件時,全部按照單字符符號處理 */
						//getchdo;
						//richard
						if (sym != period)
						{
							getchdo;
						}
						//end richard
					}
				}
			}
		}
	}
	return 0;
}

/*
* 生成虛擬機代碼
*
* 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;
}


/*
* 測試當前符號是否合法
*
* 在某一部分(如一條語句,一個表達式)將要結束時時我們希望下一個符號屬於某集?
* (該部分的後跟符號),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;

			/* the original do...while(sym == ident) is problematic, thanks to calculous */
			/* 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;

			/* the original do...while(sym == ident) is problematic, thanks to calculous */
			/* 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);
			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;
		case array:
			printf("    %d arr     %s   ", i, table[i].name);
			printf("lev=%d addr=%d size=%d startid=%d\n", table[i].level, table[i].adr, table[i].size, table[i].startid);
			fprintf(fas, "    %d arr    %s   ", i, table[i].name);
			fprintf(fas, "lev=%d addr=%d size=%d startid=%d\n", table[i].level, table[i].adr, table[i].size, table[i].startid);
			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;
}

/*
* 在名字表中加入一項
*
* k:      名字種類const,var or procedure
* ptx:    名字表尾指針的指針,爲了可以改變名字表尾指針的值
* lev:    名字所在的層次,,以後所有的lev都是這樣
* pdx:    dx爲當前應分配的變量的相對地址,分配後要增加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 array:
		table[(*ptx)].level = lev;
		table[(*ptx)].adr = (*pdx);
		break;
	case procedur:  /* 過程名字 */
		table[(*ptx)].level = lev;
		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)
	{
		// 填寫名字表並改變堆棧幀計數器
		int startid = 0, endid = 0;
		enter(variable, ptx, lev, pdx);//填寫名字表
		(*pdx)++;
		getsymdo;
		if (sym == lparen) {
			getsymdo;
			switch (sym) {
			case ident:
				startid = table[position(id, *ptx)].val;
				break;
			case number:
				startid = num;
				break;
			case plus:
				getsymdo;
				startid = num;
				break;
			case minus:
				getsymdo;
				startid = -num;
				break;
			}
			table[(*ptx)].adr = table[(*ptx)].adr - startid;
			table[(*ptx)].startid = startid;
			getsymdo;
			if (sym != colon) {
				error(30);
			}
			else {
				getsymdo;
				switch (sym) {
				case ident:
					endid = table[position(id, *ptx)].val;
					table[(*ptx)].size = endid - startid + 1;
					break;
				case number:
					endid = num + 1;
					table[(*ptx)].size = endid - startid + 1;
					break;
				case plus:
					getsymdo;
					endid = num + 1;
					table[(*ptx)].size = endid - startid + 1;
					break;
				case minus:
					getsymdo;
					endid = -num + 1;
					table[(*ptx)].size = endid - startid + 1;
					break;
				}
				table[(*ptx)].kind = array;
				(*pdx) = (*pdx) + endid - startid + 1;	//計算數組中的各自dx
				getsymdo;
				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, cx3;
	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;
					memcpy(nxtlev, fsys, sizeof(bool) * symnum);
					expressiondo(nxtlev, ptx, lev); /* 處理賦值符號右側表達式 */
					if (i != 0)
					{
						/* expression將執行一系列指令,但最終結果將會保存在棧頂,執行sto命令完成賦值 */
						gendo(sto, lev - table[i].level, table[i].adr);
					}
				}
				else if (sym == lparen) {		// 數組啦...
					getsymdo;
					memcpy(nxtlev, fsys, sizeof(bool) * symnum);
					expressiondo(nxtlev, ptx, lev);
					// parseExpression將產生一系列指令,但最終結果將會保存在棧頂,執行sto命令完成賦值
					//在expression最後已經有這個了:nextSym();	//一個)
					getsymdo;	//一個:=
					//後面和var賦值相同,除了最後生成的語句
					getsymdo;
					memcpy(nxtlev, fsys, sizeof(bool) * symnum);
					expressiondo(nxtlev, ptx, lev);
					// parseExpression將產生一系列指令,但最終結果將會保存在棧頂,執行sto命令完成賦值
					gendo(sta, lev - table[i].level, table[i].adr);
				}
				else
				{
					error(13);  /* 沒有檢測到賦值符號 */
				}
				
			}
		}//if (i == 0)
	}
	else if(sym==forsym)      //檢測到for語句
    {
        getsymdo;
        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) error(13);             //賦值語句左部標識符後應是賦值號:=
                    else getsymdo;
                    memcpy(nxtlev,fsys,sizeof(bool)*symnum); 
                    nxtlev[tosym]=true;                     //後跟符to和downto
                    expressiondo(nxtlev,ptx,lev);           //處理賦值語句右部的表達式E1
                    gendo(sto,lev-table[i].level,table[i].adr);     //保存初值
                 	if(sym==tosym){
					 
                        getsymdo;
                        cx1=cx;       //保存循環開始點
                        //將循環判斷變量取出放到棧頂
                        gendo(lod,lev-table[i].level,table[i].adr);                                        
                        memcpy(nxtlev,fsys,sizeof(bool)*symnum);    //處理表達式E2
                        nxtlev[dosym]=true;                         //後跟符do
                        expressiondo(nxtlev,ptx,lev);
                        /*判斷循環變量條件,比如for i:=E1 to E2 do S中,判斷i是否小於E2,如小於等於,繼續循環,大於的話,跳出循環*/     
                        gendo(opr,0,13);             //生成比較指令,i是否小於等於E2的值
                        cx2=cx;                      //保存循環結束點
                        //生成條件跳轉指令,跳出循環,跳出的地址未知
                        gendo(jpc,0,0);                     
                        if(sym==dosym)               //處理循環體S
                        {
                            getsymdo;
                            statement(fsys,ptx,lev);  //循環體處理
                            //增加循環變量步長爲
                            //將循環變量取出放在棧頂
                            gendo(lod,lev-table[i].level,table[i].adr);                                       
                            gendo(lit,0,1);                            //將步長取到棧頂
                            gendo(opr,0,2);                            //循環變量加步長
                            //將棧頂的值存入循環變量
                            gendo(sto,lev-table[i].level,table[i].adr); 
                            gendo(jmp,0,cx1);                 //無條件跳轉到循環開始點
                            /*回填循環結束點的地址,cx爲else後語句執行完的位置,它正是前面未定的跳轉地址*/
                            code[cx2].a=cx;                     
                         }
                         else
                         {
                            error(29);    //for語句中少了do
                         }
                    }
                }
            }
        }
    }
	else
	{
		if (sym == readsym) /* 準備按照read語句處理 */
		{
			getsymdo;
			if (sym != lparen)
			{
				error(34);  /* 格式錯誤,應是左括號 */
			}
			else
			{
			do {
				getsymdo;
				if (sym == ident)
				{
					i = position(id, *ptx); /* 查找要讀的變量 */
				}
				else
				{
					i=0;
				}
				if (i == 0)
				{
					error(35);  /* read()中應是聲明過的變量名 */
				}
				else
				{
					if (table[i].kind == constant || table[i].kind == procedur) {
						error(32);		// read()中的標識符不是變量
					}
					else {
						getsymdo;
						if (sym != lparen) {			//非數組,即變量
							gendo(opr, 0, 16);
							gen(sto, lev - table[i].level, table[i].adr);
						}
						else {		//TODO 數組
							getsymdo;
							memcpy(nxtlev, fsys, sizeof(bool) * symnum);
							nxtlev[rparen] = true;
							expressiondo(nxtlev, ptx, lev);
							int ltmp = lev - table[i].level;
							int adrtmp = table[i].adr;
							gendo(arrcheck, table[i].startid, table[i].size);
							gendo(jpc, 0, 0);
							gendo(opr, 0, 16);
							gendo(sta, ltmp, adrtmp);
							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 */
						statementdo(fsys, ptx, lev);    /* 處理then後的語句 */
						if (sym == elsesym) {
							getsymdo;
							cx2 = cx;
							gendo(jmp, 0, 0);
							code[cx1].a = cx;
							statementdo(fsys, ptx, lev);
							code[cx2].a = cx;
						}
					else {
						//以上是處理else語句
						code[cx1].a = cx;      /*經statement處理後,cx爲then後語句執行完的位置,它正是前面未定的跳轉地址*/
					}
				}
					else
					{
						if (sym == beginsym)    /* 準備按照複合語句處理 */
						{
							getsymdo;
							memcpy(nxtlev, fsys, sizeof(bool)*symnum);
							nxtlev[semicolon] = true;
							nxtlev[endsym] = true;  /* 後跟符號爲分號或end */
							/* 循環調用語句處理函數,直到下一個符號不是語句開始符號或收到end */
							statementdo(nxtlev, ptx, lev);

							while (inset(sym, statbegsys) || sym==semicolon)
							{
								if (sym == semicolon)
								{
									getsymdo;
								}
								else
								{
									error(10);  /* 缺少分號 */
								}
								statementdo(nxtlev, ptx, lev);
							}
							if(sym == endsym)
							{
								getsymdo;
							}
							else
							{
								error(17);  /* 缺少end或分號 */
							}
						}
						else
						{

							if (sym == whilesym)    /* 準備按照while語句處理 */
							{
								cx1 = cx;   /* 保存判斷條件操作的位置 */
								getsymdo;
								memcpy(nxtlev, fsys, sizeof(bool)*symnum);
								nxtlev[dosym] = true;   /* 後跟符號爲do */
								conditiondo(nxtlev, ptx, lev);  /* 調用條件處理 */
								cx2 = cx;   /* 保存循環體的結束的下一個位置 */
								gendo(jpc, 0, 0);   /* 生成條件跳轉,但跳出循環的地址未知 */
								if (sym == dosym)
								{
									getsymdo;
								}
								else
								{
									error(18);  /* 缺少do */
								}
								statementdo(fsys, ptx, lev);    /* 循環體 */
								gendo(jmp, 0, cx1); /* 回頭重新判斷條件 */
								code[cx2].a = cx;   /* 反填跳出循環的地址,與if類似 */
							}
							else
							{
								memset(nxtlev, 0, sizeof(bool)*symnum); /* 語句結束無補救集合 */
								testdo(fsys, nxtlev, 19);   /* 檢測語句結束的正確性 */
							}
						}
					}
				}
			}
		}
	}
	return 0;
}

/*
* 表達式處理
*/
int expression(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)
		{
			gendo(opr,0,1); /* 如果開頭爲負號生成取負指令 */
		}
	}
	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)
		{
			gendo(opr, 0, 2);   /* 生成加法指令 */
		}
		else
		{
			gendo(opr, 0, 3);   /* 生成減法指令 */
		}
	}
	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;
		factordo(nxtlev, ptx, lev);
		if(mulop == times)
		{
			gendo(opr, 0, 4);   /* 生成乘法指令 */
		}
		else
		{
			gendo(opr, 0, 5);   /* 生成除法指令 */
		}
	}
	return 0;
}

/*
* 因子處理
*/
int factor(bool* fsys, int* ptx, int lev)
{
	int i;
	bool nxtlev[symnum];
	testdo(facbegsys, fsys, 24);    /* 檢測因子的開始符號 */
	/* while(inset(sym, facbegsys)) */  /* 循環直到不是因子開始符號 */
	if(inset(sym,facbegsys))    /* BUG: 原來的方法var1(var2+var3)會被錯誤識別爲因子 */
	{
		if(sym == ident)    /* 因子爲常量或變量 */
		{
			i = position(id, *ptx); /* 查找名字 */
			if (i == 0)
			{
				error(11);  /* 標識符未聲明 */
			}
			else
			{
				switch (table[i].kind)
				{
				case constant:  /* 名字爲常量 */
					gendo(lit, 0, table[i].val);    /* 直接把常量的值入棧 */
					break;
				case variable:  /* 名字爲變量 */
					gendo(lod, lev-table[i].level, table[i].adr);   /* 找到變量地址並將其值入棧 */
					break;
				case procedur:  /* 名字爲過程 */
					error(21);  /* 不能爲過程 */
					break;
				case array:
					getsymdo;
					if (sym == lparen)
					{					//是數組
						int ltmp = lev - table[i].level;
						int adrtmp = table[i].adr;
						getsymdo;
						memcpy(nxtlev, fsys, sizeof(bool) * symnum);
						nxtlev[rparen] = true;
						expressiondo(nxtlev, ptx, lev);
						gendo(lda, ltmp, adrtmp);
						//getsymdo;							
					}
					if (sym == rparen)
					{
						//getsymdo;
					}
					break;
				}
			}
			getsymdo;
		}
		else
		{
			if(sym == number)   /* 因子爲數 */
			{
				if (num > amax)
				{
					error(31);
					num = 0;
				}
				gendo(lit, 0, num);
				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);  /* 缺少右括號 */
					}
				}
				testdo(fsys, facbegsys, 23);    /* 因子後有非法符號 */
			}
		}
	}
	return 0;
}

/*
* 條件處理
*/
int condition(bool* fsys, int* ptx, int lev)
{
	enum symbol relop;
	bool nxtlev[symnum];

	if(sym == oddsym)   /* 準備按照odd運算處理 */
	{
		getsymdo;
		expressiondo(fsys, ptx, lev);
		gendo(opr, 0, 6);   /* 生成odd指令 */
	}
	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:
				gendo(opr, 0, 8);
				break;
			case neq:
				gendo(opr, 0, 9);
				break;
			case lss:
				gendo(opr, 0, 10);
				break;
			case geq:
				gendo(opr, 0, 11);
				break;
			case gtr:
				gendo(opr, 0, 12);
				break;
			case leq:
				gendo(opr, 0, 13);
				break;
			}
		}
	}
	return 0;
}

/*
* 解釋程序
*/
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;
		case sta:                        // 棧頂的值存到數組下標爲a的內存
			t--;
			s[base(i.l, s, b) + i.a + s[t - 1]] = s[t];
			t--;
			break;
		case lda:
			s[t - 1] = s[base(i.l, s, b) + i.a + s[t - 1]];       //對數組的讀取 第二個S[T]是放入偏移地址的				
			break;
		case arrcheck:
			s[t] = i.a;
			if ((s[t - 1] < i.l) || (s[t - 1] > s[t] + i.l - 1))
			{
				printf("Error:Out of the array's size!\n");
				fprintf(fa2, "Error:Out of the array's size!\n");
				s[t] = 0;
			}
			else {
				s[t] = 1;
			}
			t++;
			break;
		}
	} while (p != 0);
}

/* 通過過程基址求上l層過程的基址 */
int base(int l, int* s, int b)
{
	int b1;
	b1 = b;
	while (l > 0)
	{
		b1 = s[b1];
		l--;
	}
	return b1;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章