編譯原理實驗四:語法分析程序

(一)學習經典的語法分析器(1學時)

 

實驗目的

學習已有編譯器的經典語法分析源程序。

 

實驗任務

閱讀已有編譯器的經典語法分析源程序,並測試語法分析器的輸出。

 

實驗內容

(1)選擇一個編譯器,如:TINY,其它編譯器也可(需自備源代碼)。

(2)閱讀語法分析源程序,加上你自己的理解。尤其要求對相關函數與重要變量的作用與功能進行稍微詳細的描述。若能加上學習心得則更好。TINY語言請參考《編譯原理及實踐》第3.7節。對TINY語言要特別注意抽象語法樹的定義與應用。

(3)測試語法分析器。對TINY語言要求輸出測試程序的字符形式的抽象語法樹。(手工或編程)畫出圖形形式的抽象語法樹。

TINY語言:

測試用例一:sample.tny。

 

(二)實現一門語言的語法分析器(3學時)

 

實驗目的

通過本次實驗,加深對語法分析的理解,學會編制語法分析器。

 

實驗任務

用C或C++語言編寫一門語言的語法分析器。

 

實驗內容

(1)語言確定:C-語言,其定義在《編譯原理及實踐》附錄A中。也可選擇其它語言,不過要有該語言的詳細定義(可仿照C-語言)。一旦選定,不能更改,因爲要在以後繼續實現編譯器的其它部分。鼓勵自己定義一門語言。也可選擇TINY語言,但需要使用與TINY現有語法分析代碼不同的分析算法實現,並在實驗報告中寫清原理。

(2)完成C-語言的BNF文法到EBNF文法的轉換。通過這一轉換,消除左遞歸,提取左公因子,將文法改寫爲LL(1)文法,以適用於自頂向下的語法分析。規劃需要將哪些非終結符寫成遞歸下降函數。

(3)爲每一個將要寫成遞歸下降函數的非終結符,如:變量聲明、函數聲明、語句序列、語句、表達式等,定義其抽象語法子樹的形式結構,然後定義C-語言的語法樹的數據結構。

(4)仿照前面學習的語法分析器,編寫選定語言的語法分析器。可以自行選擇使用遞歸下降、LL(0)、LR(0)、SLR、LR(1)中的任意一種方法實現。

(5)準備2~3個測試用例,測試並解釋程序的運行結果。

 

實驗通過測試後,按規定時間上交源代碼、測試樣例、輸出文件(如有輸出文件)和電子版實驗報告。

 

環境問題說明

這份代碼可能需要使用C++11標準編譯,如果你用的是Dev C++,可以參照以下辦法支持C++11標準:

https://www.cnblogs.com/decade-dnbc66/p/5351939.html

 

程序流程說明(C-的語法樹構建圖)

 

代碼實現(自頂向下方法)

#include<fstream>
#include<iostream>
#include<string.h>
#include<strstream>
using namespace std;

#define BUFLEN 256
#define MAXLEN 256
#define MAXTOKENLEN 40
#define MAXCHILDREN 4
static int lineno;
static int linepos = 0;//讀取的字符在lineBuf的位置
static int EOF_FLAG = false;
static int bufsize = 0;//lineBuf的長度
static char lineBuf[BUFLEN];
FILE * source;
char tokenString[MAXTOKENLEN + 1];
string output;//輸出文件
int flag=0; 

enum TokenType
{
	ENDFILE, ERROR,
	IF, ELSE, INT, RETURN, VOID, WHILE,
	ID, NUM,
	ASSIGN, EQ, LT, PLUS, MINUS, TIMES, OVER, LPAREN, RPAREN, SEMI, LBRACKET, RBRACKET, LBRACE, RBRACE, COMMA,
	GT, GEQ, NEQ, LEQ
};

enum StateType
{
	START, INASSIGN, INCOMMENT, INNUM, INID, DONE, PRECOMMENT, AFTERCOMMENT
};

