靜態做用域和動態做用域的心得

最近在作編譯器時遇到靜態做用域和動態做用域的抉擇問題。
以前沒有仔細探究,作的時候才發現問題。javascript

靜態做用域,在編譯階段就作完全部name check的工做,像C語言:java

{
    // Push scope 1 table
    
    int a = 10;            // Insert (a, 10) to scope 1
    {
        // Push scope 2 table

        int a = 15;        // Insert (a, 15) to scope 2
        int b = 20;        // Insert (b, 20) to scope 2
        
        a = 100;        // Use a variable
        
        // Pop scope 2 table
    }
    
    // Pop scope 2 table
}
Scope 1
a 10
Scope 2
a 15
b 20

在語義分析階段的時候進行top-down parse,每進入一個block就push一張符號表,離開block時候就pop一張符號表,
使用一個變量時就依次從最後一個符號表向前找,若是找不到就該報undefined或者undeclared錯誤了。因此C語言的函數不能在定義前調用。由於在解析main的函數體時hello還沒插入到符號表裏。ide

int main(){
    hello();        // Use of undeclared identifier "hello"
      return 0;
}  
void hello(){};

動態做用域,像javascript這樣,就能夠在函數定義以前調用函數

var a = function(){
    b();            // Run-time name check
}
    
var b = function(){}
    
a();

a()->global
由於這時候再也不是編譯時的name check而是運行時的name check,做用域是函數做用域,在運行a函數而且執行到b()的時候,會在當前函數做用域找b的值,若是找不到就往上一個函數做用域尋找,直到global做用域。也就說,只要保證在函數運行到這個位置的時候,在做用域鏈裏存在這個變量,而與定義順序無關。spa

相關文章
相關標籤/搜索