編譯原理--基於Lex的詞法分析器實驗


Lex簡介

Lex

  • Lex 代表 Lexical Analyzar, 是一種用來構造詞法分析器的工具。它本身也可以稱為一個編譯器。
  • Lex讀入詞法分析器的規格說明,根據此說明,生成一個用c語言描述的詞法分析器。
  • 描述詞法分析器的規格說明的語言稱為Lex 語言或詞法分析器設計語言。
  • 用Lex 語言書寫的詞法分析器規格說明稱為Lex 源文件。
  • 實用程序Lex 把Lex 源程序翻譯成用c語言描述的目標程序,所以通常也稱為Lex 編譯器。

Lex工作原理

  • 一種匹配的常規表達式可能會包含相關的動作。這一動作可能還包括返回一個標記。
  • 當 Lex 接收到文件或文本形式的輸入時,它試圖將文本與常規表達式進行匹配。它一次讀入一個輸入字符,直到找到一個匹配的模式。
  • 如果能夠找到一個匹配的模式,Lex 就執行相關的動作(可能包括返回一個標記)。
  • 另一方面,如果沒有可以匹配的常規表達式,將會停止進一步的處理,Lex 將顯示一個錯誤消息。

Lex 和 C的關系

  • Lex 和 C 是強耦合的。一個 .lex 文件(Lex 文件具有 .lex 的擴展名)通過 lex 公用程序來傳遞,並生成 C 的輸出文件。這些文件被編譯為詞法分析器的可執行版本。

Lex 編程

該部分大部分內容參考:https://sighingnow.github.io/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86/lex_yacc.html

各位博友可以移步該博客做進一步了解Lex和Yacc的相關內容,這里僅僅做了Lex部分的介紹

編程過程:

  • 以 Lex 可以理解的格式指定模式相關的動作。
  • 在這一文件上運行 Lex,生成掃描器的 C 代碼。
  • 編譯和鏈接 C 代碼,生成可執行的掃描器。

Lex程序的大致結構(三段):

declarations,第一段是 C 和 Lex 的全局聲明
%%
translation rules,第二段包括模式(C 代碼)
%%
auxiliary procedures,第三段是補充的 C 函數。一般都用main函數。

%%作為段與段之間分隔符號

lex 依次嘗試每一個模式,盡可能地匹配最長的輸入流。如果有一些內容根本不匹配任何模式,那么 lex 將只是把它拷貝到標准輸出

字符及其含義列表:

A-Z, 0-9, a-z   構成了部分模式的字符和數字。
.               匹配任意字符,除了 \n。
-               用來指定范圍。例如:A-Z 指從 A 到 Z 之間的所有字符。
[ ]             一個字符集合。匹配括號內的 任意 字符。如果第一個字符是 ^ 那么它表示否定模式。
                例如: [abC] 匹配 a, b, 和 C中的任何一個。
*               匹配 0個或者多個上述的模式。
+               匹配 1個或者多個上述模式。
?               匹配 0個或1個上述模式。
$               作為模式的最后一個字符匹配一行的結尾。
{ }             指出一個模式可能出現的次數。 例如: A{1,3} 表示 A 可能出現1次或3次。
\               用來轉義元字符。同樣用來覆蓋字符在此表中定義的特殊意義,只取字符的本意。
^               否定。
|               表達式間的邏輯或。
"<一些符號>"     字符的字面含義。元字符具有。
/               向前匹配。如果在匹配的模版中的“/”后跟有后續表達式,只匹配模版中“/”前 面的部分。
                如:如果輸入 A01,那么在模版 A0/1 中的 A0 是匹配的。
( )             將一系列常規表達式分組。

幾個標記聲明舉例:

數字(number)      ([0-9])+                        1個或多個數字
字符(chars)       [A-Za-z]                        任意字符
空格(blank)       " "                             一個空格
字(word)          (chars)+                        1個或多個 chars
變量(variable)    (chars)+(number)*(chars)*(number)*

 

Lex變量和函數:

  • 一些常用的Lex變量如下所示:
    yyin        FILE* 類型。 它指向 lexer 正在解析的當前文件。
    yyout       FILE* 類型。 它指向記錄 lexer 輸出的位置。 缺省情況下,yyin 和 yyout 都指向標准輸入和輸出。
    yytext      匹配模式的文本存儲在這一變量中(char*)。
    yyleng      給出匹配模式的長度。
    yylineno    提供當前的行數信息。 (lexer不一定支持。)
  • Lex函數:
    yylex()     這一函數開始分析。 它由 Lex 自動生成。
    yywrap()    這一函數在文件(或輸入)的末尾調用。 如果函數的返回值是1,就停止解析。
                因此它可以用來解析多個文件。 代碼可以寫在第三段,這就能夠解析多個文件。
                方法是使用 yyin 文件指針(見上表)指向不同的文件,直到所有的文件都被解析。
                最后,yywrap() 可以返回 1 來表示解析的結束。
    yyless(int n)   這一函數可以用來送回除了前 n 個字符外的所有讀出標記。
    yymore()    這一函數告訴 Lexer 將下一個標記附加到當前標記后。
  • Lex內部預定義宏:
    ECHO     #define ECHO fwrite(yytext, yyleng, 1, yyout) 也是未匹配字符的默認動作。

 

