檢視原始碼 leex (parsetools v2.6)

Erlang 的詞法分析器產生器

一個基於正規表達式的 Erlang 詞法分析器產生器,類似於 lexflex

注意

leex 模組被引入時,它被認為是實驗性的。

預設 Leex 選項

(主機作業系統)環境變數 ERL_COMPILER_OPTIONS 可以用來提供預設的 Leex 選項。它的值必須是有效的 Erlang 項。如果該值是一個列表,則直接使用。如果它不是一個列表,則將其放入一個列表中。

該列表會附加到任何傳遞給 file/2 的選項中。

可以使用 compile:env_compiler_options/0 來檢索該列表。

輸入檔案格式

% 開頭的 Erlang 風格註解在掃描器檔案中是允許的。定義檔案具有以下格式:

<Header>

Definitions.

<Macro Definitions>

Rules.

<Token Rules>

Erlang code.

<Erlang code>

Definitions.Rules.Erlang code 標題是強制性的,並且必須從原始碼行的開頭開始。<Header><Macro Definitions><Erlang code> 區段可以為空,但至少必須有一條規則。

巨集定義具有以下格式:

NAME = VALUE

而且在 = 周圍必須有空格。巨集可以透過寫入 {NAME} 來在規則的正規表達式中使用。

注意

當巨集在表達式中展開時,巨集呼叫會被替換為巨集值,而不會有任何形式的引用或括在括號中。

規則具有以下格式:

<Regexp> : <Erlang code>.

<Regexp> 必須出現在行的開頭,且不包含任何空格;使用 \t\s 在正規表達式中包含 TAB 和 SPACE 字元。如果 <Regexp> 匹配,則會評估對應的 <Erlang code> 以產生一個 token。在 Erlang 程式碼中,可以使用以下預定義的變數:

  • TokenChars - 匹配的 token 中的字元列表。

  • TokenLen - 匹配的 token 中的字元數。

  • TokenLine - token 出現的行號。

  • TokenCol - token 出現的欄號(token 中第一個字元的欄位)。

  • TokenLoc - token 位置。展開為 {TokenLine,TokenCol}(即使 error_location 設定為 line)。

程式碼必須回傳:

  • {token,Token} - 回傳 Token 給呼叫者。

  • {end_token,Token} - 回傳 Token 且是 tokens 呼叫中的最後一個 token。

  • skip_token - 完全略過此 token。

  • {error,ErrString} - token 中的錯誤,ErrString 是描述錯誤的字串。

也可以使用以下回傳將字元推回輸入字元中:

  • {token,Token,PushBackList}
  • {end_token,Token,PushBackList}
  • {skip_token,PushBackList}

這些與正常的回傳具有相同的含義,但是 PushBackList 中的字元將會前置到輸入字元中,並掃描下一個 token。請注意,推回換行符號將表示行號不再正確。

注意

推回字元會導致掃描器進入迴圈的意想不到的可能性!

以下範例會匹配一個簡單的 Erlang 整數或浮點數,並回傳一個可以傳送到 Erlang 解析器的 token:

D = [0-9]

{D}+ :
  {token,{integer,TokenLine,list_to_integer(TokenChars)}}.

{D}+\.{D}+((E|e)(\+|\-)?{D}+)? :
  {token,{float,TokenLine,list_to_float(TokenChars)}}.

Erlang code. 區段中的 Erlang 程式碼會直接寫入到輸出檔案中的模組宣告和預定義匯出宣告之後,因此可以新增額外的匯出、定義匯入和其他屬性,這些屬性在整個檔案中都是可見的。

正規表達式

此處允許的正規表達式是 egrep 和 AWK 程式語言中的一組子集,如同 A. V. Aho、B. W. Kernighan 和 P. J. Weinberger 所著的 The AWK Programming Language 一書中所定義。它們由以下字元組成:

  • c - 匹配非元字元 c。

  • \c - 匹配跳脫序列或字面字元 c。

  • . - 匹配任何字元。

  • ^ - 匹配字串的開頭。

  • $ - 匹配字串的結尾。

  • [abc...] - 字元類別,匹配任何字元 abc...。字元範圍由一對以 - 分隔的字元指定。

  • [^abc...] - 反向字元類別,匹配任何除了 abc... 之外的字元。

  • r1 | r2 - 交替。它匹配 r1r2

  • r1r2 - 串接。它匹配 r1 然後 r2

  • r+ - 匹配一個或多個 r

  • r* - 匹配零個或多個 r

  • r? - 匹配零個或一個 r

  • (r) - 分組。它匹配 r

