指令生成 語法制導的指令生成 介面

2021-08-24 18:29:03 字數 3215 閱讀 6306

繼續向語法樹節點結構中追加成員。

#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;

其它型別與這個例子非常類似,就不一一贅述了。下面談談各型別指令生成是要幹什麼。

// 進入基本塊和退出基本塊

// 函式將連線塊內所有語句的指令, 此外還將與符號表進行互動

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*);

有一點很有趣的是,無論是x86指令集,還是jerry指令集,都不包含與/或/非(邏輯運算,不是位運算)這些運算,也就是說我們必須完成條件短路,所以雖然 binaryoperationnode 就只有乙個指令生成入口,但是這個入口會根據運算子的不同而進入三個不同的模組中

// 運算子是 = 那麼進行賦值指令生成

static struct list* insassignment(void*);

// 運算子是 && 或 || 進行邏輯短路

static struct list* inslogicshortcut(void*);

// 此外生成一般運算指令

static struct list* insnormalbinaryop(void*);

為了方便判斷,在 const.h 中 accepttype 旁邊新增這些巨集

#define isarithoperator(x) (plus <= (x) && (x) < assign)

#define islogicoperator(x) (and <= (x) && (x) <= not)

而對於取位址函式,就目前的情況來看只有兩種——變數位址,和無法取到位址。這些介面如下

// 取變數的位址, 指令執行時執行結束將會在棧頂引入該變數的位址

struct list* addrofvar(void*);

// 其它

struct list* cantretrieveaddr(void*);

記得將它們在 newvariablenode 等函式中繫結到對應的 addressof 域中。

讀《編譯原理》第五章,語法制導的翻譯

194頁 共631 頁 使用上下文無關文法來引導對語言的翻譯。用於型別檢查和中間 生成。5.1 語法制導定義 syntax directed definition sdd 是乙個上下文無關文法和屬性及規則的結合。5.1.1 繼承屬性和綜合屬性 綜合屬性 在分析樹結點 n 上的非終結符號 a 的結合屬...

喬姆斯基生成語法 喬姆斯基的轉換生成語法理論

無論是分析哲學還是歐洲大陸哲學,都重視研究語言,這是當代西方哲學的乙個重要特徵,語言不能脫離世界,語言只有表現世界才有它正真的存在。當代美國語言大師喬姆斯基首創了轉換生成語法理論,正是這種轉換生成語法在語言中挑起了一場革命。它標誌著西方語言學的研究,尤其是美國的語言學界研究進入了乙個嶄新的時代,即喬...

Vue的基本語法和常用指令

vue是一套用於構建使用者介面的漸進式框架。與其它大型框架不同的是,vue 被設計為可以自底向上逐層應用。vue 的核心庫只關注檢視層,不僅易於上手,還便於與第三方庫或既有專案整合。另一方面,當與現代化的工具鏈以及各種支援類庫結合使用時,vue 也完全能夠為複雜的單頁應用提供驅動。mvvm 雙向資料...