一個簡單的Lex例子(單詞次數統計):

%{
/************************************************************
wc.l
Simple word count program. main is defined in the programs
section since the one in the library calls yyparse instead.

from Parser Generator Example
************************************************************/

int wc = 0; /* word count */
%}

%%
[a-zA-Z]+ { wc++; } // 前半部分是匹配,后半部分對應着動作,如果匹配着是一個單詞,wc++
\n|. { /* gobble up */ } // 如果是換行和.就跳過

%%
int main(void)
{
int n = yylex();
return n;
}

int yywrap(void)
{
printf("word count: %d\n", wc);
return 1;
}

 

Lex實現詞法分析器

Parser Generator部分

  • 創建一個新的項目

  

  • 有關項目的選項設置

  

  

   設置完后---下一步---完成

  • 完成相關內容編寫

   

   編譯后在該項目的路徑下生成.h和.c文件,將這兩個文件導入VC++中創建的項目中進行后續操作。

VC++部分

  • 將上述生成的兩個.h和.c文件導入創建好的項目
  • 下邊的配置參考一下文章完成:VC+ +中 YACC 編譯器的應用,張文彬 張曉芳(華中科技大學 湖北 武漢 430074)
  1. 目錄設置
    在 VC++中執行以下步驟 每個步驟只需執行一次
    ( 1) 選擇 Tools 菜單中的 Options 命令 在屏幕上即會出現 Options 對話框
    ( 2) 選擇 Directories 選項卡
    ( 3) 在 ShoW Directories for 下拉列表框中選擇 Include Files
    ( 4) 在 Directories 框中 點擊最后的空目錄 並填入 Parser generator 的 include 子目錄的路徑
    ( 5) 在 ShoW Directories for 下拉列表框中選擇 Library Files
    ( 6) 在 Directories 框中 點擊最后的空目錄 並填入 Parser generator 的 lib\msdev 子目錄的路徑
    ( 7) 在 ShoW Directories for 下拉列表框中選擇 Source Files
    ( 8) 在 Directories 框中 點擊最后的空目錄 並填入 Parser generator 的 source 子目錄的路徑
    ( 9) 點擊 OK 按鈕 Options 對話框將接受設置並關閉 

    VC+ + 現在就可以找到包含文件 yacc. h 和 lex. h 以及 YACC 和 Lex 的庫文件。

  2. 項目設置
    對於每個 VC+ + 項目, 都需在 VC+ + 中執行以下步驟,
    ( 1) 選擇 Project 菜單中的 Settings 命令, 在屏幕上即會出現 Project Settings 對話框,
    ( 2) 在 Settings for 下拉列表框中選擇 Win32 Debug,
    ( 3) 選擇 C/C+ + 標簽,
    ( 4) 在 Category 下拉列表框中選擇 General,
    ( 5) 在 Preprocessor Definitions 框中, 在當前文本的最后, 輸入 YYDEBUG,
    ( 6) 選擇 Link 標簽,
    ( 7) 在 Category 下拉列表框中選擇 General,
    ( 8) 在 Object/Library Modules 框 中, 在 當 前 文 本 的 后 面, 輸 入 yld.lib ylmtd.lib ylmtdlld.lib,
    ( 9) 在 Settings for 下拉列表框中選擇 Win32 Release,
    ( 10) 重復第8步的工作,
    ( 11) 點擊 OK 按鈕, Project Settings 對話框將接受設置並關閉。
   VC+ + 現在可以從特定的庫中接受 YACC 和 Lex 所需要的函數和變量。
   Node:在上述的項目配置中的(8),輸入ylmtdlld.lib會報錯誤,搜了一下網上相關的文章,發現只用輸入yld.lib即可,於是自作主張刪掉了ylmtdlld.lib如有大佬知道解決方法,還請不吝賜教。
  3. 完成上述配置后再Compile--Build--BuildExecute即可。
 
Node:本文如有錯誤之處,還請路過的博友斧正,感謝!


免責聲明!

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



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