Flex 和 Bison 使用方法


背景知識

在學編譯原理的時候,同時在做南京大學的編譯原理課程實驗,這里是鏈接,整個實驗的效果是實現一個完整的 C-- 語法的編譯器。C-- 語法是他們老師指定的一種類 C 語言。

Flex 和 Bison 是兩個在編譯前期最常實驗的工具,分別是用來做 lexical analyse 和 semantic analyse 的,這兩個工具的使用基本不需要很深的編譯知識,只需要掌握正則表達式的書寫(lexical analyse階段使用)和上下文無關文法(semantic analyse 階段使用),就可以完成這兩個階段的分析了。

Flex大體介紹

Flex 主要是用在詞法分析階段,不需要我們去手寫分析器,只需要制定好相應的正則表達式規則,他可以自動對輸入文件進行詞法分析。

Flex 主要在 Linux 系統下工作,安裝方式也很簡單。

sudo apt-get install flex

安裝好 flex 之后,我們創建一個 .l 后綴的文件,這個文件里面主要由三部分組成,定義了詞法分析的規則,整個文件的結構如下。

definitions
%%
rules
%%
user subroutines

在編寫好文件后,可以使用命令 flex file.l 進行編譯,編譯之后,我們會得到一個名為 file.yy.c 的文件,這個文件代碼中,我們只需要使用里面的 yylex() 函數,這個函數可以讀入文件中的一個詞法單元,然后進行規則匹配,即詞法分析。

我們可以在外部定義一個自己的 main() 進行調用,可也以在第三部分 {user subroutines} 中書寫 main() 函數進行調用。便於文件的組織,這里我們使用外部文件的方式定義一個新的主函數。

主要的代碼框架如下

extern File* yyin;
int main(int argc, char ** args) {
    if (argc > 1) {
        if( ! (yyin = fopen(argv[1], "r"))) {
            perror(argv[1]);
            return 1;
            }
        }
        while(yylex()!= 0);
        return 0;
}

這個 yyin 可以理解成輸入文件的文件指針,用來讀取文件,在 file.yy.c 中定義。

然后我們進行整體的編譯

gcc main.c file.yy.c -lfl -o scanner

-lfl 參數是指定一個庫函數,對於 MacOS 用戶,可以使用 -ll 參數進行代替。

這樣之后,對某個文件進行詞法分析就可以直接運行 ./scanner test.cmm 了。

Flex 規則部分

我們需要注意的是對 Flex 中的規則的編寫,整個 FLex 文件分別由三個部分,第一個部分通常定義一些之后常用的正則表達式,可以簡化書寫,定義格式為:

name definition

defintion 是一個具體的正則表達式,而 name 是其別名,比如,如果想定義一個識別任意數字的正則表達式,可以這樣定義

digit [0-9]

這個 digit 就是這個正則表達式的別名,和這個正則表達式的效果一樣,會和任意一個數字進行匹配。

第二部分是規則部分,即針對每一個特定的語法單元,我們對其有什么樣的操作。定義格式為

pattern {action}

這個pattern 和我們上面的一樣,都是正則表達式,而對應的 action 則指定了如果遇到了這個 pattern 之后,我們的應對方法。這個 pattern 我們可以重新定義,也可以直接使用在第一部分定義好的對應的 name,如果使用 name,則格式為 {name}。針對一些沒有匹配任何規則的詞法元素,我們可以使用 . 這個 pattern 指定對應的動作。

第三部分是用戶自定義的代碼部分,而這部分定義的方法,函數,都應該在第一部分中進行聲明,聲明格式為

%{
    
%}

這樣,聲明后的變量,函數和自定義的代碼片段都會在 file.yy.c 中生成,方便我們調用。

完成了這三個部分后,我們就可以生成一個簡單的語法分析器了。下面給出一個使用 flex 進行單詞統計的完整文件。

%{
    int chars = 0;
    int words = 0;
    int lines = 0;
%}
letter [a-zA-Z]
%%
{letter}+ {words ++; chars += yyleng; }
\n {chars++; lines ++;}
. {chars++;}
%%
int main(int argc, char** argv) {
    if (argc > 1) {
        if (!(yyin = fopen(argv[1], "r"))) {
            perror(argv[1]);
            return 1;
        }
    }
    yylex();
    printf("lines are %d words are %d chars are %d\n", lines, words, chars);
    return 0;
}

這里的 yyleng 是 flex 內置提供的變量,記錄當前單詞的長度。

這樣,整個詞法分析的過程就結束了,我們可以輸入對應的詞法流,在語法分析階段進行下一步的分析。而語法分析所用的工具,就是 bison。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM