首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 詞法分析器系列總結(七):從定義到自訂實作完整指南

     編輯:關於C#

前言

前六篇詳細介紹詞法分析器相關演算法 (正則表達式 → NFA → DFA → 最小化 → 多規則/上下文/Reject)。本文從整體架構角度,說明 Cyjb.Compilers 類庫的使用指南與自訂詞法分析器實作要點。

一、類庫演進重點

  1. Token 標識改用 Enum:Token<T> 泛型,T 為列舉型別,提供編譯期檢查、語義清晰、可轉整數。
  2. 命名空間複數化:Cyjb.Compilers、Cyjb.Compilers.Lexers。
  3. 上下文切換僅支援 Label:簡化實作,不影響功能。
  4. DFA 表示重構:LexerRule<T> 介面更直觀。

二、定義詞法分析器四步驟

1. 定義 Token 列舉


public enum CalcToken
{
    Number, Plus, Minus, Multiply, Divide,
    LParen, RParen, Identifier, Assign, EndOfFile
}
  • 值從 0 開始連續,EndOfFile = -1 由 Token<T>.EndOfFile 內建處理。

2. 建立 Grammar<T> 並定義上下文


var grammar = new Grammar();
grammar.DefineContext("STRING", ContextType.Exclusive); // 排除型:僅啟用 STRING 規則
grammar.DefineContext("COMMENT", ContextType.Inclusive); // 包含型:啟用 COMMENT + 無上下文規則

預設上下文為 "Initial"。

3. 定義正則表達式 (可選,供複用)


grammar.DefineRegex("digit", "[0-9]+");
grammar.DefineRegex("ident", "[a-zA-Z_][a-zA-Z0-9_]*");

4. 定義終結符


grammar.DefineSymbol(CalcToken.Number, "{digit}"); // 簡單:自動回傳 Token
grammar.DefineSymbol(CalcToken.Identifier, "{ident}", ctx => 
{
    ctx.Token.Value = double.Parse(ctx.Text); // 自訂動作:解析數值存入 Token.Value
});
grammar.DefineSymbol(CalcToken.Plus, @"\+");
grammar.DefineSymbol(CalcToken.Minus, @"-");
grammar.DefineSymbol(CalcToken.Multiply, @"\*");
grammar.DefineSymbol(CalcToken.Divide, @"/");
grammar.DefineSymbol(CalcToken.LParen, @"\(");
grammar.DefineSymbol(CalcToken.RParen, @"\)");
grammar.DefineSymbol(CalcToken.Assign, @"=");
// 空白忽略:定義無標識符、動作為空
grammar.DefineSymbol(null, @"\s+", ctx => { /* 拋棄 */ });

ReaderController<T> 主要方法

  • Accept():接受匹配,回傳 Token。
  • More():保留本次文字,併入下次匹配 (如字串換行)。
  • Reject():拒絕匹配,嘗試次優規則。
  • BeginContext/PushContext/PopContext:上下文切換。

5. 建構詞法分析器


var lexer = grammar.ToLexer(); // 或 ToLexer(TextReader), ToLexer(string), ToLexer(Stream)
foreach (var token in lexer)
    Console.WriteLine(token);

三、自訂詞法分析器核心資料結構

從 grammar.LexerRule 取得 LexerRule<T>,包含:

  • CharClass[65536]:每個字元對應的字元類別索引。
  • Contexts:上下文標籤 → DFA 起始狀態索引 字典。
  • Symbols:終結符列表 (SymbolData<T>:標識符、動作、向前看資訊)。
  • States:DFA 狀態列表 (StateData:轉移表、對應終結符索引)。每上下文 2 個 DFA (行首/非行首)。

此資料結構不依賴 Grammar<T>,可序列化為 JSON、寫入 .cs 檔、甚至移植至其他語言 (Java、Go、Rust) 實作高效能詞法分析器。

四、自訂實作建議

  • 壓縮 DFA:使用四元組 (當前狀態, 字元類別, 下一狀態, 動作) 或雙陣列 (Base/Check) 大幅減少記憶體。
  • 避免虛函數呼叫:熱路徑 (逐字元掃描) 使用 switch 或查表替代多型。
  • 緩衝區管理:大檔案採用 Stream 分塊讀取,配合 More() 處理跨塊 Token。
  • 錯誤恢復:實作 Reject 回退機制,支援關鍵字/識別符衝突解決。

結語

詞法分析器是編譯器前端的基石。Cyjb.Compilers 提供從定義到 DFA 構建的完整管線,開發者可專注於語言文法設計,亦可深入底層自訂高效能掃描器。源碼與文檔請參考 GitHub 專案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved