成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一門語言的作用域和函數調用是如何實現的

開發 前端
Visitor? 模式正好和 Listener 相反,這是由我們自行控制需要訪問哪個 AST 節點,同時需要在每次訪問之后返回數據,這點非常適合來做程序運行期。

前言

上次利用 Antlr 重構一版??用 Antlr 重構腳本解釋器??之后便著手新增其他功能,也就是現在看到的支持了作用域以及函數調用。

int b= 10;
int foo(int age){
for(int i=0;i<10;i++){
age++;
}
return b+age;
}
int add(int a,int b) {
int e = foo(10);
e = e+10;
return a+b+3+e;
}
add(2,20);
// Output:65

整個語法規則大部分參考了 Java,現階段支持了:

  • 函數聲明與調用。
  • 函數調用的入棧和出棧,保證了函數局部變量在函數退出時銷毀。
  • 作用域支持,內部作用域可以訪問外部作用域的變量。
  • 基本的表達式語句,如i++, !=,==

這次實現的重點與難點則是作用域與函數調用,實現之后也算是滿足了我的好奇心,不過在講作用域與函數調用之前先來看看一個簡單的變量聲明與訪問語句是如何實現的,這樣后續的理解會更加容易。

變量聲明

int a=10;
a;

由于還沒有實現內置函數,比如控制臺輸出函數 print(),所以這里就直接訪問變量也能拿到數據

運行后結果如下:

圖片

首先看看變量聲明語句的語法:

variableDeclarators
: typeType variableDeclarator (',' variableDeclarator)*
;

variableDeclarator
: variableDeclaratorId ('=' variableInitializer)?
;
typeList
: typeType (',' typeType)*
;
typeType
: (functionType | primitiveType) ('[' ']')*
;
primitiveType
: INT
| STRING
| FLOAT
| BOOLEAN
;

只看語法不太直觀,直接看下生成的 AST 樹就明白了:

圖片

編譯期 左邊這棵 ?BlockVardeclar? 樹對應的就是  int a=10;?,右邊的 blockStm? 對應的就是變量訪問 a。

整個程序的運行過程分為編譯期和運行期,對應的流程:

遍歷 AST 樹,做語義分析,生成對應的符號表、類型表、引用消解、還有一些語法校驗,比如變量名、函數名是否重復、是否能訪問私有變量等。

運行期:從編譯期中生成的符號表、類型表中獲取數據,執行具體的代碼邏輯。

訪問 AST

對于剛才提到的編譯期和運行期其實分別對應兩種訪問 AST? 的方式,這也是 Antlr 所提供兩種方式。

Listener 模式

第一種是 Listener 模式,就這名字也能猜到是如何運行的;我們需要實現 Antlr 所提供的接口,這些接口分別對應 AST 樹中的不同節點。

接著 Antlr 會自動遍歷這棵樹,當訪問和退出某個節點時變會回調我們自定義的方法,這些接口都是沒有返回值的,所以我們需要將遍歷過程中的數據自行存放起來。

這點非常適合上文提到的編譯期,遍歷過程中產生的數據自然就會存放到符號表、類型表這些容器中。

圖片

以這段代碼為例,我們實現了程序根節點、for循環節點的進入和退出 Listener,當 Antlr 運行到這些節點時便會執行其中的邏輯。

https://github.com/crossoverJie/gscript/blob/main/resolver/type_scope_resolver.go

Visitor 模式

Visitor? 模式正好和 Listener 相反,這是由我們自行控制需要訪問哪個 AST 節點,同時需要在每次訪問之后返回數據,這點非常適合來做程序運行期。

配合在編譯期中存放的數據,便可以實現各種特性了。

圖片

以上圖為例,在訪問 Prog 節點時便可以從編譯期中拿到當前節點所對應的作用域 scope?,同時我們可以自行控制訪問下一個節點 VisitBlockStms,訪問其他節點當然也是可以的,不過通常我們還是按照語法中定義的結構進行訪問。

作用域

即便是同一個語法生成的 AST 是相同的,但我們在遍歷 AST 時實現不同也就會導致不同的語義,這就是各個語言語義分析的不同之處。

比如 Java 不允許在子作用域中聲明和父作用域中相同的變量,但 JavaScript 卻是可以的。

有了上面的基礎下面我們來看看作用域是如何實現的。

int a=10;
a;

還是以這段代碼為例:

圖片

這里我簡單畫了下流程:

在編譯期間會會為當前節點寫入一個 scope?,以及在 scope? 中寫入變量 “a”。

