Flex

最後更新: 2023-01-10 06:39:13 +0800 +0800
tags: Flex | Lexing | Gnu
原文以英文撰寫。您正在閱讀AI翻譯版本。

Flex 會根據將輸入文字對應至 C 或 C++ 動作的規則產生掃描器。掃描器通常會向剖析器提供權杖,但也可以轉換文字或驗證正則語言格式。Flex 手冊 定義了產生的介面以及各選項的行為。

規格結構 #

.l 檔案包含三個以 %% 分隔的部分:定義、規則和使用者程式碼。定義部分包含 C 宣告、命名正規表示式和開始條件。規則部分會將模式與動作配對。最後一個部分提供輔助函式,並在需要時提供驅動程式。

lex
%option noyywrap
%{
#include "parser.h"
%}

identifier  [[:alpha:]_][[:alnum:]_]*
%%
[[:space:]]+  ;
{identifier}   return IDENTIFIER;
"+"            return '+';
.              return INVALID;
%%

Flex 會選取與輸入文字中最長部分相符的規則。當多個規則相符的長度相同時,會選取書寫順序較前的規則。預設規則會將未相符的字元複製到標準輸出;當必須回報未相符的輸入時,請使用明確的萬用規則或 -s/%option nodefault。

正規表示式與掃描器狀態 #

Flex 模式描述正規語言。命名定義可以減少重複,字元類別用來表示與地區設定相關的群組,而加引號的文字則用來比對字面字串。當語言權杖需要逐字使用中繼字元時,請將其逸出或加上引號。

開始條件可以將規則集分割。使用 %s 宣告包含式條件,使用 %x 宣告排他式條件;使用 <STATE> 限定規則。

lex
%x COMMENT
%%
"/*"             BEGIN(COMMENT);
<COMMENT>"*/"    BEGIN(INITIAL);
<COMMENT>\n      ++line;
<COMMENT>.       ;
<COMMENT><<EOF>> return UNTERMINATED_COMMENT;

包含式條件會保留未限定的規則,而排他式條件只會執行明確限定為該條件或所有狀態的規則。除非使用 %option nodefault 或明確的萬用規則取代,否則 Flex 產生的預設規則在每個狀態中都保持啟用。使用 BEGIN 變更狀態;當動作需要檢查目前狀態時,使用 YY_START。對於可能提早結束輸入的狀態,請處理 <<EOF>>。請將字串、註解、縮排或詞法模式建模為明確狀態,而不要嘗試在單一模式中表達具上下文相關的結構。

產生的 API、緩衝區與可重入性 #

依預設,Flex 會產生 yylex() 以及 yytext、yyleng 和輸入緩衝區狀態等全域變數。%option prefix="project_" 會重新命名產生的公用符號,因此可以在同一個程式中使用多個掃描器。%option outfile="scanner.c" 會選取產生的檔案;命令列選項也可以提供相同的設定。

掃描器會透過緩衝區讀取輸入。yyrestart(FILE*) 會重新開始輸入,而 yy_scan_string 或 yy_scan_bytes 會掃描呼叫端提供的記憶體。請使用 yy_delete_buffer 刪除由 yy_scan_* 函式建立的緩衝區;當巢狀輸入需要在受管理的緩衝區之間切換時,使用 yy_switch_to_buffer。

%option reentrant 會建立掃描器控制代碼 (yyscan_t),並讓產生的 API 接受該控制代碼。使用 yylex_init/yylex_destroy(或 _extra 變體)初始化和銷毀控制代碼,然後透過 yyextra 而不是全域變數傳遞每個掃描器的狀態。當剖析器或執行緒必須彼此獨立運作時,請使用此模式。

剖析器整合與診斷 #

與 Bison 整合時,請設定相符的權杖宣告,並包含產生的剖析器標頭檔。%option bison-bridge 會透過掃描器介面傳遞語意值;%option bison-locations 另外也會傳遞位置資訊。請為每個消耗的字元(包括空白和註解)更新位置,否則診斷資訊會偏離原始碼。

請區分詞法分析錯誤與剖析器語法錯誤。掃描器應回傳或回報包含其來源範圍的無效權杖;剖析器應在文法上下文中描述非預期的權杖,並且只在刻意設定的同步點進行復原。

評論

在 GitHub 上閱讀或評論(發表評論需要登入)