允許的跳脫序列與 Erlang 字串的相同:

  • \b - 退格鍵。

  • \f - 換頁符號。

  • \n - 換行符號(換行)。

  • \r - 歸位符號。

  • \t - Tab。

  • \e - 跳脫符號。

  • \v - 垂直 Tab。

  • \s - 空格。

  • \d - 刪除。

  • \ddd - 八進位值 ddd

  • \xhh - 十六進位值 hh

  • \x{h...} - 十六進位值 h...

  • \c - 任何其他字元,例如 \\ 代表反斜線,\" 代表 "

以下範例定義了一些簡化的 Erlang 資料類型版本:

Atoms [a-z][0-9a-zA-Z_]*

Variables [A-Z_][0-9a-zA-Z_]*

Floats (\+|-)?[0-9]+\.[0-9]+((E|e)(\+|-)?[0-9]+)?

注意

目前版本的 leex 中未實作使用 ^$ 定錨正規表達式,並會產生剖析錯誤。

摘要

類型

從所有 I/O 模組回傳的標準 error_info/0 結構。ErrorDescriptor 可以由 format_error/1 格式化。

產生的掃描器匯出

掃描 String 並回傳其中所有的 token 或一個 error 元組。

這是一個可重入的呼叫,嘗試從 Chars 中掃描單個 token。

這是一個可重入的呼叫,嘗試從 Chars 中掃描 token。

函式

從輸入檔案中的定義產生一個詞法分析器。

回傳以英文描述的錯誤原因字串 ErrorDescriptor,此字串是由 leex:file/1,2 在正規表達式中發生錯誤時回傳的。

類型

連結到此類型

error_info()

檢視原始碼 (未匯出)
-type error_info() :: {erl_anno:line() | none, module(), ErrorDescriptor :: term()}.

從所有 I/O 模組回傳的標準 error_info/0 結構。ErrorDescriptor 可以由 format_error/1 格式化。

連結到此類型

error_ret()

檢視原始碼 (未匯出)
-type error_ret() :: error | {error, Errors :: errors(), Warnings :: warnings()}.
連結到此類型

errors()

檢視原始碼 (未匯出)
-type errors() :: [{file:filename(), [error_info()]}].
連結到此類型

leex_ret()

檢視原始碼 (未匯出)
-type leex_ret() :: ok_ret() | error_ret().
連結到此類型

ok_ret()

檢視原始碼 (未匯出)
-type ok_ret() ::
          {ok, Scannerfile :: file:filename()} | {ok, Scannerfile :: file:filename(), warnings()}.
連結到此類型

warnings()

檢視原始碼 (未匯出)
-type warnings() :: [{file:filename(), [error_info()]}].

產生的掃描器匯出

-spec string(String) -> StringRet
                when
                    String :: string(),
                    StringRet :: {ok, Tokens, EndLoc} | ErrorInfo,
                    Tokens :: [Token],
                    Token :: term(),
                    ErrorInfo :: {error, error_info(), erl_anno:location()},
                    EndLoc :: erl_anno:location().

等同於 string(String, 1)

連結到此函式

string(String, StartLoc)

檢視原始碼
-spec string(String, StartLoc) -> StringRet
                when
                    String :: string(),
                    StringRet :: {ok, Tokens, EndLoc} | ErrorInfo,
                    Tokens :: [Token],
                    Token :: term(),
                    ErrorInfo :: {error, error_info(), erl_anno:location()},
                    StartLoc :: erl_anno:location(),
                    EndLoc :: erl_anno:location().

掃描 String 並回傳其中所有的 token 或一個 error 元組。

StartLocEndLoc 要不是 erl_anno:line() 就是 erl_anno:location(),取決於 error_location 選項。

注意

如果 String 中的字元並未全部被消耗,則會發生錯誤。

-spec token(Cont, Chars) -> {more, Cont1} | {done, TokenRet, RestChars}
               when
                   Cont :: [] | Cont1,
                   Cont1 :: tuple(),
                   Chars :: string() | eof,
                   RestChars :: string() | eof,
                   TokenRet :: {ok, Token, EndLoc} | {eof, EndLoc} | ErrorInfo,
                   ErrorInfo :: {error, error_info(), erl_anno:location()},
                   Token :: term(),
                   EndLoc :: erl_anno:location().

等同於 token(Cont, Chars, 1)

連結到此函式

token(Cont, Chars, StartLoc)

檢視原始碼
-spec token(Cont, Chars, StartLoc) -> {more, Cont1} | {done, TokenRet, RestChars}
               when
                   Cont :: [] | Cont1,
                   Cont1 :: tuple(),
                   Chars :: string() | eof,
                   RestChars :: string() | eof,
                   TokenRet :: {ok, Token, EndLoc} | {eof, EndLoc} | ErrorInfo,
                   ErrorInfo :: {error, error_info(), erl_anno:location()},
                   Token :: term(),
                   StartLoc :: erl_anno:location(),
                   EndLoc :: erl_anno:location().

這是一個可重入的呼叫,嘗試從 Chars 中掃描單個 token。

如果 Chars 中有足夠的字符可以掃描出一個符記 (token) 或偵測到錯誤,則會回傳 {done,...}。否則會回傳 {cont,Cont},其中 Cont 會在下次呼叫 token() 時使用,並帶入更多字符以嘗試掃描符記。這個過程會持續到成功掃描出符記為止。Cont 的初始值為 []

此函式並非設計為由應用程式直接呼叫,而是透過 I/O 系統使用,通常在應用程式中可以透過以下方式呼叫:

io:request(InFile, {get_until,unicode,Prompt,Module,token,[Loc]})
  -> TokenRet
-spec tokens(Cont, Chars) -> {more, Cont1} | {done, TokensRet, RestChars}
                when
                    Cont :: [] | Cont1,
                    Cont1 :: tuple(),
                    Chars :: string() | eof,
                    RestChars :: string() | eof,
                    TokensRet :: {ok, Tokens, EndLoc} | {eof, EndLoc} | ErrorInfo,
                    Tokens :: [Token],
                    Token :: term(),
                    ErrorInfo :: {error, error_info(), erl_anno:location()},
                    EndLoc :: erl_anno:location().

等同於 tokens(Cont, Chars, 1)

連結到此函式

tokens(Cont, Chars, StartLoc)

檢視原始碼
-spec tokens(Cont, Chars, StartLoc) -> {more, Cont1} | {done, TokensRet, RestChars}
                when
                    Cont :: [] | Cont1,
                    Cont1 :: tuple(),
                    Chars :: string() | eof,
                    RestChars :: string() | eof,
                    TokensRet :: {ok, Tokens, EndLoc} | {eof, EndLoc} | ErrorInfo,
                    Tokens :: [Token],
                    Token :: term(),
                    ErrorInfo :: {error, error_info(), erl_anno:location()},
                    StartLoc :: erl_anno:location(),
                    EndLoc :: erl_anno:location().

這是一個可重入的呼叫,嘗試從 Chars 中掃描 token。

如果 Chars 中有足夠的字符可以掃描出多個符記或偵測到錯誤,則會回傳 {done,...}。否則會回傳 {cont,Cont},其中 Cont 會在下次呼叫 tokens() 時使用,並帶入更多字符以嘗試掃描符記。這個過程會持續到成功掃描出所有符記為止。Cont 的初始值為 []

此函式與 token 的不同之處在於,它會持續掃描符記,直到掃描到包含 {end_token,Token} 的符記(請參閱下一節)。接著它會回傳所有符記。這通常用於掃描像 Erlang 這種有明確結束符記(例如 '.')的文法。如果沒有找到結束符記,則會掃描並回傳整個檔案。如果發生錯誤,則會跳過所有符記,直到下一個結束符記(包含結束符記)。

此函式並非設計為由應用程式直接呼叫,而是透過 I/O 系統使用,通常在應用程式中可以透過以下方式呼叫:

