天天看點

1.01 Flex基本文法格式和規則詳解

/* file: 1.01_word_counter.y */
/* 一個字數統計(word_counter)程式,程式讀入一個檔案然後報告這個檔案的行數、單詞樹和字元數。*/

/* 以下是Flex的第一部分為定義部分,包含選項、文字塊、起始條件和轉換等。
   文字塊存在與%{和%}之間,它們将被原樣拷貝到生成檔案中。
   以空白字元開頭的行會被原樣拷貝到C檔案中。通常用于/**/之間的多行注釋,在每行前面需要有空白字元。
   例如:用于聲明選項(%option),以及起始條件start condition(使用%x、%s聲明)
   */
%option noyywrap

/* %{ 和 %}之間的代碼被認為是文字塊,會被原樣拷貝到生成的檔案的開頭部分。*/
%{
int chars = 0; // 定義變量,用于計數有多少個字元
int words = 0; // 定義變量,用于計數有多少個單詞
int lines = 0; // 定義變量,用于計數有多少行
%}


/* 以下%%和%%之間是Flex的第二部分為規則部分,該部分定義一些比對模式(每個模式必須放在行首)和動作(模式比對成功是所執行的C代碼,使用{}括号包覆的一行或多行語句)。
   注意:
       在該部分也有%{ 和 %}定義的C代碼語句,它們會被原封不動地拷貝到yylex()中。
       在規則部分開頭出現的C代碼也會出現在yylex的開頭,它可以包含詞法分析器使用的變量,以及每次yylex()調用時所需運作的代碼。
       在其他部分出現的C代碼必須僅僅包含注釋,因為你無法預知它出現在詞法分析器的什麼位置。*/
%%
[a-zA-Z]+   {
            words++;
            chars += strlen(yytext); // yytext變量總是指向本次比對的輸入文本字元串
            } // 當滿足正規表達式:[a-zA-Z]+,表示成功識别到了一個單詞。words++并且chars增加單詞的字元長度
\n          {chars++; lines++; } // 當滿足正規表達式:\n,表示識别到了換行符。chars++并且lines++
.           {chars++; } // 當滿足正規表達式:.,表示識别到了任意一個單詞。chars++
%%
/* 以下是Flex的第三部分為使用者子例程部分,該部分會被拷貝到生成的詞法分析器裡面的C代碼。
   它們通常是一些與動作相關的程式代碼。
   */
int main(int argc, char **argv)
{
    yylex(); // 該函數是詞法分析器的主要函數,調用它将進行詞法分析
    printf("chars=%8d\n",chars); // 列印有多少個字元
    printf("words=%8d\n",words); // 列印有多少個單詞
    printf("lines=%8d\n",lines); // 列印有多少行
    return 0;
}

/*
注意:
    Q:上面的例子可以發現,第三條規則會比對所有的字元,
    難道它不會也比對第一個模式所能比對的單詞字母嗎?
    A:如果兩個模式都比對的話,flex會選擇在程式裡面首先出現的那個模式。
*/
           

如果你使用的是CLion來調試運作以上的代碼,你可能會碰到這樣的問題:

/home/cmp/work_dir/source_code/yacc_bison_practice/ch1/cmake-build-debug/word_counter
abc
def
^D
input in flex scanner failed

Process finished with exit code 2
           

正如上面,在CLion中調試運作程式,輸入

abc換行def換行

,然後在輸入ctrl+d,程式直接會報錯。這是由于CLion使用ctrl+d發送EOF始終有bug。最好在Terminal運作這個程式:

1.01 Flex基本文法格式和規則詳解

源碼見:

https://github.com/ronnie88597/yacc_bison_practice/blob/master/ch1/word_counter.l