實現一個C++實現的拓展C0文法MIPS交叉編譯器


本文禁止任何爬蟲爬取!來源:http://www.cnblogs.com/sciencefans/

學期終於結束了~這學期學習了編譯原理,同時做了北航最高難度的編譯課程設計——設計實現一個拓展C0文法的編譯器。

那么接下來貼一下編譯器設計的設計和實現細節吧。

本文將介紹一個小型編譯系統的實現,通過作者在兩個月的課程設計中總結出來的一些經驗接地氣地講一講如何一步一步構建一個編譯器,詳盡的說明其中的很多困難,以及作者是如何一步一步解決他們的。讓擁有很少編程經驗的同學也能夠有所收獲。

本系統實現了一個以擴充C0文法為輸入語言的采用C++語言和面向過程的思路設計的編譯器,采用遞歸子程序的方法來設計分析過程。可以生成符合MIPS指令集規范的匯編代碼,用MARS匯編可生成32位應用程序。

本系統考慮到不同MIPS模擬器的功能和使用方法的差異,以及用戶手工鍵入匯編,多有不便,本系統采用了在windows,Linux和mac系統下均可是用的Mars simulator作為模擬工具。

課程設計一發下來,只有一個PPT,一個文檔樣例,一個需求說明和三種難度的文法。沒有任何的指導手冊和講解,完全要靠自己啦~

畢竟初生牛犢不怕虎,習慣性地選擇了高難度。點開之后發現居然有四十多條文法,很多還是復合文法。感覺有些復雜,再加上這種比較大的工程如果一開始沒有設計好到最后會非常痛苦,所以即使有一些設計的想法在證明完備之前也一時不敢下手。

后來去圖書館查閱了一些相關的書籍,發現不論是C,Pascal還是Fortran,都是遵循詞法分析->一種語法語義分析的方法->轉換為中間代碼->生成機器指令並鏈接這樣的步驟來的,感覺如果自己這樣也應該不會有什么大錯,於是就從詞法分析開始寫起。

剛開始寫lax的時候感覺不就是一個狀態比較多的自動機么,於是就很快設計了一個NFA,結果發現光有NFA是遠遠不行滴,因為存在很多的不確定分支。於是重新翻課本,按照課本上的方法確定花最小化成DFA然后代碼實現之后寫完了。比如舉一個簡單的例子,首先我們看下面的NFA,它是從一組詞法分析所用的正則表達式轉換而來的。這個NFA合並了IF、ID、NUM、error這四個單詞的NFA。因此,它的四個接受狀態分別代表遇到了四種不同的單詞。

clip_image002

設計好之后因為它包含很多的不確定分支和ε,所以需要做一次NFA->DFA的確定化。按照課本上的方法,用ε-閉包的方法就求得了一個DFA,用上圖的例子,我們可以得到如下DFA,可以證明這個DFA和上圖中的NFA是等價的。

clip_image002[5]

之后,可以采用直接狀態機的編碼方式來編寫,也可以采用逐步判斷分支的方式來編寫,我采用的是后者,在程序中可以清晰的看見。

在編寫的過程中也沒有遇到太多困難,我覺得其中值得一提的就是預讀行緩沖這個部分了。記得在做這個實驗之前就已經閱讀了pl0編譯器的源碼,它也采用了行緩沖技術。當時在閱讀源碼的時候還感覺很奇怪,從小文件里讀字符何必要采用這種十來個byte的buffer緩沖技術呢,當我自己實現的時候我才意識到它的重要性。在出錯處理的時候,需要用到它來記錄定位出錯的位置,此外,在閱讀需要回溯的個別文法的時候比如定義變量和定義函數具有相同的前三個詞型,這時當判斷出了是哪一類的時候需要回溯處理(雖然改寫了文法消除了回溯但是回溯會使得程序更加好寫,且並不會增加太多效率負擔),行緩沖技術在這里就派上用場了,他可以直接讀取前幾個字符,而不需要再對文件指針進行處理。

詞法分析第二個值得一提的就是對於常數的處理了。有些同學采用讀取有符號常數的方法,比如“-123”會被當做一個詞語讀入。但是我覺得這樣會導致在語法分析中的極大不便。比如在處理“—123”,“+-123”等這種語句的時候會非常麻煩。於是我將常熟前面的符號都提出來,分別當成兩個單詞讀入,這在后面的語法分析的過程中證明了這是一個非常好的設計選擇。

詞法分析之后就該寫語法分語義分析了。因為是自己開發能,本着能用即可的原則,我才用了最好用程序實現的遞歸子程序的方法。也稱為遞歸下降法,這是一種適合手寫語法編譯器的方法,且非常簡單。遞歸下降法對語言所用的文法有一些限制,但遞歸下降是現階段主流的語法分析方法,因為它可以由開發人員高度控制,在提供錯誤信息方面也很有優勢。就連微軟C#官方的編譯器也是手寫而成的遞歸下降語法分析器。使用遞歸下降法編寫語法分析器無需任何類庫,編寫簡單的分析器時甚至連前面學習的詞法分析庫都無需使用。

我思考了一下語法分析的過程,聯想起課堂上老師講的LL分析法,LR分析法等,感覺每種文法都要有自己的條件,那么我所選到的文法是否符合這個條件呢?這是我當時遇到的難題。盡管當時老師說使用這個方法是問題不大的,頂多需要改一點點文法,但是仍然想自己證明一下放置到最后出現文法不匹配的問題。因為是上下文無關的文法,首先必須要通過超前查看進行分支預測。支持遞歸下降的文法,必須能通過從左往右超前查看k個字符決定采用哪一個產生式。書上稱這種文法為LL(k)文法。這里的超前閱讀正是使用了之前我所說的行緩沖技術才能達到這一點,否則直接面向文件操作,一旦涉及到回溯會非常痛苦。這個名字中第一個L表示從左往右掃描字符串,其實就是在行緩沖中進行掃描,這一點可以從我的編譯程序中的nnum變量從0開始遞增的特性看出來;而第二個L表示最左推導,對於每一個產生式都要從左往右開始分析即可。但是僅僅滿足這個是不一定能夠使用遞歸下降分析的。比如如下這個文法:

F → ( E )

E → F * F

E → F / F

當編寫非終結符E的解析方法時,需要在兩個E產生式中進行分支預測。然而兩個E產生式都以F開頭,而且F本身又可能是任意長的表達式,無論超前查看多少字符,都無法判定到底應該用乘號的產生式還是除號的產生式。遇到這種情況,我們可以用提取左公因式的方法,將它轉化為LL(k)的文法。

我所抽到的文法中不包含左遞歸問題,但是包含回溯問題,通過稍微改寫文法和一些程序上的技巧就輕松解決了,這並不是什么問題。

因為我采用的是一遍掃描的方式,所以在語法分析的時候會同時進行超前一個單詞的詞法分析以及和語法分析相同位置的語義分析。

語言語義,就是這段代碼實際的含義。編程語言的代碼必須有絕對明確的含義,這樣人們才能讓程序做自己想做的事情,在語義不通的情況下需要及時報錯。比如最簡單的一行代碼:a = 1; 它的語義是“將32位整型常量存儲到變量a中”。首先我們對“1”有明確的定義,它是32位有符號整型字面量,這里“32位有符號整型”就是表達式“1”的類型。其次,這句話成為合法的編程語言,32位整型常量必須能夠隱式轉換為a的類型。假設a就是int型變量,那么這條語句就直接將1存儲到a所在內存里。如果a是浮點數類型的,那么這句話就隱含着將整型常量1轉換為浮點類型的步驟。在語義分析中,類型檢查是貫穿始終的一個步驟。類型檢查要做到判定每一個表達式的聲明類型,判定每一個字段、形式參數、變量聲明的類型,判斷每一次賦值、傳參數時,是否存在合法的隱式類型轉換,判斷一元和二元運算符左右兩側的類型是否合法(比如+不就不能在bool和int之間進行,但是我得到的問法只包含CHAR和INT這兩個類型,所以暫時不用考慮這個問題)。

在語義分析中,符號表和四元式也相繼建立起來。

符號表設計是一個很頭疼的事情,因為又涉及到一時設計終身受用或者一時馬虎終身麻煩的那個關鍵的“一時”這個階段。最開始我的設計里只有變量名,類型,值和地址這幾個項目。到后來發現在處理函數參數的時候如果不能知道函數定義的參數是多少個,是很難判斷函數參數是否正確的,以及在數組定義和使用的過程中很難知道這個變量名是不是數組名,如果是數組名的話那么這個數組應該有多大,引用的時候是否越界等。這時候這些信息從哪來呢?只能從符號表來了。於是又硬生生的給符號表加上了“isVector”、“para”這樣的字段,分別表示是否是數組以及數組元素數量、函數參數數量這樣的信息。每次定義函數和數組的時候填入這兩個字段,之后只需要查詢就完美解決了上述問題。

出錯處理部分:這個部分是我覺得最繁雜的一個部分了。因為在不同的地方出錯,跳讀的區間是不同的。所以需要慢慢磨。但是由於技術性較低,所以花了一些時間就搞定了,復雜但不難。

四元式的設計:原以為四元式的設計會比較難,因為對這方面並沒有太多了解,但是直到寫的時候才發現並不是很難。四元式設計我總結出來需要注意兩點:1.一定要設計成上下文無關的四元式,否則轉匯編的時候會非常的麻煩;2.數組操作一定要小心。為了給數組賦值我專門創造了一個運算符”[]=, var1, var2, var3”, 它代表VAR1[VAR2] = VAR3。此外還設計了一個“GETA, VAR1, VAR2, VAR3”來表示var3 = VAR1[VAR2],這樣就完美的解決了數組操作的問題。

       再往后就是轉成匯編了。這一塊兒存在一些難點。

       首先我就在運行棧的設計上卡殼了。因為我並不想把全局變量存在data段上,雖然C采用了這種設計但是我仍然覺得不夠“美”。於是我就把全局變量塞到運行棧的棧底區域。但是這就帶來一個問題——如何給這些常量變量定位?這個問題也同樣存在於之后的函數中的變量常量定位。在臨時符號表中不能存出絕對地址,因為我們無法預測在運行的時候運行棧內是怎樣的。其實一開始我確實寫的是絕對地址…后來我發現這個問題的時候只好全部重新來過,建立用了一個臨時符號表來存儲變量的相對地址。這樣一來變得簡單多了——每個函數內的變量常量個數在編譯的時候就已經確定好了。於是完全可以用相對於函數起始位置的地址來表示變量的地址。當要對變量進行讀寫操作的時候只需要將它的相對地址addr進行如下操作就是它的絕對地址:addr($fp)。

       但是第一個問題依舊存在——在任何時候都能訪問的全局變量該怎么算地址呢?在這里我做了一個小trick,把整個棧底的基地址寫在了$t9中,由於T9這個寄存器在我的設計中是不會用到的,所以這樣$t9就相當於一個全局FP一樣,其中的全局變量和常量都用相對於$t9的相對偏移作為地址存儲,這樣就完美的解決了變量常量的存儲問題。

最后就是優化部分了。我才用了DAG消除公共子表達式,窺孔優化,消除死代碼,以及引用計數和FIFO的寄存器分配策略。這些寫起來都還挺快的。唯一需要說的就是消除共公共子表達式了。課本用了一個啟發式算法求解,但是經過我的大量測試發現很多情況是不適用的。比如當整個圖中沒有父節點的點有很多的時候,通常采用最左或者隨機選點的方式。但是這樣冥想是不正確的,因為當一個點所代表的變量是父節點之一,而這個變量在改變之前又被別的節點調用做子節點,這時就會出現使用修改后的數據這一現象的產生。舉一個最簡單的例子:C=A, A=B, B=C,在到處過程中C有可能寫入了A的新數據,而不是A0。為此我自己寫了一個可證正確性的算法:

  1. 通過掃描基本塊,由上向下找出有相同的op(對應DAG圖中的父節點),var1(對應DAG圖中的左子節點),var2(對應DAG圖中的右子節點)且var3為臨時變量的四元式對(A, B);
  2. 從B向下繼續掃描四元式,尋找所有與B具有相同var3的四元式C1,C2,…;
  3. 將Ci的var3置為A.var3;
  4. 刪除B,將B之后的四元式前移。

正確性證明:

              對於任意在語法分析過程中定義的臨時變量$_ti(詳見syn.cpp),均有如下定理:$_ti僅會出現在之后四元式的var1和var2位置,永不會被修改

                   因此我們無需擔心DAG圖中會出現臨時變量重定義的情況。

                   因此,一旦出現任意兩個臨時變量有相同的子表達式,完全可以用其中一個代替全部。因此以上算法正確。

至此,整個編譯器就已經實現了。

接下來說說具體實現:

 

1.我所收到的文發如下:

C0文法-數組-無實型-高級

1.<加法運算符> ::= +|-

定義加減法運算符

例子:3+4 a+b 3+a

2.<乘法運算符> ::= *|/

定義乘除法運算符

例子:1/2 a/2 a/b

3.<關系運算符> ::= <|<=|>|>=|!=|==

定義關系運算符

例子:1<2 a>=3 b!=8

4.<字母> ::= _|a|...|z|A|...|Z

定義字母可以為大小寫字母或者下划線

例子:_ a B

5.<數字> ::= 0|<非零數字>

定義數字為0~9的單位數字字符

例子: 0 1 8

6.<非零數字> ::= 1|...|9

定義非零數字為1~9的單位數字字符

例子: 1 8

7.<字符> ::= '<加法運算符>'|'<乘法運算符>'|'<字母>'|'<數字>'

定義字符為以單引號開始和結束,其間有且僅有一個字符。

例子: '+' '/' 'a' '8'

8.<字符串> ::= "{十進制編碼為32,33,35-126的ASCII字符}"

定義字符串可以為0個,1個,或多個十進制編碼為32,33,35-126的ASCII字符

需要注意的是不包括雙引號,但是包括空格

字符串的第一個和最后一個字符為雙引號

例子:"hello, world~"

9.<程序> ::= [<常量說明>][<變量說明>]{<有返回值函數定義>|<無返回值函數定義>}<主函數>

定義程序。

限定程序的子成分順序,必須為常量說明在前,然后是變量說明,以上兩者均可沒有。

然后是有返回或者無返回的函數定義若干(可以是0個),然后才是主函數

例子: const int a = 3;

int b = 4;

void f(int a);

int f2();

void main(){...}

10.<常量說明> ::= const<常量定義>;{ const<常量定義>;}

定義常量說明可以是一個或者多個const<常量定義>;這樣的格式

例子: const int a = 2;

const char c = 'b';

11.<常量定義> ::= int<標識符>=<整數>{,<標識符>=<整數>} | char<標識符>=<字符>{,<標識符>=<字符>}

定義常量定義可以是整型常量或者字符型常量

整型常量的定義格式是int后跟一個或多個<標識符>=<整數>的形式,之間用逗號隔開

字符型常量同理

例子: int a = 2;

char b = 'b';

12.<無符號整數> ::= <非零數字>{<數字>}

定義無符號整數的開頭必為非零數字,其后可跟若干個數字

該限定表明以0開頭的數字串不屬於無符號整數

0就不是無符號整數

例子: 1 99

13.<整數> ::= [+|-]<無符號整數>|0

定義整數是以可省略的正負號開頭,后跟無符號整數或者0的字符串

例子: 0 1 3

14.<標識符> ::= <字母>{<字母>|<數字>}

定義標志符是必須由字母為開頭,后跟0到多個字母或者數字的字符串

15.<聲明頭部> ::= int<標識符> | char<標識符>

定義聲明頭部

16.<變量說明> ::= <變量定義>;{<變量定義>;}

定義變量說明為一個或多個變量定義和分號組成的字符串

17.<變量定義> ::= <類型標識符>(<標識符>|<標識符>‘[’<無符號整數>‘]’){,(<標識符>|<標識符>‘[’<無符號整數>‘]’ )}

定義變量定義,變量可以為一個標志符或者由標志符為起始的數組形式。

例子: int a2bc_d

int word[10]

但是不能如下定義:

int 34dfn

int word[-1]

18.<類型標識符> ::= int | char

定義類型標識符為整數和字符這兩種

19.<有返回值函數定義> ::= <聲明頭部>‘(’<參數>‘)’ ‘{’<復合語句>‘}’

定義有返回值函數。必須包含頭聲明頭部,參數和復合語句以及必要的括號

例子: int f(char a){

...

...

}

char f(char a){

...

...

}

20.<無返回值函數定義> ::= void<標識符>‘(’<參數>‘)’ ‘{’<復合語句>‘}’

沒啥好說的。

例子: void f(char a){

...

...

}

21.<復合語句> ::= [<常量說明>][<變量說明>]<語句列>

定義復合語句是現場兩再變量再語句的順序。

例子: const int a = 2;

char b = '4';

...

22.<參數> ::= <參數表>

。。。

23.<參數表> ::= <類型標識符><標識符>{,<類型標識符><標識符>}| <空>

參數表由若干個類型標識符和標志符的集合組成,其間用逗號隔開。可以為空。

類型標識符和標志符的順序不能反。

需要注意的事不能有數組形式

例如: int a, char b, int c,

24.<主函數> ::= void main ‘(’ ‘)’ ‘{’<復合語句>‘}’

例子: void main() {

...

}

25.<表達式> ::= [+|-]<項>{<加法運算符><項>}

表達式是由可省略的+-開頭的若干個由加法運算符連接的項的字符串

例如: 3*4+2/6-4*a

26.<項> ::= <因子>{<乘法運算符><因子>}

項是由乘法運算符連接的一個或多個因子

例如: 4*b*a

13*6*num[15]

27.<因子> ::= <標識符>|<標識符>‘[’<表達式>‘]’|<整數>|<字符>|<有返回值函數調用語句>|‘(’<表達式>‘)’

因子是由標志符或標志符后跟方括號括起來的表達式或整數或者字符或者有返回值得函數調用語句或以圓括號括起來的表達式

例如: num[15]

num[a]

a

4

(3*13+5*a-2/f)

28.<語句> ::= <條件語句>|<循環語句>|‘{’<語句列>‘}’|<有返回值函數調用語句>;

|<無返回值函數調用語句>;|<賦值語句>;|<讀語句>;|<寫語句>;|<空>;|<返回語句>;

29.<賦值語句> ::= <標識符>=<表達式>|<標識符>‘[’<表達式>‘]’=<表達式>

例如: a[3] = 4

b = 5

30.<條件語句> ::= if ‘(’<條件>‘)’<語句>[else<語句>]

例如: if(a > b){

a = 1;

b = 2;

}

31.<條件> ::= <表達式><關系運算符><表達式>|<表達式>

表達式為0條件為假,否則為真,值得注意的是一個條件中只有一個關系運算符,不支持嵌套

例如:

1&2 a&b a 0 1

32.<循環語句> ::= while ‘(’<條件>‘)’<語句>| for‘(’<標識符>=<表達式>;<條件>;<標識符>=<標識符>(+|-)<步長>‘)’<語句>

循環語句具有如下形式:

while(...){

...

}

for(...;...;...){

...

}

其中大括號有時可省略

for的括號中各類型元素不能省略也不能亂位。

33.<步長> ::= <非零數字>{<數字>}

步長為以非零數字開始數字串

形式和無符號整數類似

34.<有返回值函數調用語句> ::= <標識符>‘(’<值參數表>‘)’

例如: f(2, 3)

35.<無返回值函數調用語句> ::= <標識符>‘(’<值參數表>‘)’

同上

36.<值參數表> ::= <表達式>{,<表達式>}|<空>

值參數表是若干個(包括0)表達式的集合

37.<語句列> ::= {<語句>}

語句列是若干(包括0)個連續語句的集合

38.<讀語句> ::= scanf ‘(’<標識符>{,<標識符>}‘)’

定義讀語句是以scanf起始,后接圓括號闊起來的一個或多個以逗號隔開的標識符。

例子: scanf(a, b)

39.<寫語句> ::= printf ‘(’<字符串>,<表達式>‘)’| printf ‘(’<字符串>‘)’| printf ‘(’<表達式>‘)’

定義寫語句是以printf為起始的,后接圓括號括起來的字符串或表達式或者兩者都有,若兩者都存在,則字符串在先,以逗號隔開。

例子: printf("%d", a)

printf(a)

printf("Hello, compilier!\n")

40.<返回語句> ::= return[‘(’<表達式>‘)’]

返回語句是以return開始,后接可有可無的以圓括號包圍的表達式