struct
{
	char* str;
	TokenType tok;
}ReserverWords[6]
= { { "if",IF },{ "else",ELSE },{ "int",INT },{ "return",RETURN },{ "void",VOID },{ "while",WHILE } };

void UnGetNextChar()
{
	if (!EOF_FLAG)
		linepos--;
}

int GetNextChar()
{
	if (!(linepos<bufsize))
	{
		lineno++;
		if (fgets(lineBuf, BUFLEN - 1, source))
		{
			bufsize = strlen(lineBuf);
			linepos = 0;
			return lineBuf[linepos++];
		}
		else
		{
			EOF_FLAG = true;
			return EOF;
		}
	}
	else
	{
		return lineBuf[linepos++];
	}
}

TokenType ReservedLookUp(char * s)
{
	int i;
	for (i = 0; i < 6; i++)
	{
		if (!strcmp(s, ReserverWords[i].str))
		{
			return ReserverWords[i].tok;
		}
	}
	return ID;
}

TokenType GetToken()
{
	StateType state = START;//初始狀態爲start
	bool save;
	TokenType CurrentToken;
	int tokenStringIndex = 0;
	string assign = "";
	while (state != DONE)
	{
		int c = GetNextChar();
		save = true;
		switch (state)
		{
		case START:
			if (isdigit(c))
			{
				state = INNUM;
			}
			else if (isalpha(c))
			{
				state = INID;
			}
			else if ((c == '<') || (c == '>') || (c == '=') || (c == '!'))
			{
				state = INASSIGN;
				assign += char(c);
			}
			else if ((c == ' ') || (c == '\t') || (c == '\n'))
				save = false;
			else if (c == '/')
			{
				save = false;
				state = PRECOMMENT;
			}
			else
			{
				state = DONE;
				switch (c)
				{
				case EOF:
					save = false;
					CurrentToken = ENDFILE;
					break;
				case '+':
					CurrentToken = PLUS;
					break;
				case '-':
					CurrentToken = MINUS;
					break;
				case '*':
					CurrentToken = TIMES;
					break;
				case '(':
					CurrentToken = LPAREN;
					break;
				case ')':
					CurrentToken = RPAREN;
					break;
				case ';':
					CurrentToken = SEMI;
					break;
				case '[':
					CurrentToken = LBRACKET;
					break;
				case ']':
					CurrentToken = RBRACKET;
					break;
				case '{':
					CurrentToken = LBRACE;
					break;
				case '}':
					CurrentToken = RBRACE;
					break;
				case ',':
					CurrentToken = COMMA;
					break;
				default:
					CurrentToken = ERROR;
					break;
				}
			}
			break;
		case INCOMMENT:
			save = false;
			if (c == EOF)
			{
				state = DONE;
				CurrentToken = ENDFILE;
			}
			else if (c == '*')
				state = AFTERCOMMENT;
			else
			{
				state = INCOMMENT;
			}
			break;
		case INASSIGN:
			if (c == '=')
			{
				CurrentToken = EQ;
				state = DONE;
			}
			else if (assign == "!")
			{
				UnGetNextChar();
				save = false;
				CurrentToken = ERROR;
				state = DONE;
			}
			else if (assign == "=")
			{
				UnGetNextChar();
				save = false;
				CurrentToken = ASSIGN;
				state = DONE;
			}
			else if (assign == "<")
			{
				UnGetNextChar();
				save = false;
				CurrentToken = LT;
				state = DONE;
			}
			else
			{
				UnGetNextChar();
				save = false;
				CurrentToken = GT;
				state = DONE;
			}
			break;
		case INNUM:
			if (!isdigit(c))
			{
				UnGetNextChar();
				save = false;
				state = DONE;
				CurrentToken = NUM;
			}
			break;
		case INID:
			if (!isalpha(c))
			{
				UnGetNextChar();
				save = false;
				state = DONE;
				CurrentToken = ID;
			}
			break;
		case PRECOMMENT:
			if (c == '*')
			{
				state = INCOMMENT;
				save = false;
			}
			else
			{
				UnGetNextChar();
				CurrentToken = OVER;
				state = DONE;
			}
			break;
		case AFTERCOMMENT:
			save = false;
			if (c == '/')
			{
				state = START;
			}
			else if (c == '*')
			{
				state = AFTERCOMMENT;
			}
			else
			{
				state = INCOMMENT;
			}
			break;
		case DONE:
		default:
			state = DONE;
			CurrentToken = ERROR;
			break;
		}
		if ((save) && (tokenStringIndex <= MAXTOKENLEN))
		{
			tokenString[tokenStringIndex++] = (char)c;
		}
		if (state == DONE)
		{
			tokenString[tokenStringIndex] = '\0';
			if (CurrentToken == ID)
			{
				CurrentToken = ReservedLookUp(tokenString);
			}
		}
	}
	return CurrentToken;
}