這里的寫入 scope 和寫入變量是分為兩次 Listener 進行的,具體代碼實現在下面查看源碼。

第一次:https://github.com/crossoverJie/gscript/blob/main/resolver/type_scope_resolver.go#L21

第二次:https://github.com/crossoverJie/gscript/blob/main/resolver/type_resolver.go#L59

接著是運行期,從編譯期中生成的數據拿到 scope? 以及其中的變量,獲取變量時有一個細節:當前 scope 中如果獲取不到需要嘗試從父級 scope 中獲取,比如如下情況:

int b= 10;
int foo(){
return b;
}

這里的 b 在當前函數作用域中是獲取不到的,只能在父級 scope 中獲取。

父級 scope 的關系是在創建 scope 的時候維護進去的,默認當前 scope 就是寫入時 scope 的父級。

關鍵代碼試下如下圖:

圖片

第四步獲取變量的值也是需要訪問到 AST 中的字面量節點獲取值即可,核心代碼如下:

圖片

圖片

函數

函數的調用最核心的就是在運行時需要把當前函數中的所有數據入棧,訪問完畢后出棧,這樣才能實現函數退出后自動釋放函數體類的數據。

核心代碼如下:

圖片

int b= 10;
int foo(){
return b;
}
int func(int a,int b) {
int e = foo();
return a+b+3+e;
}
func(2,20);

即便是有上面這類函數類調其他函數情況也不必擔心,無非就是在執行函數體的時候再往棧中寫入數據而已,函數退出后會依次退出棧幀。

圖片

有點類似于匹配括號的算法 {[()]},本質上就是遞歸調用。

總結

限于篇幅其中的許多細節沒有仔細討論,感興趣的朋友可以直接跑跑單測,debug 試試。

https://github.com/crossoverJie/gscript/blob/main/compiler_test.go

目前的版本還比較初級,比如基本類型還只有 int,也沒有一些常用的內置函數。

后續會逐步完善,比如新增:

  • 函數多返回值。
  • 自定義類型
  • 閉包

等特性,這個坑會一直填下去,希望在年底可以用 gscript? 寫一個 web 服務端那就算是里程碑完成了。

現階段也實現了一個簡易的 REPL? 工具,大家可以安裝試用:

圖片

源碼地址:https://github.com/crossoverJie/gscript

責任編輯:武曉燕 來源: crossoverJie
相關推薦

2019-11-18 11:00:58

程序員編程語言

2015-07-28 15:35:48

學習語言

2017-04-07 10:45:43

編程語言

2017-04-07 16:49:00

語言程序編程

2022-02-27 14:45:16

編程語言JavaC#

2022-11-04 11:11:15

語言入職項目

2022-09-07 08:05:32

GScript?編程語言

2020-11-12 07:00:50

JavaScript前端編程語言

2021-07-09 06:48:30

語言Scala編程

2022-02-21 11:15:59

編程語言后端開發

2012-03-28 09:40:40

JavaScript

2014-12-03 09:48:36

編程語言

2011-12-30 09:33:02

程序員語言

2024-06-27 09:00:00

人工智能編程語言軟件開發

2013-07-26 10:23:04

2015-08-17 15:12:56

新技術語言框架

2021-01-29 13:29:53

系統調用

2021-10-10 12:45:13

編程語言開發

2015-11-12 10:25:48

編程語言

2015-11-11 10:01:42

編程語言選擇
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美精品一区二区在线观看 | 久久久黑人 | 人人射人人 | 久产久精国产品 | 大乳boobs巨大吃奶挤奶 | 欧美日韩成人在线观看 | 韩国精品在线观看 | 精品久久久久久久久久久久久久 | 天天操操| 91一区 | 中国一级毛片免费 | 欧美视频日韩 | 亚洲一区二区中文字幕 | 在线亚洲欧美 | 韩国成人在线视频 | 成人在线中文 | 国产精品99久久久久久宅男 | 国产精品高潮呻吟久久 | 日韩av.com| 日韩成人免费中文字幕 | 最新91在线| 久久亚洲综合 | 免费观看的黄色网址 | 91av在线视频观看 | 视频在线一区 | av片在线免费看 | 久久国产亚洲精品 | 欧美性生活一区二区三区 | 久久精品国产一区 | av片在线观看网站 | 日韩精品视频在线播放 | 国产综合区 | 欧美成人a∨高清免费观看 91伊人 | 91嫩草精品 | 国产高清视频在线观看 | 男女午夜激情视频 | 毛片综合| 青青草在线播放 | 国产电影一区二区 | 免费观看一级特黄欧美大片 | 久草在线视频中文 |