例子: return 0

  

2.目標代碼說明

目標代碼選擇為32位MIPS指令集,輸出的MIPS匯編程序的后綴名為.s,可以直接在MARS, PCSpim等虛擬機上運行。目標代碼生成程序的輸入為中間代碼生成的DAG圖,才用DAG圖節點生成的順序將各個節點依次翻譯為MIPS匯編代碼。

指令

示例

語義

系統調用

syscall

 

取立即數

Li $s1, 100

$s1 = 100

Add $s1,$s2,$s3

$s3=$s1+$s2

立即數加

Addi $s1,$s2,100

$s3=$s1+100

立即數減

Subi $s1,$s2,100

$s3=$s1-100

sub $s1,$s2,$s3

$s3=$s1-$s2

mult $s2,$s3

Hi,Lo=$s2*$s3

div $s2,$s3

Lo=$s2/$s3

Hi=$s2 Mod $s3

取字

Lw $s1,100($s2)

$s1=memory[$s2+100]

存字

sw $s1,100($s2)

memory[$s2+100]=$s1

Beq

beq $s1,$s2,100

If($s1==$s2) goto PC+4+400

Bne

beq $s1,$s2,100

If($s1!=$s2) goto PC+4+400

Slt

slt $s1,$s2, $s3

If($s2<$s3) $s1=1;

Else $s1=0;

j

J 2000

Goto 8000

jr

Ja $ra

Goto $ra

jal

Jal 2500

$ra=PC+4;

Goto 10000;

3. 優化方案*

1.消除局部公共子表達式

2.常數合並(窺孔優化)

3.消除死代碼

4.刪除冗余跳轉代碼

5.通過引用計數和FIFO策略的寄存器分配方案

二.詳細設計

1.程序結構

如下圖所示

共有七個文件(綠色塊表示)。

其中六個功能塊分別進行詞法分析,語法分析和語義分析,生成中間代碼,生成匯編指令,出錯處理和優化。

上圖中省略的函數和方法包括:

Lax.cpp:

Syn.cpp:

Midcode:

2.類/方法/函數功能

image

函數功能見上圖。

所有函數:

函數名

作用和功能

詞法分析:

void getch();

獲取一個字符

int getsym();

獲取一個詞語

語法分析:

void program();

程序遞歸子程序

void defhead();

定義頭部遞歸子程序

void varstate();

變量聲明遞歸子程序

void vardef();

變量定義遞歸子程序

void constdef(int tclass);

常量定義遞歸子程序

void conststate();

常量聲明遞歸子程序

void sentencelist();

語句列遞歸子程序

void complexsentence();

復雜語句遞歸子程序

void sentence();

語句遞歸子程序

void condition();

條件遞歸子程序

void loopsentence();

循環語句遞歸子程序

void valueofpara();

值參數表遞歸子程序

void scanfsentence();

讀語句遞歸子程序

void printfsentence();

寫語句遞歸子程序

void parametertable();

參數表遞歸子程序

void returnsentence();

返回語句遞歸子程序

void expression();

表達式遞歸子程序

void item();

項遞歸子程序

void factor();

因子遞歸子程序

中間代碼:

void insmidcode(char* op, char* t1, char* t2, char* t3);

插入中間代碼

void insmidcode(char* op, int t1, int t2, char* t3);

void insmidcode(char* op, char t1, int t2, char* t3);

char* nextlab();

返回下一個label名

char* nextvar();

返回下一個臨時變量名

匯編相關:

void midcode2asm();

中間代碼轉匯編

int findvartable(char *name);

在變量表中查找

void midcode2asm();

中間代碼轉匯編

void insertaddress(int kind, int addr = -1, int nmi = -1);

向變量表中插入一個變量和地址

void pushstack(char* item = "0", int lenth = 1);

壓棧lenth*4個字節

void funcasm();

開始函數定義

int varaddr(char *name);

求變量的相對fp的地址

void dataseg();

數據段

void jmpasm();

跳轉

void printint();

寫一個整數語句

void callasm();

調用函數

void setlabasm();

放置標簽

void addasm();

四則運算

void subasm();

void mulasm();

void divasm();

void greasm();

比較運算

void geqasm();

void lssasm();

void leqasm();

void eqlasm();

void neqasm();

void assasm();

變量賦值語句

void aassasm();

包含數組元素的操作

void assaasm();

void scfasm();

讀語句

void prtasm();

寫語句

void fupaasm();

填入參數語句

void retasm();

函數返回

void paraasm();

參數聲明處理

void jneasm();

否定則跳轉

void intcharasm();

變量定義語句

void constdefasm();

常亮定義語句

void intcharaasm();

變量定義語句

3.調用依賴關系

image


如圖所示。

4.符號表管理方案
 1 typedef struct{
 2 
 3 char name[ MAXIDENLEN ]; //identifier name
 4 
 5 int kind; //identifier kind (define as follow)
 6 
 7 int value; //1對於函數來說,表示返回值為Int 0返回值為void
 8 
 9 int address; //address
10 
11 int paranum; //
12 
13 }symb;
14 
15 #define CONST 0 //常亮
16 
17 #define VARIABLE 1 //變量
18 
19 #define FUNCTION 2 //函數
20 
21 #define PARA 3 //參數
22 
23 typedef struct {
24 
25 symb element[ MAXSYMTABLENUM ];
26 
27 int index;
28 
29 int ftotal; //分程序總數
30 
31 int findextable[ MAXSYMTABLENUM ];//分程序索引數組
32 
33 }symtable;
34 
35 extern symtable maintable;

 

符號管理結構由一張符號表,分程序總數,分程序索引數組和符號表棧頂指針構成。

其中符號表含有名稱,類型,值,地址和參數個數這幾個屬性。

其代表的含義如下所示:

表項

含義

名稱

符號的名稱,如name, functiona, para1

類型

CONST 0 //常亮

VARIABLE 1 //變量

FUNCTION 2 //函數

PARA 3 //參數

存儲常量的值

地址

存儲這個變量在符號表里的地址

參數個數

表示函數的參數個數

表示數組的元素數量

5.存儲分配方案

1.存儲方式:采用引用計數算法進行寄存器分配

2.運行棧結構:

如下圖所示:

image

6. 解釋執行程序*

本編譯器不采用解釋執行方式。

7. 四元式設計*

四元式種類

代表的含義

= , 2 , , temp

temp = 2;

[]= , a , i , t

a[i] = t;

int , , , a

int a;

const,int,5 , a

const int a = 5;

char, , 30, a

char a[30];

fupa, , , a

a is a function parameter

call, f , , a

a = f()

call, f , ,

f()

<=.., a , b ,

a <= b

jne , , , lable

if not satisfy(==false) then jump

jmp , , , label

jump to label

lab:, , , labx

set label

geta, a , n , b

b = a[n]

ret , , , (a)

return a / return

prt , a , b , symb

print("a", b)

scf , , , a

scanf(a)

func,int, , f

start of function int f()

para,int, , a

f(int a, ...)

end , , , f

end of function f

8. 優化方案*
0.划分基本快:

很明顯,在本設計中,有關影響數據的操作只有以+, -, *, /, []=為operation的語句。所以我們只需要不斷讀取以這些符號為開頭的連續四元式規約為同一基本塊即可。

1.窺孔優化:

通過窺孔優化合並常數。

不斷讀取四元式,一旦發現有常數運算的立即變為賦值操作。

2.消除公共子表達式(書上算法有誤,自創算法):

課本上DAG圖算法的漏洞:由於課本上的通過構造DAG圖消除公共子表達式的啟發式算法存在明顯問題,當有多個變量沒有父節點時,啟發式算法中進入隊列的順序將會直接影響結果。一旦進入隊列順序不正確,將會導致導出的代碼使用了錯誤的節點變量。

因此,我在這里提出一個新的可證明正確性的算法:

新算法:

1. 通過掃描基本塊,由上向下找出有相同的op(對應DAG圖中的父節點),var1(對應DAG圖中的左子節點),var2(對應DAG圖中的右子節點)且var3為臨時變量的四元式對(A, B);

2. 從B向下繼續掃描四元式,尋找所有與B具有相同var3的四元式C1,C2,…;

3. 將Ci的var3置為A.var3;

4. 刪除B,將B之后的四元式前移。

正確性證明:

對於任意在語法分析過程中定義的臨時變量$_ti(詳見syn.cpp),均有如下定理:

$_ti僅會出現在之后四元式的var1和var2位置,永不會被修改

因此我們無需擔心DAG圖中會出現臨時變量重定義的情況。

因此,一旦出現任意兩個臨時變量有相同的子表達式,完全可以用其中一個代替全部。因此以上算法正確。

3.刪除冗余代碼標簽:

很多情況下,程序或出現如下的句型:

If(xxxxx){

……

}

……

即不存在else。

此外,還有很多情況會導致在轉化成四元式的時候兩個甚至多個label連在一起,這樣就導致了代碼冗余。

算法:

掃描整個四元式,一旦遇到lab:,刪除其后的所有相鄰lab代碼,並更改所有var3為被刪除的lab的四元式中跳轉指令的var3為最先發現的lab,反復執行直到讀完整個四元式。

4.通過引用計數和FIFO策略的寄存器分配方案:

本程序使用s0到s7存儲局部變量。

建立一個寄存器表,如下所示:

寄存器

變量編號

$s0

1

$s1

8

$s2

7

$s3

$s4

$s5

$s6

$s7

實際運行時的情況舉例:

其中symbnum指的是變量在變量表中的編號,cnt為計數的積分,越高使用頻率就越大。

通過引用計數算法,掃描整個函數,查找每個變量使用的頻度值,從大到小排序,分配寄存器。

9. 出錯處理

0.接口:void error(int _errsig, int signal)

 

1.出錯類型和相關信息:

出錯名稱

出錯代碼

出錯原因

NOSUCHFILE

999

源文件缺少

FILEINCOMPLETE

0

文件不完整

DOUBLEQUOTESLACK

1

缺少“"”

UNACCEPTATLECHAR

2

不可接受的字符

SINGLEQUOTESLACK

3

缺少“'”

OUTOFTABLE

4

符號表爆了

SYMBOLCONFLICT

5

變量名沖突

CSTDEFINEFAIL

6

常量聲明失敗

VARNOTINIT

7

變量未初始化

UNKNOWRIGHTSYM

8

等號右邊字符非法

SEMICOLONLACK

9

丟失“;”

KEYWORDERROR

10

關鍵字錯誤

IDENTIFIERLACK

11

丟失標志符

RIGHTBRACKLACK

12

丟失“]”

FUNCTIONNOTFOUND

13

調用函數未定義

FORMALPARANUMUNMATCH

14

形參個數不匹配

VARNOTDEFINE

15

未定義變量

LEFTPARENTLACK

16

丟失“(”

RIGHTPARENTLACK

17

丟失“)”

IMMLACK

18

丟失立即數

RIGHTBRACELACK

19

丟失“}”

FUNCTIONRETURNNULL

20

函數無返回值卻被用於參數

EXPRESSIONERROR

21

表達式缺失或錯誤

UNACCEPTABLESENTENCE

22

句子不合法

ASSIGNCONST

23

給常數賦值

LEFTBRACELACK

24

