(一)學習經典的語法分析器(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();
}