繼續向語法樹節點結構中追加成員。
#define memberabstractsyntaxnode \這篇文章將談及我們需要實現的介面和它們的功能。unsigned int line; \
struct abstractsyntaxnode* nextnode; \
struct list* (*createinstruction)(void*); \
void (*delnode)(void*); \
void (*printree)(void*, int); /***********/
// abstractsyntaxnode 增加成員 createinstruction
// 產生該語法樹節點對應的指令 list
#define memberabstractvaluenode \
memberabstractsyntaxnode \
int (*staticint)(void*, int*); \
int (*staticreal)(void*, double*); \
accepttype (*typeof)(void*); \
struct list* (*addressof)(void*);
// abstractvaluenode 增加成員 addressof
// 產生這個值節點對應的載入位址的指令 list
// 對於非法的左值, 如表示式, 這個函式返回 null
對於每類節點的指令生成模組,函式命名方式為
ins + 類名
如struct list*insintegernode(void*);
就是為 integernode 生成指令的函式,它將在 newintegernode 函式(希望大家還記得這些函式)中被賦值:
node->createinstruction =insintegernode;
其它型別與這個例子非常類似,就不一一贅述了。下面談談各型別指令生成是要幹什麼。
// 進入基本塊和退出基本塊有一點很有趣的是,無論是x86指令集,還是jerry指令集,都不包含與/或/非(邏輯運算,不是位運算)這些運算,也就是說我們必須完成條件短路,所以雖然 binaryoperationnode 就只有乙個指令生成入口,但是這個入口會根據運算子的不同而進入三個不同的模組中// 函式將連線塊內所有語句的指令, 此外還將與符號表進行互動
struct list* insbasicblocknode(void*);
// 一元 / 二元運算節點
// 載入它們的子節點(運算數)的指令, 並進行對應的運算(例外參見後文)
// 執行它們生成的指令, 結果是讓執行棧棧頂存放乙個值, 而不是乙個位址
struct list* insbinaryoperationnode(void*);
struct list* insunaryoperationnode(void*);
// 常數節點生成的指令將載入乙個常數到執行棧棧頂
struct list* insintegernode(void*);
struct list* insrealnode(void*);
// 分支控制生成的指令將根據執行棧棧頂的整數值, 調節執行方式
struct list* insifelsenode(void*);
// 迴圈控制除了生成迴圈控制相關的指令
// 還會維護乙個迴圈棧
// 而 breaknode 將根據迴圈棧來確定該跳出哪個迴圈
// insbreaknode 包含語義容錯
struct list* inswhilenode(void*);
struct list* insbreaknode(void*);
// io 是乙個統稱
// 實際上, read 與 write 生成的指令很不一樣
// read 執行時, 要求執行棧棧頂是乙個位址
// 然後根據型別讀入資料並送往該位址
// 而 write 要求棧頂是值, 並寫出該值
// 指令執行之後, 將彈走棧頂
struct list* insionode(void*);
// 乙個算術節點會幹什麼?
// 它並不是僅僅呼叫子節點的指令生成就完了
// 注意到, 當乙個運算結束之後, 執行棧棧頂總會有乙個值
// 因此為了維護棧指標, 算術節點會根據子節點的資料型別調整棧指標
struct list* insarithmaticnode(void*);
// 宣告節點主要工作是與符號表打交道
// 以及對變數進行初始化
// 包含語義容錯
struct list* insdeclarationnode(void*);
// 將變數的執行時值取到棧頂
// 包含語義容錯
struct list* insvariablenode(void*);
// 運算子是 = 那麼進行賦值指令生成為了方便判斷,在 const.h 中 accepttype 旁邊新增這些巨集static struct list* insassignment(void*);
// 運算子是 && 或 || 進行邏輯短路
static struct list* inslogicshortcut(void*);
// 此外生成一般運算指令
static struct list* insnormalbinaryop(void*);
#define isarithoperator(x) (plus <= (x) && (x) < assign)而對於取位址函式,就目前的情況來看只有兩種——變數位址,和無法取到位址。這些介面如下#define islogicoperator(x) (and <= (x) && (x) <= not)
// 取變數的位址, 指令執行時執行結束將會在棧頂引入該變數的位址記得將它們在 newvariablenode 等函式中繫結到對應的 addressof 域中。struct list* addrofvar(void*);
// 其它
struct list* cantretrieveaddr(void*);
讀《編譯原理》第五章,語法制導的翻譯
194頁 共631 頁 使用上下文無關文法來引導對語言的翻譯。用於型別檢查和中間 生成。5.1 語法制導定義 syntax directed definition sdd 是乙個上下文無關文法和屬性及規則的結合。5.1.1 繼承屬性和綜合屬性 綜合屬性 在分析樹結點 n 上的非終結符號 a 的結合屬...
喬姆斯基生成語法 喬姆斯基的轉換生成語法理論
無論是分析哲學還是歐洲大陸哲學,都重視研究語言,這是當代西方哲學的乙個重要特徵,語言不能脫離世界,語言只有表現世界才有它正真的存在。當代美國語言大師喬姆斯基首創了轉換生成語法理論,正是這種轉換生成語法在語言中挑起了一場革命。它標誌著西方語言學的研究,尤其是美國的語言學界研究進入了乙個嶄新的時代,即喬...
Vue的基本語法和常用指令
vue是一套用於構建使用者介面的漸進式框架。與其它大型框架不同的是,vue 被設計為可以自底向上逐層應用。vue 的核心庫只關注檢視層,不僅易於上手,還便於與第三方庫或既有專案整合。另一方面,當與現代化的工具鏈以及各種支援類庫結合使用時,vue 也完全能夠為複雜的單頁應用提供驅動。mvvm 雙向資料...