enum NodeKind//節點類型
{
	FuncK, IntK, IdK, ParamsK, ParamK, CompK, ConstK, CallK, ArgsK, VoidK, Var_DeclK, Arry_DeclK, Arry_ElemK, AssignK/*,WhileK*/, OpK,
	Selection_StmtK, Iteration_StmtK, Return_StmtK
};
struct//節點類型和字符串關係
{
	string str;
	NodeKind nk;
}nodekind[18]
= { { "Funck",FuncK },{ "IntK",IntK },{ "IdK",IdK },{ "ParamsK",ParamsK },{ "ParamK",ParamK },{ "CompK",CompK },{ "ConstK",ConstK },{ "CallK",CallK },
{ "ArgsK",ArgsK },{ "VoidK",VoidK },{ "Var_DeclK",Var_DeclK },{ "Arry_DeclK",Arry_DeclK },{ "Arry_ElemK",Arry_ElemK },{ "AssignK",AssignK },
/*{"WhileK",WhileK},*/{ "OpK",OpK },{ "Selection_StmtK",Selection_StmtK },{ "Iteration_StmtK",Iteration_StmtK },{ "Return_StmtK",Return_StmtK } };

struct//符號與字符串關係
{
	string str;
	TokenType tk;
}Ope[11]
= { { "=",ASSIGN },{ "==",EQ },{ "<",LT },{ "+",PLUS },{ "-",MINUS },{ "*",TIMES },{ "/",OVER },
{ ">",GT },{ ">=",GEQ },{ "!=",NEQ },{ "<=",LEQ } };

string OpeLookUp(TokenType tk)//操作符轉換爲字符串
{
	int i;
	for (i = 0; i<11; i++)
	{
		if (tk == Ope[i].tk)
		{
			return Ope[i].str;
		}
	}
}

string Change(NodeKind nk)//節點類型轉換爲字符串
{
	int i;
	for (i = 0; i<19; i++)
	{
		if (nk == nodekind[i].nk)
		{
			return nodekind[i].str;
			break;
		}
	}
}

TokenType token;
struct TreeNode
{
	struct TreeNode *  child[4];
	struct TreeNode *  sibling;
	int lineno;
	NodeKind nodekind;
	union { TokenType op; int val; const char * name; } attr;
};

TreeNode * declaration_list(void);
TreeNode * declaration(void);
TreeNode * params(void);
TreeNode * param_list(TreeNode *p);
TreeNode * param(TreeNode *p);
TreeNode * compound_stmt(void);
TreeNode * local_declaration(void);
TreeNode * statement_list(void);
TreeNode * statement(void);
TreeNode * expression_stmt(void);
TreeNode * selection_stmt(void);
TreeNode * iteration_stmt(void);
TreeNode * return_stmt(void);
TreeNode * expression(void);
TreeNode * var(void);
TreeNode * simple_expression(TreeNode * p);
TreeNode * additive_expression(TreeNode * p);
TreeNode * term(TreeNode * p);
TreeNode * factor(TreeNode * p);
TreeNode * call(TreeNode * p);
TreeNode * args(void);

