本文禁止任何爬蟲爬取!來源: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。因此,它的四個接受狀態分別代表遇到了四種不同的單詞。
設計好之后因為它包含很多的不確定分支和ε,所以需要做一次NFA->DFA的確定化。按照課本上的方法,用ε-閉包的方法就求得了一個DFA,用上圖的例子,我們可以得到如下DFA,可以證明這個DFA和上圖中的NFA是等價的。
之后,可以采用直接狀態機的編碼方式來編寫,也可以采用逐步判斷分支的方式來編寫,我采用的是后者,在程序中可以清晰的看見。
在編寫的過程中也沒有遇到太多困難,我覺得其中值得一提的就是預讀行緩沖這個部分了。記得在做這個實驗之前就已經閱讀了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。為此我自己寫了一個可證正確性的算法:
- 通過掃描基本塊,由上向下找出有相同的op(對應DAG圖中的父節點),var1(對應DAG圖中的左子節點),var2(對應DAG圖中的右子節點)且var3為臨時變量的四元式對(A, B);
- 從B向下繼續掃描四元式,尋找所有與B具有相同var3的四元式C1,C2,…;
- 將Ci的var3置為A.var3;
- 刪除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.類/方法/函數功能
函數功能見上圖。
所有函數:
函數名 |
作用和功能 |
詞法分析: |
|
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.調用依賴關系
如圖所示。
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.運行棧結構:
如下圖所示:
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的程序。此即為編譯器的主程序。
2.運行編譯器程序。
3.將需要編譯的文件拖入程序框內,如果路徑存在空格,需要加上引號。之后按回車。如圖所示:
4.如果編譯成功,會出現如下提示,並跳轉到第六步:
5.如果編譯失敗,會出現如下提示:
6.編譯成功后,將會生成如下幾個文件:
7.可以通過optMidCode.txt和midcode.txt進行比對來看優化效果
8.接下來打開MARS模擬器,導入asmrst.asm,如圖:
9.編譯執行即可,如圖:
10.需要注意的是,任何輸入都必須用換行符隔開,這是Mars定義的模擬特性。
下圖就是一個正確的輸入:
而下圖用空格隔開將會導致程序出錯:
最后貼一下工程代碼,需要注意的是這個代碼是歷史版本存在一些漏洞:
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 }
參考資料
- 《高級編譯器設計與實現》 (美)Steven S. Muchnick著 趙克佳,沈志宇譯 機械工與出版社
- 《編譯原理及編譯程序構造》 金茂忠,高仲儀編 北京航空航天大學出版社
- 《計算機組成與設計 –硬件/軟件接口》(美)Pattersom,Hennessy著 鄭緯民等譯 機械工業出版社