io:request(InFile, {get_until,unicode,Prompt,Module,tokens,[Loc]})
  -> TokensRet

函式

-spec file(FileName) -> leex_ret() when FileName :: file:filename().

等同於 file(File, [])

連結到此函式

file(FileName, Options)

查看原始碼 (自 OTP R16B02 起)
-spec file(FileName, Options) -> leex_ret()
              when
                  FileName :: file:filename(),
                  Options :: Option | [Option],
                  Option ::
                      {dfa_graph, boolean()} |
                      {includefile, Includefile :: file:filename()} |
                      {report_errors, boolean()} |
                      {report_warnings, boolean()} |
                      {report, boolean()} |
                      {return_errors, boolean()} |
                      {return_warnings, boolean()} |
                      {return, boolean()} |
                      {scannerfile, Scannerfile :: file:filename()} |
                      {verbose, boolean()} |
                      {warnings_as_errors, boolean()} |
                      {deterministic, boolean()} |
                      {error_location, line | column} |
                      {tab_size, pos_integer()} |
                      dfa_graph | report_errors | report_warnings | report | return_errors |
                      return_warnings | return | verbose | warnings_as_errors.

從輸入檔案中的定義產生一個詞法分析器。

輸入檔案的副檔名為 .xrl。如果未指定副檔名,則會將其添加到檔名中。產生的模組名稱為不帶 .xrl 副檔名的 Xrl 檔案名稱。

目前的選項如下:

  • dfa_graph - 產生一個 .dot 檔案,其中包含 DFA 的描述,其格式可使用 Graphviz (www.graphviz.com) 檢視。

  • {includefile,Includefile} - 使用特定的或自訂的序言檔案,而不是預設的 lib/parsetools/include/leexinc.hrl (否則會包含此檔案)。

  • {report_errors, boolean()} - 啟用後,會印出發生的錯誤。預設值為 true

  • {report_warnings, boolean()} - 啟用後,會印出發生的警告。預設值為 true

  • {report, boolean()} - 此為 report_errorsreport_warnings 的簡寫形式。

  • {return_errors, boolean()} - 如果設定此標誌,當發生錯誤時會回傳 {error, Errors, Warnings}。預設值為 false

  • {return_warnings, boolean()} - 如果設定此標誌,則成功回傳的元組會加入包含 Warnings 的額外欄位。預設值為 false

  • {return, boolean()} - 此為 return_errorsreturn_warnings 的簡寫形式。

  • {scannerfile, Scannerfile} - Scannerfile 為將包含產生的 Erlang 掃描器程式碼的檔案名稱。預設值 ("") 是將 .erl 副檔名加到去除 .xrl 副檔名的 FileName 上。

  • {verbose, boolean()} - 輸出從解析輸入檔案和產生內部表格的資訊。

  • {warnings_as_errors, boolean()} - 將警告視為錯誤。

  • {deterministic, boolean()} - 使產生的 -file() 屬性僅包含檔案路徑的基本名稱。

  • {error_location, line | column} - 如果設定為 column,錯誤位置將會是 {Line,Column} 元組,而不僅僅是 Line。此外,string/2token/3tokens/3 函式中的 StartLocEndLoc 也會是 {Line,Column} 元組,而不僅僅是 Line。預設值為 line。請注意,即使 error_location 設定為 line,您也可以獨立使用 TokenLoc 來取得符記位置。

    Unicode 字元會被計算為佔用多少位元組來表示的欄位數。

  • {tab_size, pos_integer()} - 設定 \t 字元的寬度(僅在 error_location 設定為 column 時相關)。預設值為 8

任何布林選項都可以透過宣告選項名稱來設定為 true。例如,verbose 等同於 {verbose, true}

Leex 將會把 .hrl 副檔名加入 Includefile 名稱中,並將 .erl 副檔名加入 Scannerfile 名稱中,除非副檔名已經存在。

連結到此函式

format_error(ErrorDescriptor)

檢視原始碼
-spec format_error(ErrorDescriptor) -> io_lib:chars() when ErrorDescriptor :: term().

回傳以英文描述的錯誤原因字串 ErrorDescriptor,此字串是由 leex:file/1,2 在正規表達式中發生錯誤時回傳的。