char * copyString(char *s)
{
	int n;
	char * t;
	if (s == NULL)
	{
		return NULL;
	}
	n = strlen(s) + 1;
	t = (char*)malloc(n);
	if (t == NULL) {
	}
	else
	{
		strcpy(t, s);
	}
	return t;
}

void match(TokenType expected)
{
	if (token == expected)
		token = GetToken();
	else
	{
		if(flag==0)
		flag=1;
		else
		cout << "unexpected token" << endl;
	}
}

TreeNode * newNode(NodeKind kind)
{
	TreeNode * t = (TreeNode *)malloc(sizeof(TreeNode));
	int i;
	if (t == NULL)
	{
		;
	}
	else {
		for (i = 0; i<4; i++)
		{
			t->child[i] = NULL;
		}
		t->sibling = NULL;
		t->nodekind = kind;

		t->lineno = lineno;
		if (kind == OpK || kind == IntK || kind == IdK)
		{
			if (kind == IdK)
				t->attr.name = "";
		}
		if (kind == ConstK)
			t->attr.val = 0;
	}
	return t;
}

TreeNode * declaration_list(void)	//declaration_list->declaration_list declaration | declaration
{
	TreeNode * t = declaration();	//入口一定是聲明,即所有的語句都是以聲明開始的,那麼這裏就要判斷是哪種聲明 
	TreeNode * p = t;
	while ((token != INT) && (token != VOID) && (token != ENDFILE))
	{
		token = GetToken();
		if (token == ENDFILE)
			break;
	}
	while (token == INT || token == VOID)		//待上一次遞歸下降返回後,處理下一條語句或下一個函數 
	{
		TreeNode * q;
		q = declaration();
		if (q != NULL)
		{
			if (t == NULL)
			{
				t = p = q;
			}
			else
			{
				p->sibling = q;
				p = q;
			}
		}
	}
	match(ENDFILE);		//遞歸結束 
	return t;
}

TreeNode * declaration(void)
{
	TreeNode * t = NULL;
	TreeNode * p = NULL;
	TreeNode * q = NULL;
	TreeNode * s = NULL;
	TreeNode * a = NULL;
	if (token == INT)
	{
		p = newNode(IntK);
		match(INT);
	}
	else//(token==VOID)
	{
		p = newNode(VoidK);
		match(VOID);
	}		//C-的關鍵字直接聲明只有int和void兩種 

	if (p != NULL&&token == ID)		//當然,除了直接聲明以外,還可能對於變量賦值這樣的聲明,因此給一個結點,因爲聲明也可能以變量名開頭(變量聲明過) 
	{
		q = newNode(IdK);
		q->attr.name = copyString(tokenString);		//聲明的結點需要給名字 
		match(ID);
		if (token==LPAREN)		//如果下一個是左括號,那麼就是一個函數,包含參數列表 
		{
			t = newNode(FuncK);		//那麼創建一個函數名稱的結點,之前的函數聲明和函數名稱都是其子結點 
			t->child[0] = p;		
			t->child[1] = q;

			match(LPAREN);
			t->child[2] = params();		//其子結點需要有參數列表 
			match(RPAREN);
			t->child[3] = compound_stmt();		//子結點還需要有大括號,此時進入匹配大括號的模式 
		}
		else if (token == LBRACKET)		//如果ID後面接着一個左中括號,那麼就匹配到聲明數組情況 
		{
			t = newNode(Var_DeclK);
			a = newNode(Arry_DeclK);		//創建數組結點 
			t->child[0] = p;		//數組的名稱是它的子結點 
			t->child[1] = a;
			match(LBRACKET);
			s = newNode(ConstK);
			s->attr.val = atoi(tokenString);		//結點的名稱是它的字符串的值 
			match(NUM);
			a->child[0] = q;
			a->child[1] = s;
			match(RBRACKET);
			match(SEMI);
		}
		else if (token == SEMI)
		{
			t = newNode(Var_DeclK);
			t->child[0] = p;
			t->child[1] = q;
			match(SEMI);
		}
		else
		{
			;
		}
	}
	else
	{
		;
	}
	return t;
}

TreeNode * params(void)		//params_list | void
{
	TreeNode * t = newNode(ParamsK);	//創建一個參數列表結點 
	TreeNode * p = NULL;
	if (token == VOID)		//如果函數括號裏面參數列表是VOID,那麼匹配到VOID 
	{
		p = newNode(VoidK);
		match(VOID);
		if (token == RPAREN)
		{
			if (t != NULL)
				t->child[0] = p;
		}
		else	//如果不爲空,那麼參數列表爲(void id,[……]) 
		{
			t->child[0] = param_list(p);
		}
	}
	else	//括號裏面的(token==INT)
	{
		t->child[0] = param_list(p);
	}
	return t;
}

TreeNode * param_list(TreeNode * k)		//params_list->params_list,param | param
{
	TreeNode * t = param(k);
	TreeNode * p = t;
	k = NULL;		//沒有要傳給param的VoidK,所以將k設爲NULL
	while (token == COMMA)		//參數之間需要以逗號連接,那麼需要當前字符需要匹配逗號 
	{
		TreeNode * q = NULL;
		match(COMMA);
		q = param(k);		//匹配完逗號之後需要匹配(類型和參數) 
		if (q != NULL)
		{
			if (t==NULL)
			{
				t=p=q;
			}
			else
			{
				p->sibling = q;
				p = q;
			}
		}
	}
	return t;
}

TreeNode * param(TreeNode * k) 	//para m →type - specifier ID | type - specifier ID[]
{
	TreeNode * t = newNode(ParamK);		//創建一個參數結點 
	TreeNode * p = NULL;
	TreeNode * q = NULL;
	if (k == NULL&&token == VOID)		//參數可能以VOID開頭 
	{
		p = newNode(VoidK);
		match(VOID);
	}
	else if (k == NULL&&token == INT)	//參數可以int開頭,因爲int是唯一的數據類型 
	{
		p = newNode(IntK);		//新創建一個int結點,匹配int
		match(INT);
	}
	else if (k != NULL)
	{
		p = k;
	}
	if (p != NULL)		//下面匹配參數,如果參數是ID,那麼新建ID結點,作爲數據類型結點的子結點 
	{
		t->child[0] = p;
		if (token == ID)
		{
			q = newNode(IdK);
			q->attr.name = copyString(tokenString);
			t->child[1] = q;
			match(ID);
		}
		if (token == LBRACKET && (t->child[1] != NULL))		//如果參數匹配到了左中括號,那麼參數形爲:int name[],此時,接連匹配左右中括號即可 
		{
			match(LBRACKET);
			t->child[2] = newNode(IdK);
			match(RBRACKET);
		}
		else
		{
			return t;
		}
	}
	else
	{
		;
	}
	return t;
}

TreeNode * compound_stmt(void)
{
	TreeNode * t = newNode(CompK);		//創建一個大括號結點 
	match(LBRACE);
	t->child[0] = local_declaration();		//讀取局部變量聲明 
	t->child[1] = statement_list();		//接下來的地方是各種語句的聲明,遞歸下降到下一層 
	match(RBRACE);		//直到函數結束的時候,匹配一個右大括號 
	return t;
}