缺少“{”

NONERETURN

25

缺少返回值

PLUSMINULACK

26

缺少‘+’或‘-’

MAINLACK

27

缺少main函數

MOREWORD

28

main函數后面有多余字符

CONSTNOTINIT

29

常量沒有初始化

2.出錯處理方式種類:

處理方式名稱

代碼

處理方式

QUIT

1

直接退出程序

DONOTHING

2

不做任何處理

ICV

3

跳到下一個類型聲明符號int/char/void

CICVIFIRSP

4

跳到下一個以下集合的元素

{ CONSTTK INTTK CHARTK VOIDTK IFTK WHILETK FORTK IDEN RETURNTK SCANFTK PRINTFTK}

CS

5

跳到下一個逗號或者分號

CLR

6

跳到下一個逗號或者括號

IWFRSPIFCV

7

跳到下一個語句列的FIRST集合元素之一

IWFLIRSPE

8

跳到下一個以下集合的元素:

{IFTK WHILETK FORTK LBRACK IDEN RETURNTK SCANFTK PRINTFTK ELSETK RBRACE}

IWFXXXANE

9

跳到下一個以下集合的元素:

{ IFTK WHILETK FORTK LBRACK IDEN RETURNTK SCANFTK PRINTFTK SEMICN ELSETK RPARENT COMMA PLUS MINU MULT DIV LSS LEQ GRE GEQ NEQ EQL}

3.出錯處理方式:

1.遞歸子程序發現錯誤立即調用error()並傳遞出錯信號;

2.error函數通過接收到的出錯信號打印出出錯信息和位置信息;

3.通過出錯類型型號和位置判斷應該如何進行跳讀,基本上是遇到錯誤則跳到同層符號的FIRST集合元素。具體情況具體分析,詳見err.cpp。

4.繼續執行編譯,直到文件結束。

三.操作說明

1.運行環境

代碼可在windows,Linux和mac下編譯正常執行;

需要Mars進行模擬;

在三種平台下均可使用Mars進行模擬執行生成的匯編代碼。

2.操作步驟

1.使用VS201*編譯本程序后會出現如下exC0compiler.exe的程序。此即為編譯器的主程序。

image

2.運行編譯器程序。

3.將需要編譯的文件拖入程序框內,如果路徑存在空格,需要加上引號。之后按回車。如圖所示:

image

4.如果編譯成功,會出現如下提示,並跳轉到第六步:

image

5.如果編譯失敗,會出現如下提示:

image

6.編譯成功后,將會生成如下幾個文件:

image

7.可以通過optMidCode.txt和midcode.txt進行比對來看優化效果

8.接下來打開MARS模擬器,導入asmrst.asm,如圖:

image

9.編譯執行即可,如圖:

image

10.需要注意的是,任何輸入都必須用換行符隔開,這是Mars定義的模擬特性。

下圖就是一個正確的輸入:

image

而下圖用空格隔開將會導致程序出錯:

image image

最后貼一下工程代碼,需要注意的是這個代碼是歷史版本存在一些漏洞:

  1 //
  2 //  glob.h
  3 //  exc0compiler
  4 //
  5 //  Created by sciencefans on 14/11/19.
  6 //  Copyright (c) 2014年 sciencefans. All rights reserved.
  7 //
  8 
  9 #ifndef exc0compiler_glob_h
 10 #define exc0compiler_glob_h
 11 #include <string>
 12 #include <iostream>
 13 #include <fstream>
 14 #include <algorithm>
 15 #include <vector>
 16 #include <map>
 17 #include <ctype.h>
 18 
 19 using namespace std;
 20 
 21 ///======================================lax
 22 
 23 extern const int kwdnum;
 24 extern char *word[];
 25 
 26 extern char *wsym[];
 27 
 28 #define BEGINTK     1
 29 #define CALLTK      2
 30 #define CASETK      3
 31 #define CHARTK      4
 32 #define CONSTTK     5
 33 #define DEFAULTTK   6
 34 #define DOTK        7
 35 #define ELSETK      8
 36 #define ENDTK       9
 37 #define FLOATTK     10
 38 #define FORTK       11
 39 #define IFTK        12
 40 #define INTTK       13
 41 #define MAINTK      14
 42 #define ODDTK       15
 43 #define PRINTFTK    16
 44 #define PROCETK     17
 45 #define READTK      18
 46 #define RETURNTK    19
 47 #define RPTTK       20
 48 #define SCANFTK     21
 49 #define SWITCHTK    22
 50 #define THENTK      23
 51 #define UTLTK       24
 52 #define VARTK       25
 53 #define VOIDTK      26
 54 #define WHILETK     27
 55 #define WRITETK     28
 56 #define IDEN        29
 57 #define INTCON      30
 58 #define CHARCON     31
 59 #define STRCON      32
 60 #define PLUS        33
 61 #define MINU        34
 62 #define MULT        35
 63 #define PERIOD      36
 64 #define DIV         37
 65 #define COLON       38
 66 #define LSS         39
 67 #define QMARK       40
 68 #define LEQ         41
 69 #define DQMARK      42
 70 #define GRE         43
 71 #define LPARENT     44
 72 #define GEQ         45
 73 #define RPARENT     46
 74 #define EQL         47
 75 #define LBRACK      48
 76 #define NEQ         49
 77 #define RBRACK      50
 78 #define ASSIGN      51
 79 #define LBRACE      52
 80 #define SEMICN      53
 81 #define RBRACE      54
 82 #define COMMA       55
 83 
 84 #define CINTCON     56
 85 #define CCHARCON    57
 86 
 87 extern ofstream laxrst, midcoderst, asmrst, symtablehis;
 88 extern int ch;//the
 89 
 90 extern int line[ 500 ], backupline[ 500 ];
 91 extern int lnum , cnum , llen, prllen;
 92 extern FILE* src;
 93 
 94 //define id, num and sym
 95 extern string id, prid;
 96 extern int num;
 97 extern string sym;
 98 extern double dnum;
 99 extern int symid;
100 
101 //declare functioint getsym();
102 void getch();
103 int getsym();
104 bool stringcmp(char* a, char* b);
105 
106 
107 ///======================================syn
108 void program();
109 void defhead();
110 void varstate();
111 void vardef();
112 void constdef(int tclass);
113 void conststate();
114 void sentencelist();
115 void complexsentence();
116 void sentence();
117 void condition();
118 void loopsentence();
119 void valueofpara();
120 void scanfsentence();
121 void printfsentence();
122 void parametertable();
123 void returnsentence();
124 void expression();
125 void item();
126 void factor();
127 void lower(char* s);
128 //the word tobe dealwith
129 extern int wd;
130 
131 #define MAXIDENLEN      30
132 #define MAXSYMTABLENUM  200
133 
134 //define symbol table
135 typedef struct{
136     char name[ MAXIDENLEN ];  //identifier name
137     int kind;               //identifier kind (define as follow)
138     int value;              //1對於函數來說,表示返回值為Int 0返回值為void
139     int address;            //address
140     int paranum;            //
141 }symb;
142 #define CONST       0   //常亮
143 #define VARIABLE    1   //變量
144 #define FUNCTION    2   //函數
145 #define PARA        3   //參數
146 /****************************
147 *                  symbol table
148 *  name    kind    value   address     paranum
149 *
150 *
151 *
152 *
153 *
154 ***************************/
155 typedef struct {
156     symb element[ MAXSYMTABLENUM ];
157     int index;
158     int ftotal;                 //分程序總數
159     int findextable[ MAXSYMTABLENUM ];//分程序索引數組
160 }symtable;
161 extern symtable maintable;
162 extern int  value;     //保存常量的值;對於子程序,0表示void,1表示int
163 extern int  address;   //變量的地址;函數返回值的地址
164 extern int  paranum;   //全局變量,用來處理函數定義,因為函數的參數個數只能在參數表子程序執行結束之后才知道,所以只能在后面才插入符號表信息
165 extern int  kind;      //正在處理的標志符的類型
166 extern char name[ MAXIDENLEN ]; //標志符的名字,包括常量變量和函數
167 extern int hsymid; //上一個單詞類型
168 extern char nowitem[ 200 ];
169 extern int returnnum; //記錄是否有返回值
170 extern char procname[ 100 ];
171 extern int mf; //主函數個數
172 
173 
174 ///=====================================四元式
175 void insmidcode(char* op, char* t1, char* t2, char* t3);
176 void insmidcode(char* op, int t1, int t2, char* t3);
177 void insmidcode(char* op, char t1, int t2, char* t3);
178 char* nextlab();
179 char* nextvar();
180 #define MAXMIDCODE 1000
181 /****************************
182 * op:      symbol of operator
183 * var1:    op1
184 * var2:    op2
185 * var3:    distination var
186 * e.g.
187 *      =   , 2 ,   , temp  ==> temp = 2;
188 *       []= , a , i , t       ==> a[i] = t;
189 *      int ,   ,   , a     ==> int  a;
190 *      const,int,5 , a     ==> const int a = 5;
191 *      char,   , 30, a     ==> char a[30];
192 *      fupa,   ,   , a     ==> a is a function parameter
193 *      call, f ,   , a     ==> a = f()
194 *      call, f ,   ,       ==> f()
195 *      <=.., a , b ,       ==> a <= b
196 *      jne ,   ,   , lable ==> if not satisfy(==false) then jump
197 *      jmp ,   ,   , label ==> jump to label
198 *      lab:,   ,   , labx  ==> set label
199 *      geta, a , n , b     ==> b = a[n]
200 *      ret ,   ,   , (a)   ==> return a / return
201 *      prt , a , b , symb  ==> print("a", b)
202 *      scf ,   ,   , a     ==> scanf(a)
203 *      func,int,   , f     ==> start of function int f()
204 *      para,int,   , a     ==> f(int a, ...)
205 *      end ,   ,   , f     ==> end of function f
206 ****************************/
207 typedef struct{
208     char op[ 10 ];
209     char var1[ 200 ];
210     char var2[ 30 ];
211     char var3[ 30 ];
212 }fourvarcode;
213 extern fourvarcode midcode[ MAXMIDCODE ];
214 extern int midcodeiter;
215 extern int labelcnt;
216 extern int varcnt;
217 
218 ///=====================================優化
219 extern FILE* optcodefile;
220 void printOptimize();
221 int isconst(char name[]);
222 void delsetlab();
223 void delpublic();
224 void combine();
225 void scan();
226 
227 
228 ///=====================================匯編
229 extern int mi;
230 extern int sp;
231 extern int x;
232 void midcode2asm();
233 int findvartable(char *name);
234 void midcode2asm();
235 void insertaddress(int kind, int addr = -1, int nmi = -1);
236 void pushstack(char* item = "0", int lenth = 1);
237 void funcasm();
238 int varaddr(char *name);
239 void dataseg();
240 void jmpasm();
241 void printint();
242 void callasm();
243 void setlabasm();
244 void addasm();
245 void subasm();
246 void mulasm();
247 void divasm();
248 void greasm();
249 void geqasm();
250 void lssasm();
251 void leqasm();
252 void eqlasm();
253 void neqasm();
254 void assasm();
255 void aassasm();
256 void assaasm();
257 void scfasm();
258 void prtasm();
259 void fupaasm();
260 void retasm();
261 void paraasm();
262 void jneasm();
263 void intcharasm();
264 void constdefasm();
265 void intcharaasm();
266 void savesreg();
267 void loadsreg();
268 void cnt(char * name);
269 void cntopt();
270 #endif
 1 //
 2 //  err.h
 3 //  exc0compiler
 4 //
 5 //  Created by sciencefans on 14/11/15.
 6 //  Copyright (c) 2014年 sciencefans. All rights reserved.
 7 //
 8 
 9 #ifndef exc0compiler_err_h
10 #define exc0compiler_err_h
11 
12 #define NOSUCHFILE            999
13 #define FILEINCOMPLETE      0
14 #define DOUBLEQUOTESLACK    1
15 #define UNACCEPTATLECHAR    2
16 #define SINGLEQUOTESLACK    3
17 #define OUTOFTABLE          4
18 #define SYMBOLCONFLICT      5
19 #define CSTDEFINEFAIL       6   //常亮聲明失敗
20 #define VARNOTINIT          7   //變量未初始化
21 #define UNKNOWRIGHTSYM      8   //等號右邊字符非法
22 #define SEMICOLONLACK       9   //丟失“;”
23 #define KEYWORDERROR        10  //關鍵字錯誤
24 #define IDENTIFIERLACK      11  //丟失標志符
25 #define RIGHTBRACKLACK      12  //丟失“]”
26 #define FUNCTIONNOTFOUND    13  //調用函數未定義
27 #define FORMALPARANUMUNMATCH 14 //形參個數不匹配
28 #define VARNOTDEFINE        15  //未定義變量
29 #define LEFTPARENTLACK      16  //丟失“(”
30 #define RIGHTPARENTLACK     17  //丟失“)”
31 #define IMMLACK             18  //丟失立即數
32 #define RIGHTBRACELACK      19  //丟失“}”
33 #define FUNCTIONRETURNNULL  20  //函數無返回值卻被用於參數
34 #define EXPRESSIONERROR     21  //表達式缺失或錯誤
35 #define UNACCEPTABLESENTENCE 22 //句子不合法
36 #define ASSIGNCONST         23  //給常數賦值
37 #define LEFTBRACELACK       24  //缺少“{”
38 #define NONERETURN          25  //缺少返回值
39 #define PLUSMINULACK        26  //缺少‘+’或‘-’
40 #define MAINLACK            27  //缺少main函數
41 #define MOREWORD            28  //main函數后面有多余字符
42 #define CONSTNOTINIT        29    //常量沒有初始化
43 
44 extern void error(int _errsig, int signal = 0);
45 extern int errnum;
46 #endif
  1 //
  2 //  main.cpp
  3 //  exc0compiler
  4 //
  5 //  Created by sciencefans on 14/11/14.
  6 //  Copyright (c) 2014年 sciencefans. All rights reserved.
  7 //
  8 
  9 #include "glob.h"
 10 #include "err.h"
 11 
 12 using namespace std;
 13 
 14 int prllen;
 15 const int kwdnum = 28;
 16 char *word[] = {
 17     "begin", "$call", "case", "char", "const",//0~4
 18     "default", "do", "else", "$end", "float",  //5~9
 19     "for", "if", "int", "main", "$odd",//10~14
 20     "printf", "$procedure", "$read", "return", "$repeat",  //15~19
 21     "scanf", "switch", "$then", "until", "$var",//20~24
 22     "void", "while", "$write"//25~27
 23 };
 24 char *wsym[] = {
 25     "BEGINTK", "CALLTK", "CASETK", "CHARTK", "CONSTTK",
 26     "DEFAULTTK", "DOTK", "ELSETK", "ENDTK", "FLOATTK",
 27     "FORTK", "IFTK", "INTTK", "MAINTK", "ODDTK",
 28     "PRINTFTK", "PROCETK", "READTK", "RETURNTK", "RPTTK",
 29     "SCANFTK", "SWITCHTK", "THENTK", "UTLTK", "VARTK",
 30     "VOIDTK", "WHILETK", "WRITETK"
 31 };
 32 
 33 int ch = ' ';//the
 34 
 35 int line[ 500 ], backupline[ 500 ];
 36 int lnum = 0, cnum = 0, llen = 0;
 37 FILE* src = NULL;
 38 
 39 //define id, num and sym
 40 string id = "";
 41 int num;
 42 string sym;
 43 double dnum;
 44 int symid;
 45 string prid;
 46 
 47 
 48 int getsym(){
 49     prid = id;
 50     id = "";
 51     while ( isspace(ch) && ch != EOF ) {
 52         getch();
 53     }
 54     if ( ch == EOF ){
 55         symid = -1;
 56         return -1;
 57     }
 58     //when the ch is alpha
 59     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 60     //!!!   this version donnot has lenth limit
 61     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 62     if ( isalpha(ch) || ch == '_' ){
 63         string tempstr;
 64         while ( isalpha(ch) || isdigit(ch) || ch == '_' ) {
 65             ch = tolower(ch);
 66             tempstr += ch;
 67             getch();
 68         }
 69         id = tempstr;
 70         //seatch reserved word table
 71         int iter = 0;
 72         for ( iter = 0; iter < kwdnum; iter++ ) {
 73             if ( stringcmp(word[ iter ], (char*)tempstr.c_str()) ) {
 74                 sym = wsym[ iter ];
 75                 symid = iter + 1;
 76                 break;
 77             }
 78         }
 79         if ( iter == kwdnum ) {
 80             sym = "IDEN";
 81             symid = IDEN;
 82         }
 83     }
 84     else if ( isdigit(ch) ){
 85         
 86         sym = "INTCON";
 87         symid = INTCON;
 88         num = 0;
 89         while ( isdigit(ch) ){
 90             id += ch;
 91             num = num * 10 + (int)( ch - '0' );
 92             getch();
 93         }
 94         if ( ch == '.' ) {
 95             id += ch;
 96             sym = "FLOATCON";
 97             symid = -1;
 98             double t = 0.1;
 99             dnum = num;
100             getch();
101             while ( isdigit(ch) ){
102                 id += ch;
103                 dnum = dnum + (int)( ch - '0' ) * t;
104                 t /= 10;
105                 getch();
106             }
107         }
108     }
109     else if ( ch == '=' ){
110         id += ch;
111         sym = "ASSIGN";
112         symid = ASSIGN;
113         getch();
114         if ( ch == '=' ) {
115             id += ch;
116             sym = "EQL";
117             symid = EQL;
118             getch();
119         }
120     }
121     else if ( ch == '<' ){
122         id += ch;
123         getch();
124         if ( ch == '=' ) {
125             id += ch;
126             sym = "LEQ";
127             symid = LEQ;
128             getch();
129         }
130         else{
131             sym = "LSS";
132             symid = LSS;
133         }
134     }
135     else if ( ch == '>' ){
136         id += ch;
137         getch();
138         if ( ch == '=' ) {
139             id += ch;
140             sym = "GEQ";
141             symid = GEQ;
142             getch();
143         }
144         else{
145             sym = "GRE";
146             symid = GRE;
147         }
148     }
149     else if ( ch == '!' ){
150         id += ch;
151         getch();
152         if ( ch == '=' ) {
153             id += ch;
154             sym = "NEQ";
155             symid = NEQ;
156             getch();
157         }
158     }
159     else if ( ch == '\"' ){
160         string tempstr;
161         getch();
162         while ( ch == 32 || ch == 33 || (ch <= 126 && ch >= 35) ) {
163             tempstr += ch;
164             getch();
165         }
166         if ( ch == '\"' ) {
167             getch();
168             sym = "STRCON";
169             symid = STRCON;
170             id = tempstr;
171         }
172         else{
173             error(DOUBLEQUOTESLACK);
174             return -1;
175         }
176     }
177     else if ( ch == '\'' ){
178         getch();
179         if ( ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '_' || isalnum(ch) ) {
180             id += ch;
181             getch();
182         }
183         else{
184             error(UNACCEPTATLECHAR);
185             return -1;
186         }
187         if ( ch == '\'' ){
188             sym = "CHARCON";
189             symid = CHARCON;
190             getch();
191         }
192         else{
193             error(SINGLEQUOTESLACK);
194             return -1;
195         }
196     }
197     else {
198         if ( ch == '+' ){
199             sym = "PLUS";
200             symid = PLUS;
201         }
202         else if ( ch == '-' ){
203             sym = "MINU";
204             symid = MINU;
205         }
206         else if ( ch == '*' ){
207             sym = "MULT";
208             symid = MULT;
209         }
210         else if ( ch == '/' ){
211             sym = "DIV";
212             symid = DIV;
213         }
214         else if ( ch == ',' ){
215             sym = "COMMA";
216             symid = COMMA;
217         }
218         else if ( ch == ':' ){
219             sym = "COLON";
220             symid = COLON;
221         }
222         else if ( ch == ';' ){
223             sym = "SEMICN";
224             symid = SEMICN;
225         }
226         else if ( ch == '{' ){
227             sym = "LBRACE";
228             symid = LBRACE;
229         }
230         else if ( ch == '[' ){
231             sym = "LBRACK";
232             symid = LBRACK;
233         }
234         else if ( ch == '(' ){
235             sym = "LPARENT";
236             symid = LPARENT;
237         }
238         else if ( ch == '}' ){
239             sym = "RBRACE";
240             symid = RBRACE;
241         }
242         else if ( ch == ']' ){
243             sym = "RBRACK";
244             symid = RBRACK;
245         }
246         else if ( ch == ')' ){
247             sym = "RPARENT";
248             symid = RPARENT;
249         }
250         id += ch;
251         getch();
252     }
253     if ( !strcmp(sym.c_str(), "INTCON") ) {
254         laxrst << sym << ' ' << num << endl;
255     }
256     else if ( !strcmp(sym.c_str(), "FLOATCON") ){
257         laxrst << sym << ' ' << dnum << endl;
258     }
259     else{
260         laxrst << sym << ' ' << id << endl;
261     }
262 
263     return 0;
264 }
265 
266 ///read one character in source file and store in 'ch'
267 void getch(){
268     int i = 0;
269     prllen = llen;
270     if ( cnum == llen && ~line[ llen ] ) {
271 
272         ch = fgetc(src);
273         while ( ch == ' ' || ch == '\n' || ch == '\t' ){
274             if (ch == '\n') {
275                 lnum++;
276             }
277             backupline[ i++ ] = ch;  //保存源文件的行,用於發生錯誤時輸出
278             ch = fgetc(src);
279         }
280         //保存過濾掉空白字符后的一行字符
281         for ( llen = 0; ch != '\n' && ch != EOF; llen++ ) {
282             line[ llen ] = ch;
283             backupline[ i++ ] = ch;   //保存源文件的行,用於發生錯誤時輸出
284             ch = fgetc(src);
285         }
286         if ( ch == EOF )
287             line[ llen ] = EOF;
288         else
289             line[ llen ] = '\n';
290         backupline[ i ] = '\0';
291 
292         cnum = 0;
293         ch = '\n';
294         lnum++;
295         /*midcoderst << "##LINE " << lnum << ": ";
296         for ( int t = 0; t < llen; t++ ){
297             midcoderst << (char)line[ t ];
298         }
299         midcoderst << endl;*/
300     }
301     else{
302         ch = line[ cnum++ ];
303     }
304 }
305 
306 
307 //return:
308 //  true:   a > b
309 //  false:  a < b
310 bool stringcmp(char *a, char *b){
311     int i = 0;
312     while ( true ){
313         if (( a[ i ] == 0) && (b[ i ] == 0 )) {
314             return true;
315         }
316         else if ( a[ i ] != b[ i ] ){
317             return false;
318         }
319         else{
320             i++;
321         }
322 
323     }
324 }
   1 //
   2 //  syn.cpp
   3 //  exc0compiler
   4 //
   5 //  Created by sciencefans on 14/11/18.
   6 //  Copyright (c) 2014年 sciencefans. All rights reserved.
   7 //
   8 
   9 
  10 
  11 #include "glob.h"
  12 #include "err.h"
  13 
  14 
  15 
  16 int wd = -1;
  17 symtable maintable;
  18 int  value;     //保存常量的值;對於子程序,0表示void,1表示int
  19 int  address;   //變量的地址;函數返回值的地址
  20 int  paranum;   //全局變量,用來處理函數定義,因為函數的參數個數只能在參數表子程序執行結束之后才知道,所以只能在后面才插入符號表信息
  21 int  kind;      //正在處理的標志符的類型
  22 char name[ MAXIDENLEN ]; //標志符的名字,包括常量變量和函數
  23 int hsymid; //上一個單詞類型
  24 char nowitem[ 200 ];
  25 int returnnum = 0; //記錄是否有返回值
  26 char procname[ 100 ];
  27 int hiscnt = 1;
  28 int sislob = 1;
  29 int factclass = 0;
  30 #define INT 1
  31 #define CHAR 2
  32 #define subfuncindex(n) maintable.findextable[(n)]
  33 
  34 //fill in symbol table
  35 //name:     symbol name
  36 //kind:     the kind of name(see syn.h)
  37 //value:    the value of const
  38 //address:  the address of the var
  39 //para:     the formal parameter of function
  40 int arrnum(char *name){
  41     int n;
  42     int m = maintable.findextable[ 1 ];
  43     n = maintable.findextable[ maintable.ftotal ];
  44     //查找符號表中是否有
  45     while ( n < maintable.index ) {
  46         if ( strcmp(maintable.element[ n ].name, name) == 0 )
  47             return maintable.element[ n ].paranum;
  48         n++;
  49     }
  50 
  51     //如果分程序符號表中無定義,查找最外層符號表
  52     if ( n == maintable.index ) {
  53         n = 0;
  54         while ( n < m ) {
  55             if ( strcmp(maintable.element[ n ].name, name) == 0 )
  56                 return maintable.element[ n ].paranum;
  57             n++;
  58         }
  59         //符號表中沒有定義
  60         if ( n == m ) {
  61             printf("\"%s\" ", name);
  62             //error(VARNOTDEFINE);
  63             return -1;
  64         }
  65     }
  66 }
  67 
  68 void pushtable(char* name, int kind, int value, int address, int paranum, int isVec = 0){
  69 
  70     //whether table is full
  71     if ( maintable.index >= MAXSYMTABLENUM ){
  72         error(OUTOFTABLE);
  73         exit(0);
  74     }
  75 
  76     //whether conflict
  77     //function
  78     if ( kind == FUNCTION ) {
  79         int iter = 1;
  80         for ( iter = 1; iter <= maintable.ftotal; iter++ ) {
  81             if ( !strcmp(maintable.element[ maintable.findextable[ iter ] ].name, name) ) {
  82                 error(SYMBOLCONFLICT);
  83                 return;
  84             }
  85         }
  86         maintable.findextable[ ++maintable.ftotal ] = maintable.index;
  87     }
  88     else{
  89         //others
  90         int iter = maintable.findextable[ maintable.ftotal ];
  91         for ( ; iter < maintable.index; iter++ ) {
  92             if ( !strcmp(maintable.element[ iter ].name, name) ) {
  93                 error(SYMBOLCONFLICT);
  94                 return;
  95             }
  96         }
  97         //if not para and non-glob-var, compare with global var.
  98         if ( kind != PARA && sislob) {
  99             iter = 0;
 100             while ( iter < maintable.findextable[ 1 ] ) {
 101                 if ( !strcmp(maintable.element[ iter ].name, name) ) {
 102                     error(SYMBOLCONFLICT);
 103                     return;
 104                 }
 105                 iter++;
 106             }
 107         }
 108     }
 109 
 110     strcpy(maintable.element[ maintable.index ].name, name);
 111     maintable.element[ maintable.index ].kind = kind;
 112     maintable.element[ maintable.index ].value = value;
 113     maintable.element[ maintable.index ].address = maintable.index;
 114     maintable.element[ maintable.index ].paranum = isVec ? isVec : paranum;
 115     if (maintable.index <= hiscnt) {
 116         symtablehis << "----------------------------------------------------------------" << endl;
 117     }
 118     hiscnt = maintable.index;
 119     symtablehis << maintable.index << "\t" << name << "\t" << kind << "\t" << value << "\t" << address << "\t" << paranum << "\t" << isVec << endl;
 120     maintable.index++;
 121 }
 122 
 123 void insertproc(int paranum)
 124 {
 125     int x = maintable.findextable[ maintable.ftotal ];   //array[i],指向的是當前正在被分析的函數在符號表中的索引
 126     maintable.element[ x ].paranum = paranum;//插入函數參數個數信息
 127     return;
 128 }
 129 
 130 //look up symbol table
 131 //flag=1時,說明要在分程序索引里查找,flag=0時,在當前所在分程序符號表中查找
 132 //flag2=1時,只在當前函數作用域里找
 133 int searchst(char* name, int flag, int flag2 = 0){
 134     int n;
 135     int m = maintable.findextable[ 1 ];
 136     if ( flag == 1 ) {
 137         n = 1;
 138         while ( n <= maintable.ftotal ) {
 139             if ( strcmp(maintable.element[ maintable.findextable[ n ] ].name, name) == 0 )
 140                 break;
 141             n++;
 142         }
 143 
 144         //如果函數標志符沒有定義
 145         if ( n > maintable.ftotal ) {
 146             printf("\"%s\" ", name);
 147             //error(FUNCTIONNOTFOUND);
 148             return -1 * FUNCTIONNOTFOUND;
 149         }
 150 
 151         //如果函數的實參個數與形參個數不匹配
 152         if ( maintable.element[ maintable.findextable[ n ] ].paranum != paranum ) {
 153             printf("\"%s\" ", name);
 154             //error(FORMALPARANUMUNMATCH);
 155             return -1 * FORMALPARANUMUNMATCH;
 156         }
 157 
 158         //如果函數標識符無內容
 159         if ( maintable.element[ maintable.findextable[ n ] ].value == 0 )
 160             return -1 * FUNCTIONRETURNNULL;
 161 
 162         return maintable.element[ maintable.findextable[ n ] ].address;
 163     }
 164     else{
 165         n = maintable.findextable[ maintable.ftotal ];
 166         //查找符號表中是否有
 167         while ( n < maintable.index ) {
 168             if ( strcmp(maintable.element[ n ].name, name) == 0 )
 169                 break;
 170             n++;
 171         }
 172 
 173         //如果分程序符號表中無定義,查找最外層符號表
 174         if ( n == maintable.index ) {
 175             n = 0;
 176             while ( n < m ) {
 177                 if ( strcmp(maintable.element[ n ].name, name) == 0 )
 178                     break;
 179                 n++;
 180             }
 181             //符號表中沒有定義
 182             if ( n == m ) {
 183                 printf("\"%s\" ", name);
 184                 //error(VARNOTDEFINE);
 185                 return -1;
 186             }
 187         }
 188         if ( maintable.element[ n ].kind == INTTK || maintable.element[ n ].kind == CHARTK )
 189             return maintable.element[ n ].address;
 190         if ( maintable.element[ n ].kind == CINTCON || maintable.element[ n ].kind == CCHARCON )
 191             return -2;    //const 返回負兩倍地址
 192         if ( maintable.element[ n ].kind == PARA )
 193             return maintable.element[ n ].address;    //參數標志
 194         return -1;
 195     }
 196 }
 197 
 198 
 199 
 200 //clear symbol table
 201 void flushst(){
 202     int x = maintable.index - 1;
 203     int y;
 204     while ( ( maintable.element[ x ].kind == INTTK || maintable.element[ x ].kind == CHARTK || maintable.element[ x ].kind == CINTCON
 205         || maintable.element[ x ].kind == CCHARCON || maintable.element[ x ].kind == PARA ) && strcmp(maintable.element[ x ].name, procname) != 0 ) {
 206         maintable.element[ x ].kind = 0;
 207         maintable.element[ x ].address = 0;
 208         maintable.element[ x ].paranum = 0;
 209         maintable.element[ x ].value = 0;
 210         y = 0;
 211         while ( y<30 )
 212             maintable.element[ x ].name[ y++ ] = '\0';
 213         x--;
 214     }
 215     maintable.index = x + 1;
 216     return;
 217 }
 218 
 219 //9.<程序>    ::= [<常量說明>][<變量說明>]{<有返回值函數定義>|<無返回值函數定義>}<主函數>
 220 void program(){
 221     getsym();
 222 
 223     if ( symid == CONSTTK ) {
 224         //調用常量說明子程序
 225         conststate();
 226         //如果是分號,則是正常的
 227     }
 228 
 229     //變量定義和有返回值的函數是相同的聲明頭部。因此預讀3個單詞用於判斷
 230     while ( symid == INTTK || symid == CHARTK ) {
 231         int tempid = symid;//恢復現場用
 232         char tempch = ch;//恢復現場用
 233         int tempcnum = cnum;//恢復現場用
 234         kind = symid;
 235         getsym();
 236         strcpy(name, id.c_str());//拷貝名字
 237 
 238         //如果標識符合法
 239         if ( symid != IDEN ) {
 240             error(IDENTIFIERLACK);//notdone
 241             continue;
 242         }
 243         getsym();
 244         //如果是逗號或者分號,則是變量定義
 245         if ( symid == COMMA || symid == LBRACK ) {
 246             symid = tempid;
 247             cnum = tempcnum;
 248             ch = tempch;
 249             varstate();
 250             continue;
 251         }
 252         else if ( symid == SEMICN ) {
 253             value = 0;
 254             address = 0;
 255             paranum = 0;
 256             pushtable(name, kind, value, address, paranum);
 257             if ( kind == INTTK ) insmidcode("int", "  ", "  ", name);
 258             else if ( kind == CHARTK ) insmidcode("char", "  ", "  ", name);
 259             getsym();
 260             continue;
 261         }
 262         else{
 263             symid = tempid;
 264             cnum = tempcnum;
 265             ch = tempch;
 266             break;
 267         }
 268     }
 269     if ( symid == CONSTTK ) {
 270         errnum++;
 271         printf("Error %d: Line %d, 常量定義位置錯誤!\n", errnum, lnum);
 272         conststate();
 273         //如果是分號,則是正常的
 274     }
 275     sislob = 0;
 276     //進入函數部分
 277     while ( symid == INTTK || symid == CHARTK || symid == VOIDTK ) {
 278         int temp = symid;
 279 
 280         //19.<有返回值函數定義>  ::=  <聲明頭部>‘(’<參數>‘)’  ‘{’<復合語句>‘}’
 281         if ( symid == INTTK || symid == CHARTK ) {
 282             defhead();
 283             if ( symid != LPARENT ) {
 284                 error(LEFTPARENTLACK);
 285                 continue;
 286             }
 287             varcnt = 0;     //臨時變量重新開始計數
 288             returnnum = 0;//將是否存在返回值的標記初始化,0表示無返回值,即未出現return
 289             kind = FUNCTION;//表示當前的函數是子程序,即非主函數
 290             value = 1;//1對於函數來說,表示返回值為Int 0返回值為void
 291             address = 0;
 292             paranum = 0;
 293             pushtable(name, kind, value, address, paranum);
 294             strcpy(procname, name);//函數名拷貝
 295             if ( temp == INTTK ) insmidcode("func", "int", "  ", procname);
 296             if ( temp == CHARTK ) insmidcode("func", "char", "  ", procname);
 297             getsym();
 298             parametertable();
 299             //缺'('<參數>')'的右小括號
 300             if ( symid != RPARENT ){
 301                 error(RIGHTPARENTLACK);
 302                 continue;
 303             }
 304             getsym();
 305             //缺'{'<復合語句>'}'的左大括號
 306             if ( symid != LBRACE ) {
 307                 error(LEFTBRACELACK);
 308                 continue;
 309             }
 310             getsym();
 311             complexsentence();
 312             //缺'{'<復合語句>'}'的右大括號
 313             if ( symid != RBRACE ) {
 314                 error(RIGHTBRACELACK);
 315                 continue;
 316             }
 317 
 318             //函數缺少返回值
 319             if ( returnnum == 0 ) {
 320                 error(NONERETURN);
 321                 continue;
 322             }
 323             getsym();
 324             insmidcode("end", "  ", "  ", procname);//函數部分四元式結束
 325             flushst();//清除符號表,這里清空的是此子函數的符號表,不清除子函數名
 326         }
 327 
 328         if ( symid == VOIDTK ) {
 329             getsym();
 330             //如果下一個單詞是main,則是<主函數>    ::= void main '(' ')'  '{'<復合語句>'}'
 331             if ( symid == MAINTK ) {
 332                 varcnt = 0;        //臨時變量重新開始計數
 333                 strcpy(name, "main");
 334                 kind = FUNCTION;
 335                 value = 0;
 336                 address = 0;
 337                 paranum = 0;
 338                 pushtable(name, kind, value, address, paranum);
 339                 strcpy(procname, name);
 340                 insmidcode("func", "  ", "  ", procname);
 341                 getsym();
 342                 if ( symid != LPARENT ) {
 343                     error(LEFTPARENTLACK);
 344                     continue;
 345                 }
 346                 getsym();
 347                 if ( symid != RPARENT ) {
 348                     error(RIGHTPARENTLACK); 
 349                     continue;
 350                 }
 351                 getsym();
 352                 if ( symid != LBRACE ) {
 353                     error(LEFTBRACELACK);
 354                     continue;
 355                 }
 356                 getsym();
 357                 complexsentence();
 358                 mf++;    //主函數的個數+1
 359                 insmidcode("end", "  ", "  ", procname);
 360                 if ( symid != RBRACE )
 361                 {
 362                     error(RIGHTBRACELACK);
 363                     continue;
 364                 }
 365                 return;    //源程序結束,跳出
 366             }
 367 
 368             //20.<無返回值函數定義>  ::= void<標識符>‘(’<參數>‘)’  ‘{’<復合語句>‘}’
 369             if ( symid != IDEN ) {
 370                 error(IDENTIFIERLACK);
 371                 continue;
 372             }
 373             varcnt = 0;          //臨時變量重新開始計數
 374             strcpy(name, id.c_str());
 375 
 376             kind = FUNCTION;
 377             value = 0;
 378             address = 0;
 379             paranum = 0;
 380             pushtable(name, kind, value, address, paranum);
 381             strcpy(procname, name);
 382             insmidcode("func", "void", "  ", procname);
 383             getsym();
 384             if ( symid != LPARENT ) {
 385                 error(LEFTPARENTLACK);
 386                 continue;
 387             }
 388             getsym();
 389             parametertable();
 390             if ( symid != RPARENT ) {
 391                 error(RIGHTPARENTLACK);
 392                 continue;
 393             }
 394             getsym();
 395             if ( symid != LBRACE ) {
 396                 error(LEFTBRACELACK);
 397                 continue;
 398             }
 399             getsym();
 400             complexsentence();
 401             if ( symid != RBRACE ) {
 402                 error(RIGHTBRACELACK);
 403                 continue;
 404             }
 405             getsym();
 406             insmidcode("end", "  ", "  ", procname);
 407             flushst();
 408         }
 409     }
 410 }
 411 
 412 
 413 //18.<類型標識符>   ::=    int | float | char
 414 //22.<參數>         ::=    <參數表>
 415 //23.<參數表>    ::=  <類型標識符><標識符>{,<類型標識符><標識符>}| <空>
 416 void parametertable()
 417 {
 418     int i = 0;     //記錄參數個數
 419     int temp;
 420     if ( symid == INTTK || symid == CHARTK ) {
 421         do{
 422             if ( symid == COMMA )
 423                 getsym();
 424             temp = symid;
 425             defhead();    //函數參數和變量定義時完全相同的,只是最后不是以分號結尾
 426             kind = PARA;     //4表示為函數參數
 427             value = 0;
 428             address = i;  //地址為i,即參數的位置,地址全部為相對地址?
 429             paranum = 0;
 430             pushtable(name, kind, value, address, paranum);  //將行數參數插入符號表
 431             if ( temp == INTTK ) insmidcode("para", "int", "  ", name);
 432             else if ( temp == CHARTK ) insmidcode("para", "char", "  ", name);
 433             i++;//參數個數加一
 434         } while ( symid == COMMA );//如果是逗號,則還有其他的參數
 435     }
 436     paranum = i;//當前的參數個數
 437     insertproc(paranum);//插入函數的參數個數
 438     return;
 439 }
 440 
 441 //10.<常量說明> ::=  const<常量定義>;{ const<常量定義>;}
 442 //ATTENTION:在這里會直接讀出類型
 443 void conststate(){
 444     while ( symid == CONSTTK ) {
 445         getsym();
 446         int tclass;
 447         if ( symid == INTTK || symid == CHARTK ) {
 448             kind = ( symid == INTTK ) ? CINTCON : CCHARCON;
 449             address = 0;
 450             paranum = 0;
 451             tclass = symid;
 452             getsym();
 453             constdef(tclass);
 454             while ( symid == COMMA ) {
 455                 getsym();
 456                 constdef(tclass);
 457             }
 458             //定義結束,下一個字符一定是分號
 459             if ( symid != SEMICN ) {
 460                 error(SEMICOLONLACK);
 461                 return;
 462             }
 463             hsymid = symid;
 464             getsym();
 465         }
 466         else{
 467             error(KEYWORDERROR);
 468             return;
 469         }
 470     }
 471     return;
 472 }
 473 
 474 //11.<常量定義>   ::=   int<標識符>=<整數>{,<標識符>=<整數>}    | char<標識符>=<字符>{,<標識符>=<字符>}
 475 //ATTENTION:這里不包含int和char, int, 這兩者將從tclass傳入
 476 void constdef(int tclass){
 477     //without int or char
 478     char temp[ 200 ];
 479     //結構:IDEN = XXXX
 480     if ( symid == IDEN ) {
 481         strcpy(name, id.c_str());
 482         getsym();
 483         //if is '='
 484         if ( symid == ASSIGN ) {
 485             getsym();
 486             // if is '+' or '-'
 487             if ( symid == PLUS || symid == MINU ) {
 488                 int symb = symid;
 489                 getsym();
 490                 // if is integer
 491                 if ( tclass == INTTK && symid == INTCON ) {
 492                     if ( symb == PLUS ) {
 493                         value = num;
 494                     }
 495                     else{
 496                         value = 0 - num;
 497                     }
 498                     pushtable(name, kind, value, address, paranum);
 499                     sprintf(temp, "%d", value);
 500                     insmidcode("const", "int", temp, name);
 501                 }
 502 
 503                 // if is char
 504             }
 505             else if ( symid == CHARCON ){
 506                 value = id.c_str()[ 0 ];
 507                 pushtable(name, kind, value, address, paranum);
 508                 sprintf(temp, "%d", value);
 509                 insmidcode("const", "char", temp, name);
 510             }
 511             else if ( symid == INTCON ){
 512                 value = num;
 513                 pushtable(name, kind, value, address, paranum);
 514                 sprintf(temp, "%d", value);
 515                 insmidcode("const", "int", temp, name);
 516             }
 517             else{
 518                 error(UNKNOWRIGHTSYM);
 519                 return;
 520             }
 521         }else{
 522             error(CONSTNOTINIT);
 523             return;
 524         }
 525     }
 526     else{
 527         error(CSTDEFINEFAIL);
 528     }
 529     getsym();
 530     return;
 531 }
 532 
 533 //15.<聲明頭部>   ::=  int<標識符> | char<標識符>
 534 //ATTENTION: 讀到的是int/char和標識符以及其后面的一個單詞!!
 535 void defhead()
 536 {
 537     if ( symid == INTTK || symid == CHARTK ) {
 538         kind = symid;
 539         getsym();
 540 
 541         if ( symid != IDEN ) {
 542             error(IDENTIFIERLACK, 1);
 543             return;
 544         }
 545         else {
 546             strcpy(name, id.c_str());//拷貝函數的名字
 547         }
 548     }
 549     else{
 550         error(KEYWORDERROR, 1);
 551         return;
 552     }
 553     getsym();
 554     return;
 555 }
 556 
 557 //16.<變量說明>  ::= <變量定義>;{<變量定義>;}
 558 void varstate()
 559 {
 560     vardef();
 561     //缺少';'
 562     if ( symid != SEMICN ) {
 563         error(SEMICOLONLACK, 1);
 564     }
 565     getsym();
 566     return;
 567 }
 568 
 569 
 570 //17.<變量定義>  ::= <類型標識符>(<標識符>|<標識符>‘[’<無符號整數>‘]’){,(<標識符>|<標識符>‘[’<無符號整數>‘]’ )}
 571 void vardef()
 572 {
 573     if ( symid == INTTK || symid == CHARTK ) {
 574         kind = symid;
 575         getsym();
 576 
 577         if ( symid != IDEN ) {
 578             error(IDENTIFIERLACK, 2);
 579             return;
 580         }
 581         else {
 582             strcpy(name, id.c_str());//拷貝函數的名字
 583         }
 584     }
 585     else{
 586         error(KEYWORDERROR, 2);
 587         return;
 588     }
 589     getsym();
 590     int isVec = ( symid == LBRACK );
 591     value = 0;
 592     address = 0;
 593     paranum = 0;
 594     if ( isVec ) {    //如果是數組
 595         getsym();
 596         if ( symid != INTCON ) {
 597             error(IMMLACK);
 598             return;
 599         }
 600         else{
 601             pushtable(name, kind, value, address, paranum, num);
 602             if ( kind == INTTK )
 603                 insmidcode("inta", 0, num, name);
 604             else if ( kind == CHARTK )
 605                 insmidcode("chara", 0, num, name);
 606             getsym();
 607             if ( symid != RBRACK ) {
 608                 error(RIGHTBRACKLACK, 1);
 609                 return;
 610             }
 611             else{
 612                 getsym();
 613             }
 614         }
 615     }
 616     else{
 617         pushtable(name, kind, value, address, paranum, isVec);
 618         if ( kind == INTTK )
 619             insmidcode("int", "  ", "  ", name);
 620         else if ( kind == CHARTK )
 621             insmidcode("char", "  ", "  ", name);
 622     }
 623 
 624     //如果后面是逗號,那么變量定義未結束
 625     while ( symid == COMMA ) {
 626         getsym();
 627         //出現不合法的標志符
 628         if ( symid != IDEN ) {
 629             error(IDENTIFIERLACK, 2);
 630             return;
 631         }
 632         strcpy(name, id.c_str());
 633         getsym();
 634         isVec = ( symid == LBRACK );
 635         if ( isVec ) {    //如果是數組
 636             getsym();
 637             if ( symid != INTCON ) {
 638                 error(IMMLACK);
 639                 return;
 640             }
 641             else{
 642                 pushtable(name, kind, value, address, paranum, num);
 643                 if ( kind == INTTK )
 644                     insmidcode("int", 0, num, name);
 645                 else if ( kind == CHARTK )
 646                     insmidcode("char", 0, num, name);
 647                 getsym();
 648                 if ( symid != RBRACK ) {
 649                     error(RIGHTBRACKLACK);
 650                     return;
 651                 }
 652                 else{
 653                     getsym();
 654                 }
 655             }
 656         }
 657         else{
 658             pushtable(name, kind, value, address, paranum, isVec);
 659             if ( kind == INTTK )
 660                 insmidcode("int", "  ", "  ", name);
 661             else if ( kind == CHARTK )
 662                 insmidcode("char", "  ", "  ", name);
 663         }
 664     }
 665     return;
 666 }
 667 
 668 //21.<復合語句>   ::=  [<常量說明>][<變量說明>]<語句列>
 669 void complexsentence()
 670 {
 671     if ( symid == CONSTTK ) {
 672         //調用常量說明子程序
 673         conststate();
 674         //如果是分號,則是正常的
 675         while ( hsymid == SEMICN ) {
 676             if ( symid == CONSTTK )
 677                 conststate();
 678             else break;
 679         }
 680     }
 681 
 682     //判斷是否為變量說明
 683     //設置部分變量用於恢復現場
 684     while ( symid == INTTK || symid == CHARTK ) {
 685         int tempid = symid;//恢復現場用
 686         char tempch = ch;//恢復現場用
 687         int tempcnum = cnum;//恢復現場用
 688         kind = symid;
 689         getsym();
 690         strcpy(name, id.c_str());//拷貝名字
 691 
 692         //如果標識符合法
 693         if ( symid != IDEN ) {
 694             error(IDENTIFIERLACK, 2);
 695             return;
 696         }
 697         getsym();
 698         //如果是逗號或者分號,則是變量定義
 699         if ( symid == COMMA || symid == LBRACK) {
 700             symid = tempid;
 701             cnum = tempcnum;
 702             ch = tempch;
 703             varstate();
 704             continue;
 705         }
 706         else if ( symid == SEMICN ) {
 707             value = 0;
 708             address = 0;
 709             paranum = 0;
 710             pushtable(name, kind, value, address, paranum);
 711             if ( kind == INTTK ) insmidcode("int", "  ", "  ", name);
 712             else if ( kind == CHARTK ) insmidcode("char", "  ", "  ", name);
 713             getsym();
 714             continue;
 715         }
 716         else{
 717             error(SEMICOLONLACK, 1);
 718             return;
 719         }
 720     }
 721 
 722     //語句列
 723     sentencelist();
 724     return;
 725 }
 726 
 727 //37.<語句列>   ::= {<語句>}
 728 void sentencelist()
 729 {
 730     sentence();
 731     //語句,如果讀到的是如下的東西,那么還是語句
 732     while ( symid == IFTK || symid == WHILETK || symid == FORTK || symid == LBRACE
 733         || symid == IDEN || symid == RETURNTK || symid == SCANFTK || symid == PRINTFTK ) {
 734         sentence();
 735     }
 736 }
 737 
 738 //30.<條件語句>  ::=  if ‘(’<條件>‘)’<語句>[else<語句>]
 739 void ifsentence()
 740 {
 741     char label1[ 10 ], label2[ 10 ], conditionvalue[ 30 ];
 742     strcpy(label1, nextlab());  //如果不滿足if,則跳過label1,label1是if的結束部分
 743     strcpy(label2, nextlab());  //如果還有else,則else的結束位置是label2
 744     getsym();
 745     //少“(”
 746     if ( symid != LPARENT ) {
 747         error(LEFTPARENTLACK, 1);
 748         return;
 749     }
 750     getsym();
 751     //<條件>
 752     condition();
 753     strcpy(conditionvalue, nowitem);  //條件計算的值在nowitem里面,此處應該是個臨時變量$_x
 754     insmidcode("jne", "  ", "  ", label1);  //比較,為假的時候跳轉
 755     if ( symid != RPARENT ) {
 756         error(RIGHTPARENTLACK, 1);
 757         return;
 758     }
 759     getsym();
 760     sentence();
 761     insmidcode("jmp", "  ", "  ", label2);//不執行else的部分
 762     insmidcode("lab:", "  ", "  ", label1);
 763     if ( symid == ELSETK ) {
 764         getsym();
 765         sentence();
 766     }
 767     insmidcode("lab:", "  ", "  ", label2);
 768     return;
 769 }
 770 
 771 //31.<條件>    ::=  <表達式><關系運算符><表達式>|<表達式>
 772 void condition()
 773 {
 774     char place1[ 30 ], place2[ 30 ];
 775     expression();
 776     strcpy(place1, nowitem);  //條件至少有一個表達式
 777     //關系運算符
 778     if ( symid == LSS || symid == LEQ || symid == GRE || symid == GEQ || symid == NEQ || symid == EQL ) {
 779         if ( symid == LSS ) {
 780             getsym();
 781             expression();
 782             strcpy(place2, nowitem);
 783             insmidcode("<", place1, place2, "  ");
 784         }
 785         else if ( symid == LEQ ) {
 786             getsym();
 787             expression();
 788             strcpy(place2, nowitem);
 789             insmidcode("<=", place1, place2, "  ");
 790         }
 791         else if ( symid == GRE ) {
 792             getsym();
 793             expression();
 794             strcpy(place2, nowitem);
 795             insmidcode(">", place1, place2, "  ");
 796         }
 797         else if ( symid == GEQ ) {
 798             getsym();
 799             expression();
 800             strcpy(place2, nowitem);
 801             insmidcode(">=", place1, place2, "  ");
 802         }
 803         else if ( symid == NEQ ) {
 804             getsym();
 805             expression();
 806             strcpy(place2, nowitem);
 807             insmidcode("!=", place1, place2, "  ");
 808         }
 809         else if ( symid == EQL ) {
 810             getsym();
 811             expression();
 812             strcpy(place2, nowitem);
 813             insmidcode("==", place1, place2, "  ");
 814         }
 815         return;
 816     }
 817     strcpy(place2, "0");
 818     insmidcode("!=", place1, place2, "  ");
 819     return;
 820 }
 821 
 822 //32.<循環語句>   ::=   while '('<條件>')'<語句>
 823 //                   | for'('<標識符>=<表達式>;<條件>;<標識符>=<標識符>(+|-)<步長>')'<語句>
 824 void loopsentence()
 825 {
 826     int s = 0;
 827     char names[ 30 ], names1[ 30 ], names2[ 30 ], place2[ 30 ], place3[ 30 ];
 828     char label1[ 10 ], label2[ 10 ], op_flag[ 5 ];
 829     strcpy(label1, nextlab());
 830     strcpy(label2, nextlab());
 831     if ( symid == WHILETK ) {
 832         getsym();
 833         if ( symid != LPARENT ) {
 834             error(LEFTPARENTLACK, 1);
 835             return;
 836         }
 837         insmidcode("lab:", "  ", "  ", label1);
 838         getsym();
 839         condition();
 840         if ( symid != RPARENT ) {
 841             error(RIGHTPARENTLACK, 1);
 842             return;
 843         }
 844         insmidcode("jne", "  ", "  ", label2);
 845         getsym();
 846         sentence();
 847         insmidcode("jmp", "  ", "  ", label1);
 848         insmidcode("lab:", "  ", "  ", label2);
 849         return;
 850     }
 851 
 852     if ( symid == FORTK ) {    //for|(...)
 853         getsym();
 854         if ( symid != LPARENT ) {//for(|...)
 855             error(LEFTPARENTLACK, 1);
 856             return;
 857         }
 858         getsym();
 859 
 860         if ( symid != IDEN ) {    //for(i|=x;...;...)
 861             error(UNACCEPTABLESENTENCE);//不合法的句子
 862             return;
 863         }
 864         strcpy(names, id.c_str());
 865         getsym();
 866         if ( symid != ASSIGN ) {    //for(i=|..;...;...)
 867             error(UNACCEPTABLESENTENCE);
 868             return;
 869         }
 870         s = searchst(names, 0);
 871         if ( s < 0 ) {     //如果是常量
 872             if ( s == -1 ) error(VARNOTDEFINE, 1);  //"="左邊是不合法的標識符
 873             else    error(ASSIGNCONST);
 874             return;
 875         }
 876         getsym();
 877         expression();    //for(i=a+b|;...;...)
 878         insmidcode("=", nowitem, "  ", names);
 879         if ( symid != SEMICN ) {
 880             error(SEMICOLONLACK, 2);
 881             return;
 882         }
 883         getsym();//for(i=a+b;|...;...)
 884         insmidcode("lab:", "  ", "  ", label1);
 885         condition();//for(i=a+b;...;|...)
 886         insmidcode("jne", "  ", "  ", label2);
 887         if ( symid != SEMICN ) {
 888             error(SEMICOLONLACK, 2);
 889             return;
 890         }
 891         getsym();        //for(i=a+b;...;|...)
 892         //<標識符>=<標識符>(+|-)<步長>!!!!!!!!!!!
 893         if ( symid != IDEN ) {
 894             error(IDENTIFIERLACK, 3);
 895             return;
 896         }
 897         strcpy(names1, id.c_str());
 898         s = searchst(names1, 0);
 899         if ( s < 0 ) {     //如果是常量
 900             if ( s == -1 ) error(VARNOTDEFINE, 1);  //"="左邊是不合法的標識符
 901             else    error(ASSIGNCONST);
 902             return;
 903         }
 904         getsym();
 905         if ( symid != ASSIGN ) {
 906             error(UNACCEPTABLESENTENCE);
 907             return;
 908         }
 909         getsym();
 910         if ( symid != IDEN ) {
 911             error(IDENTIFIERLACK, 3);
 912             return;
 913         }
 914         strcpy(names2, id.c_str());
 915         s = searchst(names2, 0);
 916         if ( s < 0 ) {     //如果是常量
 917             if ( s == -1 ) error(VARNOTDEFINE, 1);  //"="左邊是不合法的標識符
 918             else    error(ASSIGNCONST);
 919             return;
 920         }
 921 
 922         getsym();
 923         if ( symid != PLUS && symid != MINU ) {
 924             error(PLUSMINULACK);
 925             return;
 926         }
 927         if ( symid == PLUS ) strcpy(op_flag, "+ ");
 928         else if ( symid == MINU ) strcpy(op_flag, "- ");
 929 
 930         getsym();
 931         if ( symid != INTCON || num == 0 ) {
 932             error(UNKNOWRIGHTSYM, 1);     //等號右邊不是合法的整數
 933             return;
 934         }
 935         strcpy(place2, id.c_str());
 936 
 937         getsym();
 938         if ( symid != RPARENT ) {
 939             error(RIGHTPARENTLACK, 1);
 940             return;
 941         }
 942 
 943         getsym();
 944         sentence();
 945         strcpy(place3, nextvar());
 946         insmidcode(op_flag, names2, place2, place3);
 947         insmidcode("=", place3, "  ", names1);
 948 
 949         insmidcode("jmp", "  ", "  ", label1);
 950         insmidcode("lab:", "  ", "  ", label2);
 951         return;
 952     }
 953 }
 954 
 955 //28.<語句>    ::= <條件語句>|<循環語句>|‘{’<語句列>‘}’|<有返回值函數調用語句>;
 956 //|<無返回值函數調用語句>;|<賦值語句>;|<讀語句>;|<寫語句>;|<空>;|<返回語句>;
 957 void sentence(){
 958     int s;
 959 
 960     //條件語句
 961     if ( symid == IFTK ) {
 962         ifsentence();
 963         return;
 964     }
 965 
 966     //循環語句
 967     if ( symid == WHILETK || symid == FORTK ) {
 968         loopsentence();
 969         return;
 970     }
 971 
 972     //{‘語句列’}
 973     if ( symid == LBRACE ) {
 974         getsym();
 975         sentencelist();
 976         //缺“}”
 977         if ( symid != RBRACE ) {
 978             error(RIGHTBRACELACK, 1);
 979             return;
 980         }
 981         //不缺“}”
 982         getsym();
 983         return;
 984     }
 985 
 986     //函數調用語句|<賦值語句>;
 987     
 988     if ( symid == IDEN ) {
 989         int isVec = 0;
 990         char names[ MAXIDENLEN ];
 991         strcpy(names, id.c_str());
 992         getsym();
 993         //<賦值語句>;
 994         //29.<賦值語句>   ::=  <標識符>=<表達式>|<標識符>'['<表達式>']'=<表達式>
 995         char place2[ 100 ];
 996         if ( symid == LBRACK ){ //如果是數組
 997             s = searchst(names, 0);
 998             if ( s == -1 )
 999             {
1000                 error(VARNOTDEFINE, 1);
1001                 return;
1002             }
1003             getsym();
1004             expression();
1005             strcpy(place2, nowitem);
1006             if (isdigit(nowitem[0])){
1007                 int arrnums = 0;
1008                 arrnums = arrnum(names);
1009                 if (atoi(nowitem) >= arrnums){
1010                     printf("Warning: Line:%d index of array out of boundary, which should be less than %d.\n",lnum, atoi(nowitem));
1011                 }
1012             }
1013             isVec = 1;
1014             if ( symid != RBRACK ) {
1015                 error(RIGHTBRACKLACK, 1);
1016                 return;
1017             }
1018             getsym();
1019         }
1020         if ( symid == ASSIGN ) {
1021             s = searchst(names, 0);
1022             if ( s < -1 ) {     //如果是常量
1023                 error(ASSIGNCONST);            //"="左邊是不合法的標識符
1024                 return;
1025             }
1026             getsym();
1027             expression();
1028             if ( isVec ){
1029                 insmidcode("[]=", names, place2, nowitem);
1030             }
1031             else{
1032                 insmidcode("=", nowitem, "  ", names);
1033             }
1034             
1035             if ( symid != SEMICN ) {
1036                 error(SEMICOLONLACK, 2);
1037                 return;
1038             }
1039             getsym();
1040             return;
1041         }
1042 
1043         //函數調用語句
1044         if ( symid == LPARENT ) {
1045             getsym();
1046             valueofpara();  //計算並記錄參數的值以及個數
1047             if ( symid != RPARENT ) {
1048                 error(RIGHTPARENTLACK, 1);
1049                 return;
1050             }
1051             s = searchst(names, 1);
1052             if ( s == -1 * FUNCTIONNOTFOUND ) {
1053                 error(FUNCTIONNOTFOUND);
1054                 return;
1055             }
1056             else if ( s == -1 * FORMALPARANUMUNMATCH ){
1057                 error(FORMALPARANUMUNMATCH, 1);
1058                 return;
1059             }
1060             insmidcode("call", names, "  ", "  ");
1061             getsym();
1062             if ( symid != SEMICN ) {
1063                 error(SEMICOLONLACK, 2);
1064                 return;
1065             }
1066             getsym();
1067         }
1068 
1069         else {
1070             error(UNACCEPTABLESENTENCE);    //不合法的句子
1071             return;
1072         }
1073         return;
1074     }
1075 
1076     //讀語句
1077     if ( symid == SCANFTK ) {
1078         scanfsentence();
1079         if ( symid != SEMICN ) {
1080             error(SEMICOLONLACK, 2);
1081             return;
1082         }
1083         getsym();
1084         return;
1085     }
1086 
1087     //寫語句
1088     if ( symid == PRINTFTK ) {
1089         printfsentence();
1090         if ( symid != SEMICN ) {
1091             error(SEMICOLONLACK, 2);
1092             return;
1093         }
1094         getsym();
1095         return;
1096     }
1097 
1098     //返回語句
1099     if ( symid == RETURNTK ) {
1100         returnsentence();
1101         //返回語句后缺“;”
1102         if ( symid != SEMICN ) {
1103             error(SEMICOLONLACK, 2);
1104             return;
1105         }
1106         getsym();
1107         return;
1108     }
1109     if ( symid == SEMICN )
1110     {
1111         getsym();
1112         return;
1113     }
1114 
1115     //不合法的句子
1116     error(UNACCEPTABLESENTENCE);
1117     return;
1118 }
1119 
1120 //36.<值參數表>   ::=   <表達式>{,<表達式>}|<空>
1121 void valueofpara()
1122 {
1123     int j = 0;
1124     vector<string> paraqueue;
1125     do {
1126         if ( symid == COMMA )
1127             getsym();
1128         if ( symid == PLUS || symid == MINU || symid == IDEN || symid == LPARENT || symid == CHARCON || symid == INTCON ) {
1129             expression();
1130             paraqueue.push_back(nowitem);
1131             j++;
1132         }
1133     } while ( symid == COMMA );
1134     char tc[ 20 ];
1135     for ( int i = 0; i < paraqueue.size(); i++ ) {
1136         strcpy(tc, paraqueue[ i ].c_str());
1137         insmidcode("fupa", "  ", "  ", tc);
1138     }
1139     paranum = j;
1140     paraqueue.~vector();
1141     return;
1142 }
1143 
1144 //38.<讀語句>    ::=  scanf ‘(’<標識符>{,<標識符>}‘)’
1145 void scanfsentence()
1146 {
1147     char names[ 30 ];
1148     int s;
1149     getsym();
1150     if ( symid != LPARENT ) {
1151         error(LEFTPARENTLACK, 1);
1152         return;
1153     }
1154 
1155     do{
1156         getsym();
1157         if ( symid != IDEN ) {
1158             error(IDENTIFIERLACK, 3);         //不合法的標志符
1159             return;
1160         }
1161         strcpy(names, id.c_str());
1162         s = searchst(names, 0);
1163         if ( s < 0 ) {
1164             if ( s == -1 )
1165                 error(VARNOTDEFINE, 1);            //未定義標志符
1166             else
1167                 error(ASSIGNCONST, 1);
1168             return;
1169         }
1170         insmidcode("scf", "  ", "  ", names);
1171         getsym();
1172     } while ( symid == COMMA );
1173 
1174     if ( symid != RPARENT ) {
1175         error(RIGHTPARENTLACK, 1);
1176         return;
1177     }
1178     getsym();
1179     return;
1180 }
1181 
1182 //39.<寫語句>    ::=   printf ‘(’<字符串>,<表達式>‘)’|
1183 //                     printf ‘(’<字符串>‘)’| printf ‘(’<表達式>‘)’
1184 void printfsentence()
1185 {
1186     char place1[ 200 ] = "", place2[ 30 ] = ""; //place1是字符串,place2是表達式
1187     getsym();
1188     if ( symid != LPARENT ) {
1189         error(LEFTPARENTLACK, 1);
1190         return;
1191     }
1192     getsym();
1193     if ( symid == STRCON ) {
1194         strcpy(place1, id.c_str());
1195         getsym();
1196         if ( symid == COMMA ) {
1197             getsym();
1198             expression();
1199             strcpy(place2, nowitem);
1200         }
1201     }
1202     else {
1203         expression();
1204         strcpy(place2, nowitem);
1205     }
1206     if ( symid != RPARENT ) {
1207         error(RIGHTPARENTLACK, 1);
1208         return;
1209     }
1210     insmidcode("prt", place1, place2, (factclass == CHAR) ? "char" : "int");
1211     getsym();
1212     return;
1213 }
1214 
1215 //40.<返回語句>   ::=  return[‘(’<表達式>‘)’]
1216 void returnsentence()
1217 {
1218     char place3[ 30 ];
1219     getsym();
1220     if ( symid == LPARENT ) {
1221         getsym();
1222         expression();//表達式子程序
1223         strcpy(place3, nowitem);
1224         if ( symid != RPARENT ) {
1225             error(RIGHTPARENTLACK, 1);
1226             return;
1227         }
1228         insmidcode("ret", "  ", "  ", place3);
1229         returnnum++;
1230         getsym();
1231         return;
1232     }
1233     insmidcode("ret", "  ", "  ", "  ");
1234     return;
1235 }
1236 
1237 //25.<表達式>    ::= [+|-]<項>{<加法運算符><項>}
1238 void expression()
1239 {
1240     factclass = 0;
1241     char place1[ 30 ], place2[ 30 ], place3[ 30 ];
1242     //有+|-的情況
1243     if ( symid == PLUS || symid == MINU ) {
1244         factclass = INT;
1245         if ( symid == PLUS ) {
1246             getsym();
1247             item();//項,結束后,項的結果會放入全局變量nowitem
1248             strcpy(place3, nowitem);//把項的結果放入臨時變量的位置
1249         }
1250         if ( symid == MINU ) {
1251             getsym();
1252             item();//
1253             strcpy(place1, nowitem);
1254             strcpy(place3, nextvar());
1255             insmidcode("-", "0 ", place1, place3); //place3 = 0 - (place1)
1256         }
1257     }
1258     else {
1259         item();
1260         strcpy(place3, nowitem);
1261     }
1262     while ( symid == PLUS || symid == MINU ) {
1263         factclass = INT;
1264         strcpy(place1, place3);
1265         if ( symid == PLUS ) {
1266             getsym();
1267             item();
1268             strcpy(place2, nowitem);
1269             strcpy(place3, nextvar());
1270             insmidcode("+", place1, place2, place3);
1271             continue;
1272         }
1273         else {
1274             getsym();
1275             item();
1276             strcpy(place2, nowitem);
1277             strcpy(place3, nextvar());
1278             insmidcode("-", place1, place2, place3);
1279             continue;
1280         }
1281     }
1282     strcpy(nowitem, place3);//把表達式的最終值存放在p之中
1283     return;
1284 }
1285 
1286 //26.<項>     ::= <因子>{<乘法運算符><因子>}
1287 void item()
1288 {
1289     char place1[ 200 ], place2[ 200 ], place3[ 200 ];
1290     factor();
1291     strcpy(place3, nowitem);//這種操作是為了對付只有賦值的情況
1292     while ( symid == MULT || symid == DIV ) {
1293         factclass = INT;
1294         strcpy(place1, place3);
1295         if ( symid == MULT ) {
1296             getsym();
1297             factor();
1298             strcpy(place2, nowitem);
1299             strcpy(place3, nextvar());//申請臨時變量
1300             insmidcode("*", place1, place2, place3);
1301             continue;
1302         }
1303         if ( symid == DIV ) {
1304             getsym();
1305             factor();
1306             strcpy(place2, nowitem);
1307             strcpy(place3, nextvar());
1308             insmidcode("/", place1, place2, place3);
1309             continue;
1310         }
1311     }
1312     strcpy(nowitem, place3);  //每一個項,計算后的值都在變量nowitem里面
1313     return;
1314 }
1315 
1316 
1317 //27.<因子>    ::= <標識符>|<標識符>‘[’<表達式>‘]’|<整數>|<字符>|<有返回值函數調用語句>|‘(’<表達式>‘)’
1318 void factor()
1319 {
1320     int t = -1;
1321     char names[ 30 ], place3[ 30 ];
1322     //<標識符>|<有返回值函數調用語句>
1323     if ( symid == IDEN ) {
1324         strcpy(names, id.c_str());
1325         getsym();
1326         //如果有左括號,則是<有返回值函數調用語句>
1327         if ( symid == LPARENT ) {
1328             getsym();
1329             valueofpara();
1330             if ( symid != RPARENT ) {
1331                 error(LEFTPARENTLACK, 2);
1332                 return;
1333             }
1334             t = searchst(names, 1);
1335             if ( t < 0 ) {
1336                 if ( t == -1 * FUNCTIONRETURNNULL )
1337                     error(FUNCTIONRETURNNULL);   //函數無返回值,不能出現在表達式中
1338                 else if ( t == -1 * FUNCTIONNOTFOUND )
1339                     error(FUNCTIONNOTFOUND, 1);
1340                 return;
1341             }
1342             strcpy(place3, nextvar());//生成臨時變量
1343             insmidcode("call", names, "  ", place3);//將調用的返回值存放在臨時變量里面
1344             strcpy(nowitem, place3);
1345             getsym();
1346             return;
1347         }
1348 
1349         //如果是變量、數組、
1350         else if ( symid != LBRACK ){
1351             t = searchst(names, 0);      //查表,查找到標識符對應的地址
1352             if (t == -1) {
1353                 error(IDENTIFIERLACK, 4);
1354                 return;
1355             }
1356             if ( t < -1 ) {
1357                 t = -t / 2;
1358             }
1359             strcpy(nowitem, names);
1360         }
1361         else if ( symid == LBRACK ){      //如果是數組
1362             getsym();
1363             int tclass = factclass;
1364             expression();
1365             factclass = tclass;
1366             char ttt[ 30 ];
1367             strcpy(ttt, nowitem);
1368             
1369             if (isdigit(nowitem[0])){
1370                 int arrnums = 0;
1371                 arrnums = arrnum(names);
1372                 if (atoi(ttt) >= arrnums){
1373                     printf("Warning: Line:%d index of array out of boundary, which should be less than %d.\n",lnum, atoi(ttt));
1374                 }
1375             }
1376             if ( symid != RBRACK ) {
1377                 error(RIGHTBRACKLACK);
1378                 return;
1379             }
1380             else{
1381                 strcpy(nowitem, nextvar());
1382                 insmidcode("geta", names, ttt, nowitem);
1383                 getsym();
1384             }
1385         }
1386         return;
1387     }
1388 
1389     //'('<表達式>')'
1390     if ( symid == LPARENT ) {
1391         getsym();
1392         expression();
1393         if ( symid != RPARENT ) {
1394             error(RIGHTPARENTLACK, 2);
1395             return;
1396         }
1397         getsym();
1398         return;
1399     }
1400 
1401     // <整數>|<字符>
1402     if ( symid == PLUS || symid == MINU || symid == INTCON || symid == CHARCON ) {
1403         int temp = 1;
1404         if ( symid == PLUS )
1405             getsym();
1406         else if ( symid == MINU ) {
1407             temp = -1;
1408             getsym();
1409         }
1410         if ( symid != INTCON ) {
1411             if ( symid == CHARCON ){
1412                 if ( factclass != INT ) {
1413                     factclass = CHAR;
1414                 }
1415                 sprintf(nowitem, "%d", id.c_str()[0]);
1416                 getsym();
1417                 return;
1418             }
1419             error(IMMLACK);
1420             return;
1421         }
1422         sprintf(nowitem, "%d", temp * num);
1423         factclass = INT;
1424         getsym();
1425         return;
1426     }
1427 
1428     error(EXPRESSIONERROR);                  //表達式缺失或錯誤
1429     return;
1430 }
 1 //
 2 //  midcode.cpp
 3 //  exc0compiler
 4 //
 5 //  Created by sciencefans on 14/11/29.
 6 //  Copyright (c) 2014年 sciencefans. All rights reserved.
 7 //
 8 
 9 
10 
11 #include "glob.h"
12 
13 fourvarcode midcode[ MAXMIDCODE ];
14 int midcodeiter = 0;
15 int labelcnt = 0;
16 int varcnt = 0;
17 vector <char*> hisvar;
18 
19 char* itoa(int i){
20     char *temp = (char*)malloc(sizeof(char) * 10);
21     sprintf(temp, "%d", i);
22     return temp;
23 }
24 
25 //插入中間代碼
26 void insmidcode(char* op, char* t1, char* t2, char* t3){
27     if ( strcmp(op, "func") == 0 ){
28         midcoderst << endl << endl;
29     }
30     midcoderst << "\t\t";
31     midcoderst << op << "\t," << t1 << "\t," << t2 << "\t," << t3 << endl;
32     strcpy(midcode[ midcodeiter ].op, op);
33     strcpy(midcode[ midcodeiter ].var1, t1);
34     strcpy(midcode[ midcodeiter ].var2, t2);
35     strcpy(midcode[ midcodeiter ].var3, t3);
36     midcodeiter++;
37 }
38 void insmidcode(char* op, int t1, int t2, char* t3){
39     midcoderst << "\t\t";
40     midcoderst << op << "\t," << t1 << "\t," << t2 << "\t," << t3 << endl;
41     strcpy(midcode[ midcodeiter ].op, op);
42     char *t;
43 
44     strcpy(midcode[ midcodeiter ].var1, strcmp(t = itoa(t1), "0") == 0 ? "  " : t);
45     strcpy(midcode[ midcodeiter ].var2, t = itoa(t2));
46     strcpy(midcode[ midcodeiter ].var3, t3);
47     midcodeiter++;
48     free(t);
49 }
50 void insmidcode(char* op, char* t1, int t2, char* t3){
51     midcoderst << "\t\t";
52     midcoderst << op << "\t," << t1 << "\t," << t2 << "\t," << t3 << endl;
53     strcpy(midcode[ midcodeiter ].op, op);
54     char *t;
55     strcpy(midcode[ midcodeiter ].var1, t1);
56     strcpy(midcode[ midcodeiter ].var2, t = itoa(t2));
57     strcpy(midcode[ midcodeiter ].var3, t3);
58     midcodeiter++;
59     free(t);
60 }
61 //生成新的標記
62 char* nextlab(){
63     char *label = (char*)malloc(sizeof(char) * 20);
64     strcpy(label, "_LABEL_");
65     sprintf(label, "_LABEL_%d", labelcnt++);
66     return label;
67 }
68 
69 //生成新的變量
70 char* nextvar()
71 {
72     char *var = (char*)malloc(sizeof(char) * 20);
73     sprintf(var, "$_%d", varcnt++);
74     //insmidcode("int", "  ", "  ", var);
75     hisvar.push_back(var);
76     return var;
77 }
78 
79 void freetempvar(){
80     for ( int i = 0; i < hisvar.size(); i++ ) {
81         free(hisvar[ i ]);
82     }
83 }
 1 //
 2 //  main.cpp
 3 //  exc0compiler
 4 //
 5 //  Created by sciencefans on 14/11/22.
 6 //  Copyright (c) 2014年 sciencefans. All rights reserved.
 7 //
 8 
 9 
10 #include "glob.h"
11 #include "err.h"
12 int mf;
13 ofstream laxrst, midcoderst, asmrst, symtablehis;
14 FILE* optcodefile;
15 int main(int argc, char **argv){
16     char filename[500] = "in.c";
17     printf("Input the source file:\n");
18     char tempsrc[ 500 ];
19     gets(tempsrc);
20     if ( strlen(tempsrc) > 2 )
21         if ( tempsrc[ 0 ] == '\"' ){
22             strcpy(filename, tempsrc + 1 );
23             filename[ strlen(filename) - 1 ] = 0;
24         }else            
25             strcpy(filename, tempsrc);
26     src = fopen(filename, "r");
27     if ( src == NULL )
28     {
29         error(NOSUCHFILE);
30         system("pause");
31         return 0;
32     }
33     laxrst.open("laxrst.txt");
34     midcoderst.open("midcode.txt");
35     asmrst.open("asmrst.asm");
36     symtablehis.open("symbolTable.txt");
37     symtablehis << "index" << "\t" << "name" << "\t" << "kind" << "\t" << "value" << "\t" << "address" << "\t" << "paranum" << "\t" << "isVec" << endl;
38     getch();
39     program();
40 
41     if ( mf < 1 ) error(MAINLACK);                         //沒有定義主函數
42     do  getsym(); while ( ch == '\n' || ch == ' ' || ch == '\t' );
43     if ( symid != -1 )  error(MOREWORD);                //主函數后有多余的代碼
44 
45     if ( errnum == 0 ) {
46         printf("\n\n編譯成功,沒有語法語義錯誤!\n\n");
47         printOptimize();     //打印優化后的四元式
48         printf("四元式 生成完成...\n");
49         midcode2asm();   //生成匯編碼
50         printf("匯編指令 生成完成...\n");
51         scan();          //掃描四元式結構數組,完成優化
52         printOptimize();
53         printf("優化后的四元式 生成完成...\n");
54     }
55 
56     laxrst.close();
57     asmrst.close();
58     midcoderst.close();
59     symtablehis.close();
60     fclose(src);
61     
62     printf("\n-----------------------------\n");
63     if ( errnum == 0 )
64     {
65         printf("Compile Success.\n");
66     }
67     printf("Errors:\t%d\tTotal Line: %d\n", errnum, lnum);
68     system("pause");
69     return 0;
70 }
  1 #include "err.h"
  2 #include "glob.h"
  3 
  4 #define QUIT 1
  5 #define DONOTHING 2
  6 #define ICV    3
  7 #define CICVIFIRSP 4
  8 #define CS    5
  9 #define CLR 6
 10 #define IWFRSPIFCV 7
 11 #define IWFLIRSPE 8
 12 #define IWFXXXANE 9
 13 int errnum = 0;
 14 
 15 void error(int _errsig, int signal){
 16     int errclass = -1;
 17     errnum++;
 18     printf("Error %d: LINE %d, COLUMN %d: Near \"%s\" : ", errnum, cnum == 0 ? lnum - 1 : lnum, cnum == 0 ? prllen : cnum + 1, prid.c_str());
 19     switch ( _errsig ) {
 20         case  NOSUCHFILE:            errclass = QUIT;    printf("NO SUCH FILE\n");    break;
 21         case  FILEINCOMPLETE:        errclass = DONOTHING;    printf("FILEINCOMPLETE\n");    break;
 22         case  DOUBLEQUOTESLACK:        errclass = DONOTHING;    printf("DOUBLEQUOTESLACK\n");    break;
 23         case  UNACCEPTATLECHAR:        errclass = DONOTHING;    printf("UNACCEPTATLECHAR\n");    break;
 24         case  SINGLEQUOTESLACK:        errclass = DONOTHING;    printf("SINGLEQUOTESLACK\n");    break;
 25         case  OUTOFTABLE:            errclass = QUIT;    printf("OUT OF TABLE\n");    break;
 26         case  SYMBOLCONFLICT:        errclass = DONOTHING;    printf("SYMBOL CONFLICT\n");    break;
 27         case  CSTDEFINEFAIL:        errclass = CS;    printf("CST DEFINE FAIL\n");    break;
 28         case  VARNOTINIT:            errclass = DONOTHING;    printf("VARNOTINIT\n");    break;
 29         case  UNKNOWRIGHTSYM:        errclass =
 30             signal == 0 ? CS :
 31             signal == 1 ? IWFLIRSPE :
 32             -1;
 33             printf("UNKNOWRIGHTSYM\n");    break;
 34         case  SEMICOLONLACK:        errclass =
 35             signal == 0 ? CICVIFIRSP :
 36             signal == 1 ? IWFRSPIFCV :
 37             signal == 2 ? IWFLIRSPE :
 38             -1;
 39             printf("SEMICOLONLACK\n");
 40             break;
 41         case  KEYWORDERROR:
 42             errclass = signal == 0 ? CICVIFIRSP :
 43                 signal == 1 ? CLR :
 44                 signal == 2 ? IWFRSPIFCV :
 45                 printf("KEYWORDERROR\n");
 46             break;
 47         case  IDENTIFIERLACK:        errclass =
 48             signal == 0 ? ICV :
 49             signal == 1 ? CLR :
 50             signal == 2 ? IWFRSPIFCV :
 51             signal == 3 ? IWFLIRSPE :
 52             signal == 4 ? IWFXXXANE :
 53             -1;
 54             printf("IDENTIFIER LACK\n");
 55             break;
 56         case  RIGHTBRACKLACK:        errclass =
 57             signal == 0 ? IWFXXXANE :
 58             signal == 1 ? IWFRSPIFCV :
 59             -1;
 60             printf("RIGHT BRACK LACK\n");
 61             break;
 62         case  FUNCTIONNOTFOUND:        errclass = 
 63             signal == 0 ? IWFLIRSPE :
 64             signal == 1 ? IWFXXXANE :
 65             -1;    
 66             printf("FUNCTION NOT FOUND\n");    break;
 67         case  FORMALPARANUMUNMATCH:    errclass =
 68             signal == 0 ? DONOTHING :
 69             signal == 1 ? IWFLIRSPE :
 70             -1;
 71             printf("FORMAL PARA NUM UNMATCH\n");    break;
 72         case  VARNOTDEFINE:            errclass =
 73             signal == 0 ? DONOTHING :
 74             signal == 1 ? IWFLIRSPE :
 75             -1;
 76             printf("VAR NOT DEFINE\n");    break;
 77         case  LEFTPARENTLACK:        errclass =
 78             signal == 0 ? ICV :
 79             signal == 1 ? IWFLIRSPE :
 80             signal == 2 ? IWFXXXANE :
 81             -1;
 82             printf("LEFT PARENT LACK\n");    break;
 83         case  RIGHTPARENTLACK:        errclass =
 84             signal == 0 ? ICV :
 85             signal == 1 ? IWFLIRSPE :
 86             signal == 2 ? IWFXXXANE :
 87             -1;
 88             printf("RIGHT PARENT LACK\n");    break;
 89         case  IMMLACK:                errclass = IWFRSPIFCV;    printf("IMM LACK\n");    break;
 90         case  RIGHTBRACELACK:        errclass =
 91             signal == 0 ? ICV :
 92             signal == 1 ? IWFLIRSPE :
 93             -1;    printf("RIGHT BRACE LACK\n");    break;
 94         case  FUNCTIONRETURNNULL:    errclass = IWFXXXANE;    printf("FUNCTION RETURN NULL\n");    break;
 95         case  EXPRESSIONERROR:        errclass = IWFXXXANE;    printf("EXPRESSION ERROR\n");    break;
 96         case  UNACCEPTABLESENTENCE:    errclass = IWFLIRSPE;    printf("UNACCEPTABLE SENTENCE\n");    break;
 97         case  ASSIGNCONST:            errclass =
 98             signal == 0 ? IWFLIRSPE :
 99             signal == 1 ? IWFLIRSPE :
100             -1;
101             printf("ASSIGN CONST\n");    break;
102         case  LEFTBRACELACK:        errclass = ICV;    printf("LEFT BRACE LACK\n");    break;
103         case  NONERETURN:            errclass = ICV;    printf("NON ERETURN\n");    break;
104         case  PLUSMINULACK:            errclass = IWFLIRSPE;    printf("PLUS or MINU LACK\n");    break;
105         case  MAINLACK:                errclass = DONOTHING;    printf("MAIN LACK\n");    break;
106         case  MOREWORD:                errclass = DONOTHING;    printf("MORE WORD\n");    break;
107         case  CONSTNOTINIT:        errclass = CS;    printf("CONST NOT INIT\n");    break;
108         default:                    errclass = QUIT;    printf("Unknow error occurs! [error code: %d]\n", _errsig);
109     }
110     /*
111     laxrst.close();
112     asmrst.close();
113     midcoderst.close();
114     symtablehis.close();
115     fclose(src);
116     system("pause");
117     exit(0);
118     */
119     switch ( errclass ){
120         case QUIT:
121             system("pause");
122             exit(0);
123             break;
124         case DONOTHING:
125             break;
126         case ICV:
127             while ( symid != INTTK && symid != CHARTK && symid != VOIDTK ) {
128                 if ( symid == -1 )
129                 {
130                     system("pause");    exit(0);
131                 }
132                 getsym();
133             }
134             break;
135         case CICVIFIRSP:
136             while ( symid != CONSTTK && symid != INTTK && symid != CHARTK && symid != VOIDTK && symid != IFTK && symid != WHILETK
137                 && symid != FORTK && symid != IDEN && symid != RETURNTK && symid != SCANFTK && symid != PRINTFTK ){
138                 if ( symid == -1 ) { system("pause");    exit(0); }
139                 getsym();
140             }
141             break;
142         case CS:
143             while ( symid != COMMA && symid != SEMICN ) {
144                 if ( symid == -1 ) { system("pause");    exit(0); }
145                 getsym();
146             }
147             break;
148         case CLR:
149             while ( symid != COMMA && symid != LPARENT && symid != RPARENT ) {
150                 if ( symid == -1 ) { system("pause");    exit(0); }
151                 getsym();
152             }
153             break;
154         case IWFRSPIFCV:
155             while ( symid != IFTK && symid != WHILETK && symid != FORTK && symid != RETURNTK && symid != SCANFTK
156                 && symid != PRINTFTK && symid != INTTK && symid != CHARTK && symid != VOIDTK ) {
157                 if ( symid == -1 ) { system("pause");    exit(0); }
158                 getsym();
159             }
160             break;
161         case IWFLIRSPE:
162             while ( symid != IFTK && symid != WHILETK && symid != FORTK && symid != LBRACK && symid != IDEN
163                 && symid != RETURNTK && symid != SCANFTK && symid != PRINTFTK && symid != ELSETK && symid != RBRACE) {
164                 if ( symid == -1 ) { system("pause");    exit(0); }
165                 getsym();
166             }
167             break;
168         case IWFXXXANE:
169             while ( symid != IFTK && symid != WHILETK && symid != FORTK && symid != LBRACK && symid != IDEN && symid != RETURNTK
170                 && symid != SCANFTK && symid != PRINTFTK && symid != SEMICN && symid != ELSETK && symid != RPARENT
171                 && symid != COMMA && symid != PLUS && symid != MINU && symid != MULT && symid != DIV
172                 && symid != LSS && symid != LEQ && symid != GRE && symid != GEQ && symid != NEQ && symid != EQL ) {
173                 if ( symid == -1 ) { system("pause");    exit(0); }
174                 getsym();
175             }
176             break;
177         default:
178             break;
179     }
180 
181 }
  1 #include <string.h>
  2 #include "glob.h"
  3 
  4 int codeindex = 0;
  5 
  6 
  7 //掃描這個四元式數組,處理所有的基本塊
  8 void scan()
  9 {
 10     //找到函數開始
 11     while ( strcmp(midcode[ codeindex ].op, "func") != 0 ) codeindex++;
 12 
 13     while ( codeindex < midcodeiter ) {
 14         combine();
 15         delpublic();
 16         codeindex++;
 17     }
 18     delsetlab();
 19     return;
 20 }
 21 
 22 //合並常數
 23 void combine() {
 24     int i = codeindex, num1, num2, temp;
 25     char sum[ 30 ];
 26     while ( strcmp(midcode[ i ].op, "+") == 0 || strcmp(midcode[ i ].op, "-") == 0 || strcmp(midcode[ i ].op, "*") == 0 || strcmp(midcode[ i ].op, "/") == 0 ) {
 27         if ( isconst(midcode[ i ].var1) && isconst(midcode[ i ].var2) ) {
 28             num1 = atoi(midcode[ i ].var1);
 29             num2 = atoi(midcode[ i ].var2);
 30             if ( strcmp(midcode[ i ].op, "+") == 0 ) temp = num1 + num2;
 31             if ( strcmp(midcode[ i ].op, "-") == 0 ) temp = num1 - num2;
 32             if ( strcmp(midcode[ i ].op, "*") == 0 ) temp = num1*num2;
 33             if ( strcmp(midcode[ i ].op, "/") == 0 ) temp = num1 / num2;
 34             sprintf(sum, "%d", temp);
 35             strcpy(midcode[ i ].op, "=");
 36             strcpy(midcode[ i ].var1, sum);
 37             strcpy(midcode[ i ].var2, "  ");
 38         }
 39         i++;
 40     }
 41 }
 42 
 43 //刪除公共子表達式
 44 void delpublic()
 45 {
 46     int i, j, h, k;
 47     //划分基本塊
 48     for ( i = codeindex; strcmp(midcode[ i ].op, "+") == 0 || strcmp(midcode[ i ].op, "-") == 0 || strcmp(midcode[ i ].op, "*") == 0 || strcmp(midcode[ i ].op, "/") == 0 || strcmp(midcode[ i ].op, "=") == 0; i++ ) {
 49         if ( i >= midcodeiter ){
 50             return;
 51         }
 52         if ( midcode[ i ].var3[ 0 ] == '$' ) {
 53             for ( j = i + 1; strcmp(midcode[ j ].op, "+") == 0 || strcmp(midcode[ j ].op, "-") == 0 || strcmp(midcode[ j ].op, "*") == 0 || strcmp(midcode[ j ].op, "/") == 0 || strcmp(midcode[ j ].op, "=") == 0; j++ ) {
 54                 if ( j >= midcodeiter ){
 55                     return;
 56                 }
 57                 //尋找公共子表達式
 58                 if ( strcmp(midcode[ j ].op, midcode[ i ].op) == 0 && strcmp(midcode[ j ].var1, midcode[ i ].var1) == 0 && strcmp(midcode[ j ].var2, midcode[ i ].var2) == 0 && midcode[ j ].var3[ 0 ] == '$' ) {
 59                     //修改變量的名字
 60                     for ( h = j + 1; strcmp(midcode[ h ].op, "+") == 0 || strcmp(midcode[ h ].op, "-") == 0 || strcmp(midcode[ h ].op, "*") == 0 || strcmp(midcode[ h ].op, "/") == 0 || strcmp(midcode[ h ].op, "=") == 0; h++ ) {
 61                         if ( h >= midcodeiter ){
 62                             return;
 63                         }
 64                         if ( strcmp(midcode[ h ].var1, midcode[ j ].var3) == 0 )
 65                             strcpy(midcode[ h ].var1, midcode[ i ].var3);
 66                         if ( strcmp(midcode[ h ].var2, midcode[ j ].var3) == 0 )
 67                             strcpy(midcode[ h ].var2, midcode[ i ].var3);
 68                     }
 69                     for ( k = j; k< midcodeiter; k++ ) {
 70                         strcpy(midcode[ k ].op, midcode[ k + 1 ].op);     //刪除
 71                         strcpy(midcode[ k ].var1, midcode[ k + 1 ].var1);
 72                         strcpy(midcode[ k ].var2, midcode[ k + 1 ].var2);
 73                         strcpy(midcode[ k ].var3, midcode[ k + 1 ].var3);
 74                     }
 75                     midcodeiter--;
 76                     j--;
 77                 }
 78             }
 79         }
 80     }
 81 }
 82 
 83 //刪除冗余跳轉代碼
 84 void delsetlab()
 85 {
 86     int i, k, j, t, flag;
 87     char temp[ 30 ][ 10 ];
 88     for ( i = 0; i < midcodeiter; i++ ) {
 89         if ( i >= midcodeiter ){
 90             return;
 91         }
 92         if ( strcmp(midcode[ i ].op, "lab:") == 0 ) {
 93             j = 0;
 94             flag = i;
 95             i = i + 1;
 96             while ( strcmp(midcode[ i ].op, "lab:") == 0 ) {
 97                 strcpy(temp[ j++ ], midcode[ i ].var3);
 98                 for ( k = i; k<midcodeiter; k++ ) {
 99                     strcpy(midcode[ k ].op, midcode[ k + 1 ].op);     //刪除
100                     strcpy(midcode[ k ].var1, midcode[ k + 1 ].var1);
101                     strcpy(midcode[ k ].var2, midcode[ k + 1 ].var2);
102                     strcpy(midcode[ k ].var3, midcode[ k + 1 ].var3);
103                 }
104                 midcodeiter--;
105             }
106             if ( j == 0 ) continue;
107             for ( k = 0; k <= midcodeiter; k++ ) {
108                 if ( k >= midcodeiter ){
109                     return;
110                 }
111                 if ( strcmp(midcode[ k ].op, "jmp") == 0 || strcmp(midcode[ k ].op, "jne") == 0 ) {
112                     for ( t = 0; t<j; t++ ) {
113                         if ( strcmp(midcode[ k ].var3, temp[ t ]) == 0 )
114                             strcpy(midcode[ k ].var3, midcode[ flag ].var3);
115                     }
116                 }
117             }
118         }
119     }
120 }
121 
122 //判斷是不是數字
123 int isconst(char name[])
124 {
125     int i = 0;
126     if ( name[ i ] == '-' ) i++;
127     while ( name[ i ] != '\0' ) {
128         if ( name[ i ]>'9' || name[ i ]<'0' ) return 0;
129         i++;
130     }
131     return 1;
132 }
133 
134 //打印優化后的四元式
135 void printOptimize()
136 {
137     optcodefile = fopen("optMidCode.txt", "w");
138     int i = 0;
139     while ( i<midcodeiter ) {
140         fprintf(optcodefile, "%s,\t", midcode[ i ].op);
141         fprintf(optcodefile, "%s,\t", midcode[ i ].var1);
142         fprintf(optcodefile, "%s,\t", midcode[ i ].var2);
143         fprintf(optcodefile, "%s;\n", midcode[ i ].var3);
144         if ( strcmp(midcode[ i ].op, "end") == 0 )
145             fprintf(optcodefile, "\n\n");
146         i++;
147     }
148     fclose(optcodefile);
149     return;
150 }
  1 #include "glob.h"
  2 #define rsT asmrst
  3 #define VOID 0
  4 #define INT 1
  5 #define CHAR 2
  6 #define WINT 3
  7 #define WCHAR 4
  8 #define INITSTACK 0x7fffeffc
  9 #define INITDATA 0x10010000
 10 #define OPTFLAG 0    //優化開關
 11 
 12 int mi = 0;    //四元式處理的行數
 13 int sp = INITSTACK;    //棧指針,此地址為即將分配的!!相對fp!!地址
 14 int fp = 0;//幀指針
 15 int ap;//地址表計數器
 16 int paran = 0;
 17 int constedge = 0;
 18 int tmi;
 19 int ismain = 0;
 20 int tlabelnum = 0;
 21 int isglob;
 22 int funckin;
 23 int funcnum = 0;
 24 
 25 typedef struct {
 26     char name[ 100 ];
 27     int kind;
 28 }funcclass;
 29 vector<funcclass> fc;//函數表
 30 
 31 typedef struct {
 32     char name[ 100 ];
 33     int address;
 34     int kind;
 35     int cnt;
 36 }tempvaraddress;//變量表
 37 tempvaraddress addrtable[ 1000 ];//臨時變量在棧中的地址表
 38 
 39 typedef struct {
 40     int symbnum;
 41     int cnt;
 42 }cntstruct;
 43 cntstruct cnttable[200];//計數器
 44 int cntindex = 0;
 45 
 46 int varreg[ 200 ];
 47 
 48 bool cmpcnt(cntstruct a, cntstruct b) {
 49     return a.cnt > b.cnt;
 50 }
 51 
 52 int funckind(char *fname) {
 53     for ( int i = 0; i < fc.size(); i++ ) {
 54         if ( strcmp(fc[i].name, fname) == 0 ) {
 55             return fc[ i ].kind;
 56         }
 57     }
 58 }
 59 
 60 int findvartable(char *name) {
 61     int t = ap - 1;
 62     if ( name[ 0 ] == '+' || name[ 0 ] == '-' || name[ 0 ] >= '0'&&name[ 0 ] <= '9' )
 63         return -1;
 64     while ( t >= 0 ) {
 65         if ( strcmp(addrtable[ t ].name, name) == 0 )
 66             return t;
 67         t--;
 68     }
 69     return -1;
 70 }
 71 
 72 int varkind(char *name) {
 73     int t = ap - 1;
 74     if ( name[ 0 ] == '+' || name[ 0 ] == '-' || name[ 0 ] >= '0'&&name[ 0 ] <= '9' )
 75         return -1;
 76     while ( t >= 0 ) {
 77         if ( strcmp(addrtable[ t ].name, name) == 0 )
 78             return addrtable[ t ].kind;
 79         t--;
 80     }
 81     return -1;
 82 }
 83 
 84 void midcode2asm(){
 85     memset(varreg, 0xff, sizeof(int) * 200);
 86     rsT << "\t.text" << endl;
 87     rsT << "\t\tori\t$fp\t$sp\t0" << endl;
 88     rsT << "\t\tli\t$t9\t0x7fffeffc\t#global stack bottom" << endl;
 89     rsT << "\t\tli\t$t8\t0x10010000\t#save word" << endl;
 90     sp = 0;
 91     mi = ap = 0;
 92 
 93     while ( mi < midcodeiter ){
 94         //全局常量定義
 95         while ( strcmp(midcode[ mi ].op, "const") == 0 ) {
 96             pushstack(midcode[ mi ].var2);
 97             if ( strcmp(midcode[ mi ].var1, "int") == 0 ) {
 98                 insertaddress(WINT);
 99             } else {
100                 insertaddress(WCHAR);
101             }
102             mi++;
103         }
104         //全局變量定義
105         while ( strcmp(midcode[ mi ].op, "int") == 0 || strcmp(midcode[ mi ].op, "char") == 0 ) {
106             pushstack("0");
107             if ( strcmp(midcode[ mi ].op, "int") == 0 ) {
108                 insertaddress(WINT);
109             } else {
110                 insertaddress(WCHAR);
111             }
112             mi++;
113         }
114         //全局數組定義
115         while ( strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) {
116             pushstack("0", atoi(midcode[mi].var2));
117             if ( strcmp(midcode[ mi ].op, "inta") == 0 ) {
118                 insertaddress(WINT);
119             } else {
120                 insertaddress(WCHAR);
121             }
122             mi++;
123         }
124         rsT << "\t\tj\t__main" << endl;
125         constedge = ap;
126         //函數定義
127         funcclass tfc;
128         while ( strcmp(midcode[mi].op, "func") == 0 ) {
129             funcnum++;
130             if ( strcmp(midcode[ mi ].var1, "char") == 0 ) {
131                 tfc.kind = CHAR;
132                 strcpy(tfc.name, midcode[ mi ].var3);
133                 fc.push_back(tfc);
134             } else if ( strcmp(midcode[ mi ].var1, "int") == 0 ) {
135                 tfc.kind = INT;
136                 strcpy(tfc.name, midcode[ mi ].var3);
137                 fc.push_back(tfc);
138             } else {
139                 tfc.kind = VOID;
140                 strcpy(tfc.name, midcode[ mi ].var3);
141                 fc.push_back(tfc);
142             }
143             if ( strcmp(midcode[ mi ].var3, "main") == 0 ) {
144                 ismain = 1;
145                 rsT << "__main:" << endl;
146             } else {
147                 ismain = 0;
148                 rsT << midcode[ mi ].var3 << ":" << endl;
149             }
150             mi++;
151             funcasm();
152         }
153     }
154 }
155 
156 //給地址表插入相對地址,sp不變
157 void insertaddress(int kind, int addr, int nmi) {
158     if ( nmi == -1 ) {
159         strcpy(addrtable[ ap ].name, midcode[ mi ].var3);
160     } else {
161         strcpy(addrtable[ ap ].name, midcode[ nmi ].var3);
162     }
163     if ( addr == -1 ) {
164         addrtable[ ap ].address = sp + 4;
165     } else {
166         addrtable[ ap ].address = addr;
167     }
168     addrtable[ ap ].kind = kind;
169     addrtable[ ap ].cnt = 0;
170     ap++;
171 }
172 
173 void pushstack(char* item, int lenth) {
174     if ( lenth == 1 ) {
175         rsT << "\t\tli\t$t0\t" << item << "\t#" << midcode[tmi].var3 << endl; //li    $t0 item
176         rsT << "\t\tsw\t$t0\t($sp)" << endl;      //sw    $t0 $sp
177     }
178     sp -= ( 4 * lenth );
179     rsT << "\t\tsubi\t$sp\t$sp\t" << 4 * lenth << endl; //subi  $sp $sp 4  
180     return;
181 }
182 
183 //處理函數內容,不處理最后的end和開始的func
184 void funcasm() {
185     memset(varreg, 0xff, sizeof(int) * 200);
186     sp = 0;//相對偏移為0
187     //保存現場
188     rsT << "\t\t#Save Register" << endl;//
189     savesreg();
190     rsT << "\t\tsw\t$fp\t($sp)" << endl;//保存上一個函數的$fp
191     rsT << "\t\tadd\t$fp\t$sp\t$0" << endl;//設置本函數$fp:$fp=$sp
192     sp -= 4;
193     rsT << "\t\tsubi\t$sp\t$sp\t4" << endl;//$sp-=4
194     rsT << "\t\tsw\t$ra\t($sp)" << endl;//保存$ra
195     sp -= 4;
196     rsT << "\t\tsubi\t$sp\t$sp\t4" << endl;//$sp-=4
197     rsT << "\t\t#Save Register Done!" << endl;//
198     
199     //while ( strcmp(midcode[ mi ].op, "int") == 0 || strcmp(midcode[ mi ].op, "char") == 0
200     //    || strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) {
201     //    ////變量定義
202     //    //while ( strcmp(midcode[ mi ].op, "int") == 0 || strcmp(midcode[ mi ].op, "char") == 0 ) {
203     //    //    pushstack("0");
204     //    //    if ( strcmp(midcode[ mi ].var1, "int") == 0 ) {
205     //    //        insertaddress(INT);
206     //    //    } else {
207     //    //        insertaddress(CHAR);
208     //    //    }
209     //    //    mi++;
210     //    //}
211     //    ////數組定義
212     //    //while ( strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) {
213     //    //    pushstack("0", atoi(midcode[ mi ].var2));
214     //    //    if ( strcmp(midcode[ mi ].var1, "inta") == 0 ) {
215     //    //        insertaddress(INT);
216     //    //    } else {
217     //    //        insertaddress(CHAR);
218     //    //    }
219     //    //    mi++;
220     //    //}
221     //}
222     //臨時變量定義
223     tmi = mi;
224     while ( strcmp(midcode[ tmi ].op, "end") != 0 ) {
225         char v1[100], v2[100], v3[100];
226         strcpy(v1, midcode[ tmi ].var1);
227         strcpy(v2, midcode[ tmi ].var2);
228         strcpy(v3, midcode[ tmi ].var3);
229         
230 
231         if ( v1[ 0 ] == '$' && varaddr(v1) == -1 ) {
232             pushstack("0");
233             insertaddress(INT, -1, tmi);
234         }
235         if ( v2[ 0 ] == '$' && varaddr(v2) == -1 ) {
236             pushstack("0");
237             insertaddress(INT, -1, tmi);
238         }
239         if ( v3[0] == '$' && varaddr(v3) == -1 ) {
240             pushstack("0");
241             if ( strcmp(midcode[tmi].op, "call") == 0 ) {
242                 insertaddress(funckind(midcode[tmi].var1), -1, tmi);
243             }
244             else if ( strcmp(midcode[ tmi ].op, "geta") == 0 ){
245                 insertaddress(varkind(v1), -1, tmi);
246             }
247             else{
248                 insertaddress(INT, -1, tmi);
249             }
250         }
251         tmi++;
252     }
253 
254     while ( strcmp(midcode[ mi ].op, "end") != 0 ) {
255         paran = 0;
256         for ( int i = 0; i < strlen(midcode[ mi ].op); i++ ) {
257             if ( midcode[ mi ].op[ i ] == ' ' ) {
258                 midcode[ mi ].op[ i ] = '\0';
259                 break;
260             }
261         }
262         if ( strcmp(midcode[ mi ].op, "+") == 0 ) addasm();
263         if ( strcmp(midcode[ mi ].op, "-") == 0 ) subasm();
264         if ( strcmp(midcode[ mi ].op, "*") == 0 ) mulasm();
265         if ( strcmp(midcode[ mi ].op, "/") == 0 ) divasm();
266         if ( strcmp(midcode[ mi ].op, ">") == 0 ) greasm();
267         if ( strcmp(midcode[ mi ].op, ">=") == 0 ) geqasm();
268         if ( strcmp(midcode[ mi ].op, "<") == 0 ) lssasm();
269         if ( strcmp(midcode[ mi ].op, "<=") == 0 ) leqasm();
270         if ( strcmp(midcode[ mi ].op, "!=") == 0 ) neqasm();
271         if ( strcmp(midcode[ mi ].op, "==") == 0 ) eqlasm();
272         if ( strcmp(midcode[ mi ].op, "=") == 0 ) assasm();
273         if ( strcmp(midcode[ mi ].op, "[]=") == 0 ) aassasm();
274         if ( strcmp(midcode[ mi ].op, "geta") == 0 ) assaasm();
275         if ( strcmp(midcode[ mi ].op, "lab:") == 0 ) setlabasm();
276         if ( strcmp(midcode[ mi ].op, "scf") == 0 ) {
277             scfasm();
278         }
279         if ( strcmp(midcode[ mi ].op, "prt") == 0 ) {
280             prtasm();
281         }
282         if ( strcmp(midcode[ mi ].op, "jne") == 0 ) jneasm();
283         if ( strcmp(midcode[ mi ].op, "jmp") == 0 ) jmpasm();
284         if ( strcmp(midcode[ mi ].op, "fupa") == 0 ) fupaasm();
285         if ( strcmp(midcode[ mi ].op, "call") == 0 ) callasm();
286         if ( strcmp(midcode[ mi ].op, "ret") == 0 ) retasm();
287         if ( strcmp(midcode[ mi ].op, "para") == 0 ) paraasm();
288         if ( OPTFLAG ) {
289             int flag = 0;
290             while ( strcmp(midcode[ mi ].op, "int") == 0
291                 || strcmp(midcode[ mi ].op, "char") == 0 ) {
292                 flag = 1;
293                 intcharasm();
294                 mi++;
295             }
296             if (flag)    mi--;
297             //引用計數優化
298             cntopt();
299         } else {
300             if ( strcmp(midcode[ mi ].op, "int") == 0
301                         || strcmp(midcode[ mi ].op, "char") == 0 ) intcharasm();
302         }
303         
304         if ( strcmp(midcode[ mi ].op, "const") == 0 ) constdefasm();
305         if ( strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) intcharaasm();
306         mi++;
307     }
308     ap = constedge;
309     //恢復現場
310     rsT << "__FEND_LAB_" << funcnum << ":" << endl;//結束開始
311     rsT << "\t\tlw\t$ra\t-4($fp)" << endl;//恢復$ra
312     rsT << "\t\tadd\t$sp\t$fp\t$0" << endl;//退棧,恢復$sp
313     rsT << "\t\tlw\t$fp\t($fp)" << endl;//恢復上一個函數的fp
314     loadsreg();//恢復$s0-$s7
315     if ( ismain ) {
316         rsT << "\t\tli\t$v0\t10" << endl;
317         rsT << "\t\tsyscall" << endl;//終止程序
318     } else {
319         rsT << "\t\tjr\t$ra\t" << endl;//返回
320     }
321     mi = mi + 1;
322     return;
323 }
324 
325 //查找匯編變量地址
326 int varaddr(char *name) {
327     int t = ap - 1;
328     isglob = 0;
329     if ( name[ 0 ] == '+' || name[ 0 ] == '-' || name[ 0 ] >= '0'&&name[ 0 ] <= '9' )
330         return -1;
331     while ( t >= 0 ) {
332         if ( strcmp(addrtable[ t ].name, name) == 0 ) {
333             if ( t < constedge ) {
334                 isglob = 1;
335             }
336             return addrtable[ t ].address;
337         }
338         t--;
339     }
340     return -1;
341 }
342 
343 //void dataseg() {
344 //    rsT << "\t.data" << endl;
345 //    while ( strcmp(midcode[mi].op, "const") == 0 ) {
346 //        if ( strcmp(midcode[mi].var1, "int") == 0 || 
347 //            strcmp(midcode[mi].var1, "char") == 0 ) {
348 //            rsT << ".word" << endl;
349 //        }
350 //    }
351 //}
352 
353 //    jmp ,  ,  ,
354 void jmpasm() {
355     rsT << "\t\tj\t" << midcode[ mi ].var3 << endl;
356 }
357 
358 //    jne
359 void jneasm() {
360     rsT << "\t\tbne\t$t0\t1\t" << midcode[ mi ].var3 << endl;
361 }
362 
363 //    call, f ,   , a 
364 void callasm() {
365     rsT << "\t\tjal\t" << midcode[ mi ].var1 << endl;
366     rsT << "\t\tnop\n";
367     if ( midcode[ mi ].var3[ 0 ] != ' ' && midcode[ mi ].var3[ 0 ] != '\0' ) {
368         int addr2;
369         addr2 = varaddr(midcode[ mi ].var3);
370         if ( isglob )
371             rsT << "\t\tsw\t$v0\t" << addr2 << "($t9)" << endl;
372         else
373             rsT << "\t\tsw\t$v0\t" << addr2 << "($fp)" << endl;
374     }
375 }
376 
377 //    lab,  ,  ,
378 void setlabasm() {
379     rsT << midcode[ mi ].var3 << ":\n";
380 }
381 
382 //    add, a, b, c
383 void addasm() {
384     int addr1, addr2, addr3;
385     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
386         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
387     } else {
388         addr1 = varaddr(midcode[ mi ].var1);
389         if ( isglob )
390             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
391         else
392             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
393     }
394     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
395         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
396     } else {
397         addr2 = varaddr(midcode[ mi ].var2);
398         if ( isglob )
399             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
400         else
401             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
402     }
403     addr3 = varaddr(midcode[ mi ].var3);
404     rsT << "\t\tadd\t$t0\t$t0\t$t1" << endl;
405     if ( isglob )
406         rsT << "\t\tsw\t$t0\t" << addr1 << "($t9)" << endl;
407     else
408         rsT << "\t\tsw\t$t0\t" << addr3 << "($fp)" << endl;
409 }
410 
411 //    sub, a, b, c
412 void subasm() {
413     int addr1, addr2, addr3;
414     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
415         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
416     } else {
417         addr1 = varaddr(midcode[ mi ].var1);
418         if ( isglob ) 
419             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
420         else
421             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
422     }
423     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
424         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
425     } else {
426         addr2 = varaddr(midcode[ mi ].var2);
427         if ( isglob )
428             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
429         else
430             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
431     }
432     addr3 = varaddr(midcode[ mi ].var3);
433     rsT << "\t\tsub\t$t0\t$t0\t$t1" << endl;
434     if ( isglob ) 
435         rsT << "\t\tsw\t$t0\t" << addr3 << "($t9)" << endl;
436     else
437         rsT << "\t\tsw\t$t0\t" << addr3 << "($fp)" << endl;
438 }
439 
440 //    mul, a, b, c
441 void mulasm() {
442     int addr1, addr2, addr3;
443     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
444         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
445     } else {
446         addr1 = varaddr(midcode[ mi ].var1);
447         if ( isglob )
448             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
449         else
450             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
451     }
452     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
453         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
454     } else {
455         addr2 = varaddr(midcode[ mi ].var2);
456         if ( isglob )
457             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
458         else
459             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
460     }
461     addr3 = varaddr(midcode[ mi ].var3);
462     rsT << "\t\tmul\t$t0\t$t0\t$t1" << endl;
463     if ( isglob )
464         rsT << "\t\tsw\t$t0\t" << addr3 << "($t9)" << endl;
465     else
466         rsT << "\t\tsw\t$t0\t" << addr3 << "($fp)" << endl;
467 }
468 
469 //    div, a, b, c
470 void divasm() {
471     int addr1, addr2, addr3;
472     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
473         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
474     } else {
475         addr1 = varaddr(midcode[ mi ].var1);
476         if ( isglob )
477             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
478         else
479             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
480     }
481     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
482         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
483     } else {
484         addr2 = varaddr(midcode[ mi ].var2);
485         if ( isglob )
486             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
487         else
488             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
489     }
490     addr3 = varaddr(midcode[ mi ].var3);
491     rsT << "\t\tdiv\t$t0\t$t0\t$t1" << endl;
492     if ( isglob )
493         rsT << "\t\tsw\t$t0\t" << addr3 << "($t9)" << endl;
494     else
495         rsT << "\t\tsw\t$t0\t" << addr3 << "($fp)" << endl;
496 }
497 
498 //    > , a, b, c
499 void greasm() {
500     int addr1, addr2;
501     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
502         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
503     } else {
504         addr1 = varaddr(midcode[ mi ].var1);
505         if ( isglob ) 
506             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
507         else
508             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
509     }
510     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
511         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
512     } else {
513         addr2 = varaddr(midcode[ mi ].var2);
514         if ( isglob )
515             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
516         else
517             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
518     }
519     rsT << "\t\tslt\t$t0\t$t1\t$t0" << endl;
520 }
521 
522 //    >=
523 void geqasm() {
524     int addr1, addr2;
525     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
526         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
527     } else {
528         addr1 = varaddr(midcode[ mi ].var1);
529         if ( isglob )
530             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
531         else
532             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
533     }
534     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
535         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
536     } else {
537         addr2 = varaddr(midcode[ mi ].var2);
538         if ( isglob )
539             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
540         else
541             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
542     }
543     rsT << "\t\tslt\t$t0\t$t0\t$t1" << endl;
544     rsT << "\t\tli\t$t1\t1" << endl;
545     rsT << "\t\tsub\t$t0\t$t1\t$t0" << endl;
546 }
547 
548 //    <
549 void lssasm() {
550     int addr1, addr2;
551     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
552         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
553     } else {
554         addr1 = varaddr(midcode[ mi ].var1);
555         if ( isglob )
556             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
557         else
558             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
559     }
560     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
561         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
562     } else {
563         addr2 = varaddr(midcode[ mi ].var2);
564         if ( isglob )
565             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
566         else
567             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
568     }
569     rsT << "\t\tslt\t$t0\t$t0\t$t1" << endl;
570 }
571 
572 //    <=
573 void leqasm() {
574     int addr1, addr2;
575     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
576         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
577     } else {
578         addr1 = varaddr(midcode[ mi ].var1);
579         if ( isglob )
580             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
581         else
582             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
583     }
584     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
585         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
586     } else {
587         addr2 = varaddr(midcode[ mi ].var2);
588         if ( isglob )
589             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
590         else
591             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
592     }
593     rsT << "\t\tslt\t$t0\t$t1\t$t0" << endl;
594     rsT << "\t\tli\t$t1\t1" << endl;
595     rsT << "\t\tsub\t$t0\t$t1\t$t0" << endl;
596 }
597 
598 //    ==
599 void eqlasm() {
600     int addr1, addr2;
601     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
602         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
603     } else {
604         addr1 = varaddr(midcode[ mi ].var1);
605         if ( isglob )
606             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
607         else
608             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
609     }
610     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
611         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
612     } else {
613         addr2 = varaddr(midcode[ mi ].var2);
614         if ( isglob )
615             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
616         else
617             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
618     }
619 
620     int t1 = tlabelnum++;
621     int t2 = tlabelnum++;
622     rsT << "\t\tbne\t$t0\t$t1\t__tLABEL" << t1 << endl;
623     rsT << "\t\tli\t$t0\t1" << endl;
624     rsT << "\t\tj\t__tLABEL" << t2 << endl;
625     rsT << "__tLABEL" << t1 << ":" << endl;
626     //cout << "__tLABEL" << t1 << ":" << endl;
627     rsT << "\t\tli\t$t0\t0" << endl;
628     rsT << "__tLABEL" << t2 << ":" << endl;
629 }
630 
631 //    !=
632 void neqasm() {
633     int addr1, addr2;
634     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
635         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
636     } else {
637         addr1 = varaddr(midcode[ mi ].var1);
638         if ( isglob )
639             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
640         else
641             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
642     }
643     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
644         rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl;
645     } else {
646         addr2 = varaddr(midcode[ mi ].var2);
647         if ( isglob )
648             rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl;
649         else
650             rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl;
651     }
652     int t1 = tlabelnum++;
653     int t2 = tlabelnum++;
654     rsT << "\t\tbeq\t$t0\t$t1\t__tLABEL" << t1 << endl;
655     rsT << "\t\tli\t$t0\t1" << endl;
656     rsT << "\t\tj\t__tLABEL" << t2 << endl;
657     rsT << "__tLABEL" << t1 << ":" << endl;
658     //cout << "__tLABEL" << t1 << ":" << endl;
659     rsT << "\t\tli\t$t0\t0" << endl;
660     rsT << "__tLABEL" << t2 << ":" << endl;
661 }
662 
663 //    =
664 void assasm() {
665     int addr1, addr2;
666     if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) {
667         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl;
668     } else {
669         addr1 = varaddr(midcode[ mi ].var1);
670         if ( isglob )
671             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
672         else
673             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
674     }
675     addr2 = varaddr(midcode[ mi ].var3);
676     if (isglob )
677         rsT << "\t\tsw\t$t0\t" << addr2 << "($t9)" << endl;
678     else
679         rsT << "\t\tsw\t$t0\t" << addr2 << "($fp)" << endl;
680 }
681 
682 //    []= , a , i , t
683 void aassasm() {
684     int addr1, addr2, addrt;
685     addr1 = varaddr(midcode[ mi ].var1);
686     int tisglob = isglob;
687     if ( isdigit(midcode[ mi ].var2[0]) ) {
688         addr1 += (atoi(midcode[ mi ].var2) * 4);
689         if ( isdigit(midcode[ mi ].var3[ 0 ]) || midcode[ mi ].var3[ 0 ] == '-' || midcode[ mi ].var3[ 0 ] == '+' ) {
690             rsT << "\t\tli\t$t0\t" << midcode[ mi ].var3 << endl;
691         } else {
692             addr2 = varaddr(midcode[ mi ].var3);
693             if ( isglob ) {
694                 rsT << "\t\tlw\t$t0\t" << addr2 << "($t9)" << endl;
695             }else
696                 rsT << "\t\tlw\t$t0\t" << addr2 << "($fp)" << endl;
697         }
698         if (isglob)
699             rsT << "\t\tsw\t$t0\t" << addr1 << "($t9)" << endl;
700         else
701             rsT << "\t\tsw\t$t0\t" << addr1 << "($fp)" << endl;
702     } else {
703         //求數組元素a[i]地址
704         addrt = varaddr(midcode[ mi ].var2);//addrt = &i
705         if (isglob)
706             rsT << "\t\tlw\t$t1\t" << addrt << "($t9)" << endl;    //t1 = i
707         else
708             rsT << "\t\tlw\t$t1\t" << addrt << "($fp)" << endl;    //t1 = i
709         rsT << "\t\tmul\t$t1\t$t1\t4\n";    //t1 = t1 * 4 (t1 = offset)
710         rsT << "\t\taddi\t$t1\t$t1\t" << addr1 << endl;    //t1 = &a[i] - $fp
711         rsT << "\t\tadd\t$t1\t$t1\t$fp" << endl;//t1 = &a[i]
712         if ( isdigit(midcode[ mi ].var3[ 0 ]) || midcode[ mi ].var3[ 0 ] == '-' || midcode[ mi ].var3[ 0 ] == '+' ) {
713             rsT << "\t\tli\t$t0\t" << midcode[ mi ].var3 << endl;
714         } else {
715             addr2 = varaddr(midcode[ mi ].var3);
716             if ( isglob ) {
717                 rsT << "\t\tlw\t$t0\t" << addr2 << "($t9)" << endl;
718             } else {
719                 rsT << "\t\tlw\t$t0\t" << addr2 << "($fp)" << endl;
720             }
721             
722         }
723         rsT << "\t\tsw\t$t0\t0($t1)" << endl;
724     }
725 }
726 
727 //geta, a, n, b
728 void assaasm() {
729     int addr1 = varaddr(midcode[ mi ].var1);
730     int tisglob = isglob;
731     int addr2;
732     if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
733         addr1 += ( atoi(midcode[ mi ].var2) * 4 );    //addr1 = &a[n]
734         addr2 = varaddr(midcode[ mi ].var3);        //addr2 = &b
735         if ( tisglob ) {
736             rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl;
737         }else
738             rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl;
739         if ( isglob ) {
740             rsT << "\t\tsw\t$t0\t" << addr2 << "($t9)" << endl;
741         }else
742             rsT << "\t\tsw\t$t0\t" << addr2 << "($fp)" << endl;
743     } else {
744         //求數組元素a[i]地址
745         int addrt = varaddr(midcode[ mi ].var2);//addrt = &i
746         if ( isglob ) {
747             rsT << "\t\tlw\t$t1\t" << addrt << "($t9)" << endl;    //t1 = i
748         }else
749             rsT << "\t\tlw\t$t1\t" << addrt << "($fp)" << endl;    //t1 = i
750         rsT << "\t\tmul\t$t1\t$t1\t4\n";    //t1 = t1 * 4 (t1 = offset)
751         rsT << "\t\taddi\t$t1\t$t1\t" << addr1 << endl;    //t1 = &a[i] - $fp
752         rsT << "\t\tadd\t$t1\t$t1\t$fp" << endl;
753         rsT << "\t\tlw\t$t1\t0($t1)\n";    //t1 = a[i]
754         addr2 = varaddr(midcode[ mi ].var3);    //addr2 = &b
755         if (isglob)
756             rsT << "\t\tsw\t$t1\t" << addr2 << "($t9)" << endl;
757         else
758             rsT << "\t\tsw\t$t1\t" << addr2 << "($fp)" << endl;
759     }
760 }
761 
762 //scf ,   ,   , a
763 void scfasm() {
764     int addr = varaddr(midcode[ mi ].var3);
765     int ti = findvartable(midcode[ mi ].var3);
766     int kind = addrtable[ ti ].kind;
767     if ( kind == INT ) {
768         rsT << "\t\tli\t$v0\t5" << endl;
769         rsT << "\t\tsyscall" << endl;
770         //rsT << "\t\tsubi\t$v0\t$v0\t" << ( int )'0' << endl;
771         if (isglob)
772             rsT << "\t\tsw\t$v0\t" << addr << "($t9)" << endl;
773         else
774             rsT << "\t\tsw\t$v0\t" << addr << "($fp)" << endl;
775     } else {
776         rsT << "\t\tli\t$v0\t12" << endl;
777         rsT << "\t\tsyscall" << endl;
778         if ( isglob )
779             rsT << "\t\tsw\t$v0\t" << addr << "($t9)" << endl;
780         else
781             rsT << "\t\tsw\t$v0\t" << addr << "($fp)" << endl;
782     }
783 }
784 
785 //prt, a, b, symb
786 void prtasm() {
787     int addr;
788     if ( midcode[ mi ].var1[ 0 ] != '\0' ) {
789         int len = strlen(midcode[ mi ].var1);
790         for ( int i = 0; i < len; i++ ) {
791             rsT << "\t\tli\t$v0\t11" << endl;
792             rsT << "\t\tli\t$a0\t" << int(midcode[ mi ].var1[i]) << endl;
793             rsT << "\t\tsyscall" << endl;
794         }
795     }
796     if ( midcode[ mi ].var2[ 0 ] != ' ' && midcode[ mi ].var2[ 0 ] != '\0' ) {
797         if ( isdigit(midcode[mi].var2[0]) && strcmp(midcode[mi].var3, "char") == 0 ) {
798             rsT << "\t\tli\t$v0\t11" << endl;
799             rsT << "\t\tli\t$a0\t" << midcode[ mi ].var2 << endl;
800             rsT << "\t\tsyscall" << endl;
801             return;
802         } else if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
803             rsT << "\t\tli\t$v0\t1" << endl;
804             rsT << "\t\tli\t$a0\t" << midcode[ mi ].var2 << endl;
805             rsT << "\t\tsyscall" << endl;
806             return;
807         }
808         addr = varaddr(midcode[ mi ].var2);
809         int ti = findvartable(midcode[ mi ].var2);
810         int kind = addrtable[ ti ].kind;
811         if ( kind == INT || kind == WINT) {
812             rsT << "\t\tli\t$v0\t1" << endl;
813             if ( isglob ) {
814                 rsT << "\t\tlw\t$a0\t" << addr << "($t9)" << endl;
815             }else
816             rsT << "\t\tlw\t$a0\t" << addr << "($fp)" << endl;
817             rsT << "\t\tsyscall" << endl;
818         } else {
819             rsT << "\t\tli\t$v0\t11" << endl;
820             if ( isglob )    rsT << "\t\tlw\t$a0\t" << addr << "($t9)" << endl;
821             else    rsT << "\t\tlw\t$a0\t" << addr << "($fp)" << endl;
822             rsT << "\t\tsyscall" << endl;
823         }
824     }
825 }
826 
827 //fupa,   ,   , a     ==> a is a function parameter
828 void fupaasm() {
829     if ( isdigit(midcode[mi].var3[0]) ) {
830         rsT << "\t\tli\t$t0\t" << midcode[ mi ].var3 << endl;
831     } else {
832         rsT << "\t\tlw\t$t0\t" << varaddr(midcode[ mi ].var3); //li    $t0 item
833         if(isglob){
834             rsT << "($t9)" << endl;
835         }else{
836             rsT << "($fp)" << endl;
837         }
838     }
839     rsT << "\t\tsw\t$t0\t($sp)" << endl;      //sw    $t0 $sp
840     sp -= 4;
841     rsT << "\t\tsubi\t$sp\t$sp\t4" << endl; //subi  $sp $sp 4  
842 }
843 
844 //ret ,   ,   , (a)   ==> return a / return
845 void retasm() {
846     if ( midcode[ mi ].var3[ 0 ] != ' ' && midcode[ mi ].var3[ 0 ] != '\0' ) {
847         if ( isdigit(midcode[ mi ].var3[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) {
848             rsT << "\t\tli\t$v0\t" << midcode[ mi ].var3 << endl;
849         } else {
850             int addr2 = varaddr(midcode[ mi ].var3);
851             if ( isglob )
852                 rsT << "\t\tlw\t$v0\t" << addr2 << "($t9)" << endl;
853             else
854                 rsT << "\t\tlw\t$v0\t" << addr2 << "($fp)" << endl;
855         }
856     }
857     rsT << "\t\tj\t__FEND_LAB_" << funcnum << endl;//跳至結束
858 }
859 
860 //para, int, , a == > f(int a, ...)
861 void paraasm() {
862     paranum = 0;
863     for ( int i = mi; i < midcodeiter; i++ ) {
864         if ( strcmp(midcode[ i ].op, "para") == 0 )
865             paranum++;
866         else
867             break;
868     }
869     for ( int i = 0; i < paranum; i++ ) {
870         int kind = (strcmp(midcode[ mi ].var1, "int") == 0) ? INT : CHAR;
871         insertaddress(kind, 4 * ( paranum - i ));
872         mi++;
873     }
874     mi--;
875 }
876 
877 void intcharasm() {
878     if ( isdigit(midcode[ mi ].var2[0]) ) {
879         pushstack(midcode[ mi ].var2);
880     } else {
881         pushstack("0");
882     }
883     if ( strcmp(midcode[ mi ].op, "int") == 0 ) {
884         insertaddress(INT);
885     } else {
886         insertaddress(CHAR);
887     }
888 }
889 
890 void constdefasm() {
891     //常量定義
892     while ( strcmp(midcode[ mi ].op, "const") == 0 ) {
893         pushstack(midcode[ mi ].var2);
894         if ( strcmp(midcode[ mi ].var1, "int") == 0 ) {
895             insertaddress(INT);
896         } else {
897             insertaddress(CHAR);
898         }
899         mi++;
900     }
901     mi--;
902 }
903 
904 void intcharaasm() {
905     //數組定義
906     while ( strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) {
907         pushstack("0", atoi(midcode[ mi ].var2));
908         if ( strcmp(midcode[ mi ].op, "inta") == 0 ) {
909             insertaddress(INT);
910         } else {
911             insertaddress(CHAR);
912         }
913         mi++;
914     }
915     mi--;
916     
917 }
918 
919 void cntopt() {
920     //引用計數
921     int tmi;
922     if ( OPTFLAG ) {
923         tmi = mi;
924         while ( strcmp(midcode[ tmi ].op, "end") != 0 ) {
925             if ( !strcmp(midcode[ tmi ].op, "=") || !strcmp(midcode[ tmi ].op, "+") || !strcmp(midcode[ tmi ].op, "-") || !strcmp(midcode[ tmi ].op, "*") || !strcmp(midcode[ tmi ].op, "/") ) {
926                 cnt(midcode[ tmi ].var1);
927                 cnt(midcode[ tmi ].var2);
928                 cnt(midcode[ tmi ].var3);
929             }
930             tmi++;
931         }
932         sort(cnttable, cnttable + cntindex, cmpcnt);
933         for ( int i = 0; i < 8; i++ ) {
934             varreg[ cnttable[ i ].symbnum ] = i;
935             int addr = addrtable[ cnttable[ i ].symbnum ].address;
936             rsT << "\t\tlw\t$s" << i << "\t" << addr << "($fp)" << endl;
937         }
938     }
939 }
940 
941 void savesreg() {
942     if ( OPTFLAG ) {
943         for ( int i = 0; i < 8; i++ ) {
944             rsT << "\t\tsw\t$t" << i << "\t" << 4 * i << "($t8)" << endl;
945         }
946     }
947 }
948 
949 void loadsreg() {
950     if ( OPTFLAG ) {
951         for ( int i = 0; i < 8; i++ ) {
952             rsT << "\t\tlw\t$t" << i << "\t" << 4 * i << "($t8)" << endl;
953         }
954     }
955 }
956 
957 void cnt(char* name) {
958     int t = ap - 1;
959     isglob = 0;
960     if ( name[ 0 ] == '+' || name[ 0 ] == '-' || ( name[ 0 ] >= '0'&& name[ 0 ] <= '9' ) || name[ 0 ] == ' ' || name[ 0 ] == '\t' || name[ 0 ] == '\0' )
961         return ;
962     while ( t >= constedge) {
963         if ( strcmp(addrtable[ t ].name, name) == 0 ) {
964             addrtable[ t ].cnt++;
965             for ( int q = 0; q <= cntindex; q++ ) {
966                 if ( q == cntindex ) {
967                     cnttable[ cntindex ].cnt = 1;
968                     cnttable[ cntindex ].symbnum = t;
969                     cntindex++;
970                     break;
971                 }
972                 if ( cnttable[q].symbnum == t ) {
973                     cnttable[ q ].cnt++;
974                     break;
975                 }
976             }
977         }
978         t--;
979     }
980 }

 

 

 

參考資料

  1. 《高級編譯器設計與實現》 (美)Steven S. Muchnick著  趙克佳,沈志宇譯  機械工與出版社
  2. 《編譯原理及編譯程序構造》 金茂忠,高仲儀編  北京航空航天大學出版社
  3. 《計算機組成與設計 –硬件/軟件接口》(美)Pattersom,Hennessy著 鄭緯民等譯  機械工業出版社


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM