1. 程式人生 > >C語言結構體struct的語法解析

C語言結構體struct的語法解析

本節內容需要結合視訊講解才能更容易理解,視訊播放地址如下:
用java開發編譯器

本節,我們著重研究結構體定義,也就是struct 這種變數定義,C語言編譯器是如何解析的,本節我們要解析的結構體定義如下:

struct tag {
    int x;
    long y;
    char z;
    struct tag* p;
}name;

1.1 結構體定義的解析語法

     * TYPE_SPECIFIER -> STRUCT_SPECIFIER
     * 
     * STTUCT_SPECIFIER -> STRUCT OPT_TAG LC DEF_LIST RC
     *                     | STRUCT TAG
     * 
     * OPT_TAG -> TAG
     * 
     * TAG -> NAME
     * 
     * DEF_LIST ->  DEF
     * 
     * DEF_LIST ->  DEF_LIST DEF
     *           
     *             
     * 
     * 
     *            
     * DEF -> SPECIFIERS  DECL_LIST SEMI
     *        | SPECIFIERS SEMI
     *       
     *        
     * DECL_LIST -> DECL
     *             | DECL_LIST COMMA DECL
     *             
     * DECL -> VAR_DECL
     * 
     * VAR_DECL -> NEW_NAME
     *             | VAR_DECL LP RP
     *             | VAR_DECL LP VAR_LIST RP
     *             | LP VAR_DECL RP
     *             | START VAR_DECL
     *

我們先看這一句定義:
STTUCT_SPECIFIER -> STRUCT OPT_TAG LC DEF_LIST RC

STRUCT 是關鍵字struct 對應的標籤, OPT_TAG 對應的是結構體變數的名字tag, LC 對應左大括號, DEF_LIST 對應結構體內部變數的定義序列,RC就是右大括號。這一句語法就已經描述了整個結構體的定義,解析的終點其實在 DEF_LIST, 這個非終結符描述的是結構體內部變數的定義規則,對DEF_LIST的解析是整個解析過程的難點。

1.2語法解析流程描述

解析開始時,詞法解析器會把關鍵字struct讀入,並返回一個STRUCT標籤。

讀入struct 後面的變數名tag, 返回對應標籤NAME.

根據表示式 TAG -> NAME, 將NAME轉換成非終結符TAG.

通過表示式 OPT_TAG -> TAG , 將TAG轉換成非終結符OPT_TAG.

讀入左大括號{, 並返回對應標籤LC.

*讀入關鍵字int, 並返回對應的標籤TYPE

*根據表示式TYPE_SPECIFIER -> TYPE, 將TYPE替換成非終結符TYPE_SPECIFIER. 這個表示式在前面的章節中講解過,本節沒有列出來。

*根據表示式 TYPE_OR_CLASS -> TYPE_SPECIFIER 將非終結符TYPE_SPECIFIER 轉換成TYPE_OR_CLASS.

*通過表示式 SPECIFIER -> TYPE_OR_CLASS, 將非終結符TYPE_OR_CLASS轉換成SPECIFIERS.

上面幾步完成了對關鍵字int 的解析。

接著讀入變數名x, 返回對應的標籤NAME.

*根據表示式NEW_NAME -> NAME, 將非終結符NEW_NAME 壓入堆疊。

*根據表示式VAR_DECL -> NEW_NAME 將非終結符換成VAR_DECL.

*通過表示式DECL -> VAR_DECL 將非終結符DECL替換掉VAR_DECL.

*通過表示式DECL_LIST -> DECL 將非終結符DECL_LIST 壓入堆疊。

*讀入分號,並返回對應的標籤SEMI

*根據表示式DEF -> SPECIFIERS DECL_LIST SEMI 將解析堆疊上的符號全部彈出,換成非終結符DEF.

再次通過 DEF_LIST -> DEF 將非終結符壓入堆疊。

在這一步我們可以看到,”int x ; “, 這一個變數定義語句可以被非終結符DEF_LIST所描述。

接下來,解析器讀入語句 “long y ;”,該語句的解析也同樣經歷前面帶*號的解析步驟,最後”long y;” 會解析成非終結符DEF,此時解析堆疊頂部有兩個非終結符DEF, DEF_LIST.

通過表示式 DEF_LIST -> DEF_LIST DEF 將兩個非終結符歸納成一個非終結符DEF_LIST.

解析器繼續讀入 “char z;”, 同樣經歷帶*號的解析步驟後,把該語句解析成非終結符DEF, 這時解析堆疊頭部又在此含有兩個非終結符 DEF_LIST, DEF, 於是又可以通過表示式 DEF_LIST -> DEF_LIST DEF 將兩個非終結符歸納為一個非終結符DEF_LIST.

接下來解析器再次遇到關鍵字struct, 讀入後返回對應標籤STRUCT.

入讀struct 後面的變數名tag,返回對應標籤NAME.

運用表示式 TAG -> NAME, 將非終結符TAG壓入堆疊。

採用表示式STRUCT_SPECIFIER -> STRUCT TAG 將堆疊頂部的兩個非終結符替換成STRUCT_SPECIFIER.

再通過TYPE_SPECIFIER -> STRUCT_SPECIFIER 將棧頂非終結符替換成TYPE_SPECIFIER.

接著分別通過兩個表示式TYPE_OR_CLASS -> TYPE_SPECIFIER 和 SPECIFIERS -> TYPE_OR_CLASS, 將棧頂元素替換成SPECIFIERS.

然後把代表指標的* 讀入,返回對應標籤STAR.

讀入星號後面的變數名p, 返回對應的標籤NAME.

通過表示式NEW_NAME -> NAME, 將非終結符NEW_NAME壓入解析堆疊。

通過VAR_DECL -> NEW_NAME 將棧頂元素替換成VAR_DECL.

此時棧頂元素包含VAR_DECL, 和 STAR, 這兩個元素正好形成表示式:
VAR_DECL -> STAR VAR_DECL 的右邊部分,於是經過一次reduce,將堆疊頂部的兩個元素替換成VAR_DECL.

繼續通過表示式DECL -> VAR_DECL, 將非終結符DECL壓入堆疊。

DECL 可以通過表示式DECL_LIST -> DECL 替換成DECL_LIST.

接著讀入變數p後面的分號,返回對應標籤SEMI

此時,解析堆疊上含有三個元素:SEMI, DECL_LIST, SPECIFIERS, 他們正好構成表示式DEF -> SPECIFIERS DECL_LIST SEMI 的右邊,於是通過該表示式進行一次reduce, 將DEF替換掉這三個符號。

此時,堆疊頂部有兩個元素,DEF, DEF_LIST, 又正好構成表示式:
DEF_LIST -> DEF_LIST DEF 的右邊,於是又可以用DEF_LIST 替換掉堆疊頂部的兩個元素。

接著讀入右括號 }, 返回對應標籤RC.