TreeNode * local_declaration(void)
{
	TreeNode * t = NULL;
	TreeNode * q = NULL;
	TreeNode * p = NULL;
	while (token == INT || token == VOID)
	{
		p = newNode(Var_DeclK);
		if (token == INT)
		{
			TreeNode * q1 = newNode(IntK);
			p->child[0] = q1;
			match(INT);
		}
		else if (token == VOID)
		{
			TreeNode * q1 = newNode(VoidK);
			p->child[0] = q1;
			match(INT);
		}
		if ((p != NULL) && (token == ID))
		{
			TreeNode * q2 = newNode(IdK);
			q2->attr.name = copyString(tokenString);
			p->child[1] = q2;
			match(ID);

			if (token == LBRACKET)
			{
				TreeNode * q3 = newNode(Var_DeclK);
				p->child[3] = q3;
				match(LBRACKET);
				match(RBRACKET);
				match(SEMI);
			}
			else if (token == SEMI)
			{
				match(SEMI);
			}
			else
			{
				match(SEMI);
			}
		}

		if (p != NULL)
		{
			if (t == NULL)
				t = q = p;
			else
			{
				q->sibling = p;
				q = p;
			}
		}
	}
	return t;
}

TreeNode * statement_list(void)		//函數中的表達式語句
{
	TreeNode * t = statement();		//首先確定這是一個什麼語句,遞歸下降 
	TreeNode * p = t;
	while (IF == token || LBRACKET == token || ID == token || WHILE == token || RETURN == token || SEMI == token || LPAREN == token || NUM == token)	//待上一次遞歸完成之後,進行下一次遞歸 
	{
		TreeNode * q;
		q = statement();
		if (q != NULL)
		{
			if (t == NULL)
			{
				t = p = q;
			}
			else
			{
				p->sibling = q;
				p = q;
			}
		}
	}
	return t;
}

TreeNode * statement(void)
{
	TreeNode * t = NULL;
	switch (token)
	{
	case IF:
		t = selection_stmt();		//爲每一種語句創建一棵語法樹,這裏是判斷語句 
		break;
	case WHILE:
		t = iteration_stmt();		//循環語句 
		break;
	case RETURN:
		t = return_stmt();		//返回語句 
		break;
	case LBRACE:
		t = compound_stmt();		//匹配到了又一個大括號,那麼再重複一遍 
		break;
	case ID: case SEMI: case LPAREN: case NUM:
		t = expression_stmt();		//如果匹配到了ID、分號、左括號、數字,一律以語句處理 
		break;
	default:
		token = GetToken();
		break;
	}
	return t;
}

TreeNode * selection_stmt(void)
{
	TreeNode * t = newNode(Selection_StmtK);
	match(IF);		//if( 開頭 
	match(LPAREN);
	if (t != NULL)
	{
		t->child[0] = expression();		//其子結點是一個語句,代表判斷條件 
	}
	match(RPAREN);
	t->child[1] = statement();		//條件判斷語句結束以反括號結尾,也需要同樣考慮ELSE的情況 
	if (token == ELSE)
	{
		match(ELSE);
		if (t != NULL)
		{
			t->child[2] = statement();
		}
	}
	return t;
}

TreeNode * iteration_stmt(void)
{
	TreeNode * t = newNode(Iteration_StmtK);
	match(WHILE);
	match(LPAREN);		//創建一個循環WHILE結點,匹配到左括號,條件判斷語句,右括號 
	if (t != NULL)
	{
		t->child[0] = expression();
	}
	match(RPAREN);
	if (t != NULL)
	{
		t->child[1] = statement();
	}
	return t;
}

TreeNode * return_stmt(void)
{
	TreeNode * t = newNode(Return_StmtK);
	match(RETURN);		//匹配到return和一個語句,代表返回的東西,最後有一個分號 
	if (token == SEMI)
	{
		match(SEMI);
		return t;
	}
	else
	{
		if (t != NULL)
		{
			t->child[0] = expression();
		}
	}
	match(SEMI);
	return t;
}

TreeNode * expression_stmt(void)		//匹配一些標識符 
{
	TreeNode * t = NULL;
	if (token == SEMI)
	{
		match(SEMI);
		return t;
	}
	else
	{
		t = expression();
		match(SEMI);
	}
	return t;
}

