編譯程序時放在符號表里的不光是內存地址和函數/變量的對應關系,還有很多在編譯時要用到的信息。比如該節點的各種屬性(類型,作用域,分配空間大小,(函數)的參數類型)等等。
符號表與編譯的各個階段都有交互。對符號表的具體使用方法每個編譯器都不同。 目標文件中的符號表用來輸出函數/變量符號信息,供連接時給其他模塊引用。這種符號表中主要包含
函數/變量的名稱和地址對應關系,其中的地址一般是位置無關碼(PIC碼)。 ( 節點是指分析樹上的某個節點。看看編譯的書你即可明白。:)
位置無關碼是指代碼中出現的內存地址和具體運行環境無關(相對地址),這樣的代碼可被loader載入內存中的任意某個位置運行。從而增加了程序的靈活性。動態連接庫中的代碼全是
位置無關碼,因為動態連接庫也需要這種能力。
在編譯程序中符號表用來存放語言程序中出現的有關標識符的屬性信息,這些信息集中反映了標識符的語義特征屬性。在詞法分析及語法在分析過程中不斷積累和更新表中的信息,
並在詞法分析到代碼生成的各階段,按各自的需要從表中獲取不同的屬性信息。不論編譯策略是否分趟,符號表的作用和地位是完全一致的。
① 收集符號屬性
收集符號屬性 編譯程序掃描說明部分收集有關標識符的屬性,並在符號表中建立符號的相應屬性信息。
例如,編譯程序分析到下述兩個說明語句 int A; float B[5];
則在符號表中收集到關於符號A的屬性是一個整型變量,關於符號B的屬性是具有5個浮點型元素的一維數組。
② 上下文語義的合法性檢查的依據
上下文語義的合法性檢查的依據 同一個標識符可能在程序的不同地方出現,而有關該符號的屬性是在這些不同情況下收集的。
特別是在多趟編譯及程序分段編譯(在PASCAL及C中以文件為單位)的情況下,更需檢查標識符屬性在上下文中的一致性和合法性。通過符號表中屬性記錄可進行相應上下文的語義檢查。
例如,在一個C語言程序中出現
…
int i [3,5]; //定義整型數組i
…
float i[4,2]; //定義實型數組i,重定義沖突
…
int i [3,5]; //定義整型數組i,重定義沖突
…
編譯過程首先在符號表中記錄了標識符i的屬性是3×5個整型元素的數組,而后在分析第二、第三這兩個定義說明時編譯系統可通過符號表檢查出標識符i的二次重定義沖突錯誤。
本例還可以看到不論在后二句中i的其它屬性與前一句是否完全相同,只要標識符名重定義,就將產生重定義沖突的語義錯誤。
③ 作為目標代碼生成階段地址分配的依據
作為目標代碼生成階段地址分配的依據 每個符號變量在目標代碼生成時需要確定其在存儲分配的位置(主要是相對位置)。
語言程序中的符號變量由它被定義的存儲類別(如在C、FORTRAN語言中)或被定義的位置(如分程序結構的位置)來確定。
首先要確定其被分配的區域。例如,在C語言中首先要確定該符號變量是分配在公共區(extern)、文件靜態區(extern static)、
函數靜態區(函數中static)、還是函數運行時的動態區(auto)等。
其次是根據變量出現的次序,(一般來說)決定該變量在某個區中所處的具體位置,這通常使用在該區域中相對區頭的相對位置確定。
而有關區域的標志及相對位置都是作為該變量的語義信息被收集在該變量的符號表屬性中