這時,堆疊頂部的5個元素正好對應表示式:
STRUCT_SPECIFIER -> STRUCT OPT_TAG LC DEF_LIST RC 的右邊,於是解析器可以一下子將這5個元素全部替換成STRUCT_SPECIFIER.

接著解析器可以通過TYPE_SPECIFIER -> STRUCT_SPECIFIER 將TYPE_SPECIFIER壓入堆疊。

然後把}後面的變數名name,讀入,解析流程跟前面講解的流程一樣。

讀入最後的分號後,解析堆疊上的元素正好構成表示式:
EXT_DEF -> .OPT_SPECIFIERS EXT_DECL_LIST SEMI
的右邊部分,於是整個解析堆疊頂部的元素全部彈出,換成符號EXT_DEF.

接下來的推導跟以前一樣,經過一系列固定步驟後,全域性非終結符PROGRAM會被壓入堆疊,從而使得解析器接收輸入文字。

由此可見,依賴本節給出的語法定義,解析器能夠順利的分解結構體的程式碼。

通過這幾節的解析流程分析,我們可以看到,寫的再繁雜,再雜亂無章的程式程式碼,只要符合語法,那麼這些看似隨機組合的字元或單詞,本質上遵從著一種非常嚴謹的層次和結構,這種層次和結構可以通過語法定義的方式描述出來,大道至簡,任何複雜的系統,其本質都可以歸因為若干簡單的原理。這就是科學之美,編譯原理的演算法之美,學習編譯原理或任何科學知識,其實是一種享受美的過程。

要體驗這種系統邏輯之美,需要巨大的耐心,和不厭其煩的探索,持之以恆的意志力,有這種恆心的人,才有可能“會當凌絕頂,一覽眾山小”,學習是一個不斷攀爬,跌倒,再攀爬的過程,只有要緊牙,永不放棄的人,才有可能在光明頂感受到“蕩胸生層雲,決眥入歸鳥”的人生成就感。

再次以王安石《遊褒禪山記》為每一位願意“吾將上下而求索”的同學共勉:

“古人之觀於天地、山川、草木、蟲魚、鳥獸,往往有得,以其求思之深而無不在也。夫夷以近,則遊者眾;險以遠,則至者少。而世之奇偉、瑰怪,非常之觀,常在於險遠,而人之所罕至焉,故非有志者不能至也。有志矣,不隨以止也,然力不足者,亦不能至也。有志與力,而又不隨以怠,至於幽暗昏惑而無物以相之,亦不能至也。然力足以至焉,於人為可譏,而在己為有悔;盡吾志也而不能至者,可以無悔矣,其孰能譏之乎?此餘之所得也!”

相信我,你,並不孤獨!