TreeNode * expression(void)
{
	TreeNode * t = var();
	if (t == NULL)		//不是以ID開頭,只能是simple_expression情況
	{
		t = simple_expression(t);
	}
	else	//以ID開頭,可能是賦值語句,或simple_expression中的var和call類型的情況
	{
		TreeNode * p = NULL;
		if (token == ASSIGN)//賦值語句
		{
			p = newNode(AssignK);
			match(ASSIGN);
			p->child[0] = t;
			p->child[1] = expression();
			return p;
		}
		else 	//simple_expression中的var和call類型的情況
		{
			t = simple_expression(t);
		}
	}
	return t;
}

TreeNode * var(void)
{
	TreeNode * t = NULL;
	TreeNode * p = NULL;
	TreeNode * q = NULL;
	if (token == ID)
	{
		p = newNode(IdK);
		p->attr.name = copyString(tokenString);
		match(ID);
		if (token == LBRACKET)
		{
			match(LBRACKET);
			q = expression();
			match(RBRACKET);

			t = newNode(Arry_ElemK);
			t->child[0] = p;
			t->child[1] = q;
		}
		else
		{
			t = p;
		}
	}
	return t;
}

TreeNode * simple_expression(TreeNode * k)
{
	TreeNode * t = additive_expression(k);		//先匹配加減法運算,因爲先計算乘除再加減,而方法爲自頂向下,因此加減法先被匹配,乘除法後匹配先計算 
	k = NULL;
	if (EQ == token || GT == token || GEQ == token || LT == token || LEQ == token || NEQ == token)		//匹配一些簡單表達式,比如等於、大於、小於這些 
	{
		TreeNode * q = newNode(OpK);
		q->attr.op = token;
		q->child[0] = t;
		t = q;
		match(token);		//匹配兩個運算式子,作爲符號的子結點 
		t->child[1] = additive_expression(k);		//匹配乘除法 
		return t;
	}
	return t;
}

TreeNode * additive_expression(TreeNode * k)
{
	TreeNode * t = term(k);
	k = NULL;
	while ((token == PLUS) || (token == MINUS))		//匹配乘除法,並將兩邊的參與運算的數字作爲符號的子結點 
	{
		TreeNode * q = newNode(OpK);
		q->attr.op = token;
		q->child[0] = t;
		match(token);
		q->child[1] = term(k);
		t = q;
	}
	return t;
}

TreeNode * term(TreeNode * k)		//最後,匹配數字或參數 
{
	TreeNode * t = factor(k);
	k = NULL;
	while ((token == TIMES) || (token == OVER))		//乘除法 
	{
		TreeNode * q = newNode(OpK);
		q->attr.op = token;
		q->child[0] = t;
		t = q;
		match(token);
		q->child[1] = factor(k);		//匹配數字的值或變量 
	}
	return t;
}

TreeNode * factor(TreeNode * k)
{
	TreeNode * t = NULL;
	if (k != NULL)	//k爲上面傳下來的已經解析出來的以ID開頭的var,可能爲call或var
	{
		if (token == LPAREN && k->nodekind != Arry_ElemK) //call
		{
			t = call(k);	//如果表達式裏面出現了括號,那麼肯定是函數的調用 
		}
		else
		{
			t = k;
		}
	}
	else	//沒有從上面傳下來的var
	{
		switch (token)
		{
		case LPAREN:
			match(LPAREN);
			t = expression();
			match(RPAREN);
			break;
		case ID:
			k = var();
			if (LPAREN == token && k->nodekind != Arry_ElemK)
			{
				t = call(k);
			}
			else	//如果是連續計算,進入這一步
			{
				t = k;
			}
			break;
		case NUM:
			t = newNode(ConstK);
			if ((t != NULL) && (token == NUM))
			{
				t->attr.val = atoi(tokenString);
			}
			match(NUM);
			break;
		default:
			token = GetToken();
			break;
		}
	}
	return t;
}

TreeNode * call(TreeNode * k)
{
	TreeNode * t = newNode(CallK);		//創建一個call函數的結點,匹配左右括號和參數 
	if (k != NULL)
		t->child[0] = k;
	match(LPAREN);
	if (token == RPAREN)
	{
		match(RPAREN);
		return t;
	}
	else if (k != NULL)
	{
		t->child[1] = args();		//如果存在參數,還需要匹配參數 
		match(RPAREN);
	}
	return t;
}

TreeNode * args(void)
{
	TreeNode * t = newNode(ArgsK);
	TreeNode * s = NULL;
	TreeNode * p = NULL;
	if (token != RPAREN)
	{
		s = expression();
		p = s;
		while (token == COMMA)
		{
			TreeNode * q;
			match(COMMA);
			q = expression();
			if (q != NULL)
			{
				if (s == NULL)
				{
					s = p = q;
				}
				else
				{
					p->sibling = q;
					p = q;
				}
			}
		}
	}
	if (s != NULL)
	{
		t->child[0] = s;
	}
	return t;
}

int blank_number = 0;
void PreOrder(TreeNode* t)
{
	string blank = "   ";
	int i;
	for (i = 0; i<blank_number; i++)
	{
		blank += "   ";
	}
	if (t != NULL)
	{
		if (t->nodekind == OpK)
		{
			cout << blank << "Op: " << OpeLookUp(t->attr.op) << endl;
			output += blank + "Op: " + OpeLookUp(t->attr.op) + "\n";
		}
		else if (t->nodekind == IdK)
		{
			cout << blank << Change(t->nodekind) << ": " << t->attr.name << endl;
			output += blank + Change(t->nodekind) + ": " + t->attr.name + "\n";
		}
		else if (t->nodekind == ConstK)
		{
			cout << blank << Change(t->nodekind) << ": " << t->attr.val << endl;
			int n = t->attr.val;
			strstream ss;
			string s;
			ss << n;
			ss >> s;
			output += blank + Change(t->nodekind) + ": " + s + "\n";
		}
		else if (t->nodekind == AssignK)
		{
			cout << blank << "Assign" << endl;
			output += blank + "Assign" + "\n";
		}
		else if (t->nodekind == Selection_StmtK)
		{
			cout << blank << "If" << endl;
			output += blank + "If" + "\n";
		}
		else if (t->nodekind == Iteration_StmtK)
		{
			cout << blank << "While" << endl;
			output += blank + "While" + "\n";
		}
		else if (t->nodekind == Return_StmtK)
		{
			cout << blank << "Return" << endl;
			output += blank + "Return" + "\n";
		}
		else
		{
			cout << blank << Change(t->nodekind) << endl;
			output += blank + Change(t->nodekind) + "\n";
		}
	}
	for (i = 0; i<MAXCHILDREN; i++)
	{
		if (t->child[i] != NULL)
		{
			blank_number += 2;
			PreOrder(t->child[i]);
			blank_number -= 2;
		}
	}
	if (t->sibling != NULL)
	{
		PreOrder(t->sibling);
	}
}

void parse(void)
{
	TreeNode *t;	//t是一個根結點 
	cout<<"Syntax tree:"<<endl;
	token = GetToken();
	t = declaration_list();
	PreOrder(t);	//從根結點打印語法樹 
}

int main()
{
	char* file = (char *)malloc(100);//打開的文件名
	string result;//輸出結果文件名
	cout << "please input filename:" << endl;
	scanf("%s", file);
	while((source=fopen(file, "r")) == NULL) {}

		//cout <<"please input outputfile name:"<<endl;
		//scanf("%s", file);
	ofstream write;//輸出文件
	result = string(file)+"-Result.txt";
	write.open(result);
	write<<"Syntax tree:"<<endl;
	parse();
	write<<output;
	write.close();
}

 

發佈了35 篇原創文章 · 獲贊 43 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章