# 機能設計書 73-fslex

## 概要

本ドキュメントは、F#用の字句解析器ジェネレータ「fslex」の設計を記述する。fslexは、字句解析仕様ファイル（.fsl）を読み込み、F#で記述された字句解析器（レキサー）のソースコードを生成するビルドツールである。

### 本機能の処理概要

**業務上の目的・背景**：プログラミング言語のコンパイラやインタプリタの実装において、字句解析（lexical analysis）は入力テキストをトークン列に分解する最初の処理段階である。fslexは、正規表現ベースの字句解析仕様から効率的なDFA（決定性有限オートマトン）ベースのレキサーを自動生成することで、F#コンパイラ自身のパーサーや、F#を使用した言語処理系の開発を支援する。本ツールはocamllexに類似したツールであり、F#エコシステムにおける言語処理ツールチェーンの重要な構成要素である。

**機能の利用シーン**：F#コンパイラのビルドプロセス中に、レキサー仕様ファイル（lex.fsl）からF#レキサーコード（lex.fs）を生成する際に使用される。また、F#で独自のDSL（Domain Specific Language）やプログラミング言語を開発する際にも利用可能である。

**主要な処理内容**：
1. コマンドライン引数の解析（出力ファイル名、モジュール名、Unicode対応等）
2. 仕様ファイル（.fsl）の読み込みとパース
3. 正規表現からNFA（非決定性有限オートマトン）への変換
4. NFAからDFA（決定性有限オートマトン）への変換（サブセット構成法）
5. DFA状態遷移テーブルのF#コード生成
6. 出力ファイル（.fs）およびシグネチャファイル（.fsi）の書き出し

**関連システム・外部連携**：FSharp.Text.Lexingライブラリと連携し、生成されたレキサーは実行時にこのライブラリの`LexBuffer`型を使用する。

**権限による制御**：本機能はビルドツールであり、ファイルシステムへの読み書きアクセス権限が必要。特別なユーザー権限制御は存在しない。

## 関連画面

本機能はコマンドラインツールであり、関連する画面は存在しない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | - |

## 機能種別

コード生成 / ビルドツール / オートマトン変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | string | Yes | 入力仕様ファイルパス（.fsl） | ファイルが存在すること |
| -o | string | No | 出力ファイル名 | 有効なファイルパス |
| --module | string | No | 生成モジュール名 | 有効なF#識別子 |
| --internal | flag | No | 内部モジュールとして生成 | - |
| --open | string | No | openするモジュール名（複数指定可） | 有効なモジュール名 |
| --codepage | int | No | 入力ファイルのコードページ | 有効なコードページ番号 |
| --lexlib | string | No | レキサーライブラリ名前空間 | デフォルト: FSharp.Text.Lexing |
| --unicode | flag | No | 16ビットUnicode対応レキサー生成 | - |
| -i | flag | No | 大文字小文字を区別しないレキサー | - |

### 入力データソース

- 仕様ファイル（.fsl）：字句解析ルールを定義したテキストファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 出力ファイル | .fs | 生成されたF#レキサーソースコード |
| シグネチャファイル | .fsi | 生成されたF#シグネチャファイル |

### 出力先

- 指定された出力ファイルパス、またはデフォルトで入力ファイルと同じディレクトリに拡張子を.fsに変更したファイル

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数解析
   └─ ArgParser.Parseで各オプションを処理
2. 仕様ファイルの読み込み
   └─ readSpecFromFileで仕様をパース
3. DFAへのコンパイル
   └─ compileSpecでNFA構築→DFA変換
4. 状態数の表示
   └─ コンソールに状態数を出力
5. 出力ファイルの生成
   └─ writeSpecToFileで.fsと.fsiを生成
```

### フローチャート

```mermaid
flowchart TD
    A[開始: main] --> B[コマンドライン引数解析]
    B --> C{入力ファイル指定?}
    C -->|No| D[エラー: no input given]
    C -->|Yes| E[readSpecFromFile]
    E --> F{パース成功?}
    F -->|No| G[エラー出力・終了]
    F -->|Yes| H[compileSpec呼び出し]
    H --> I[LexerStateToNfa]
    I --> J[NfaToDfa]
    J --> K[DFAノードのソート]
    K --> L[状態数を表示]
    L --> M[writeSpecToFile]
    M --> N[.fs/.fsi生成]
    N --> O[終了]
    D --> P[exit 1]
    G --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-73-01 | 単一入力 | 入力ファイルは1つのみ指定可能 | 常時 |
| BR-73-02 | デフォルト出力 | 出力ファイル未指定時は入力ファイルの拡張子を.fsに変更 | -o未指定時 |
| BR-73-03 | Unicode変換 | --unicode指定時は16ビット文字対応のDFA生成 | --unicode指定時 |
| BR-73-04 | 大文字小文字 | -i指定時は大文字小文字を同一視する遷移を生成 | -i指定時 |
| BR-73-05 | センチネル値 | 無効な遷移は0xFFFF（65535）で表現 | 常時 |

### 計算ロジック

- **NFA→DFA変換**: サブセット構成法（subset construction）
  - ε-closureを計算してNFA状態集合をDFA状態にマッピング
- **遷移テーブル**: 各DFA状態について、入力シンボルごとの遷移先状態をuint16配列として格納

## データベース操作仕様

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| FSL000 | 一般エラー | パースエラーまたは内部エラー | エラーメッセージを出力してexit 1 |
| - | 入力エラー | 入力ファイル未指定 | "no input given"を出力してexit 1 |
| - | 複数入力エラー | 複数の入力ファイル指定 | "more than one input given"で失敗 |
| - | パースエラー | 仕様ファイルの構文エラー | 行番号・列番号と共にエラー出力 |

### リトライ仕様

リトライは行わない。エラー発生時は即座にexit 1で終了。

## トランザクション仕様

本機能はトランザクション管理を必要としない。

## パフォーマンス要件

- 大規模な字句解析仕様でも実用的な時間内にDFA生成を完了すること
- DFA状態数は入力仕様の複雑さに依存するが、最小化は行われない

## セキュリティ考慮事項

- 入力ファイルの信頼性に依存
- 生成されたコードは直接実行されるため、仕様ファイルの出所を確認すること

## 備考

- F#コンパイラ自身のレキサー（lex.fsl→lex.fs）の生成にも使用される
- Unicode対応時は、特定のUnicode文字とUnicodeカテゴリの両方をサポート

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | fslexast.fs | `buildtools/fslex/fslexast.fs` | AST定義、NfaNode、DfaNode、正規表現型 |

**主要処理フロー**:
- **9-16行目**: ParseContext - Unicode/大文字小文字区別の設定
- **146-156行目**: Input/Regexp型 - 正規表現のAST定義
- **169-173行目**: Spec型 - 仕様全体の構造
- **176-187行目**: NfaNode/DfaNode - オートマトン状態の定義

**読解のコツ**: `Alphabet`型は`uint32`であり、文字やUnicodeカテゴリをエンコードした値を保持する。Eof（0xFFFFFFFE）とEpsilon（0xFFFFFFFF）は特殊値。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fslex.fs | `buildtools/fslex/fslex.fs` | メイン関数とコマンドライン処理 |

**主要処理フロー**:
- **14-24行目**: グローバル変数定義（オプション値）
- **25-36行目**: usage - コマンドライン引数定義
- **38行目**: ArgParser.Parse - 引数解析
- **40-43行目**: compileSpec - コンパイル処理呼び出し
- **45-86行目**: main関数 - 全体フロー制御

#### Step 3: コンパイル処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fslexast.fs | `buildtools/fslex/fslexast.fs` | Compile関数、LexerStateToNfa、NfaToDfa |

**主要処理フロー**:
- **212-312行目**: LexerStateToNfa - 正規表現からNFAを構築
- **355-434行目**: NfaToDfa - サブセット構成法でDFA変換
- **436-445行目**: Compile - 全ルールをコンパイル

#### Step 4: コード生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | fslexdriver.fs | `buildtools/fslex/fslexdriver.fs` | writeSpecToFile、遷移テーブル出力 |

**主要処理フロー**:
- **71行目**: sentinel定義（65535 = 0xFFFF）
- **111-182行目**: writeUnicodeTranslationArray - 遷移テーブル生成
- **199-243行目**: writeRules - ルール関数生成
- **249-260行目**: writeSpecToFile - ファイル出力の統合

### プログラム呼び出し階層図

```
fslex.main
    │
    ├─ ArgParser.Parse
    │      └─ usage定義を使用して引数解析
    │
    ├─ readSpecFromFile
    │      ├─ UnicodeFileAsLexbuf
    │      └─ Parser.spec / Lexer.token
    │
    ├─ compileSpec
    │      └─ Compile
    │             ├─ LexerStateToNfa
    │             │      ├─ NfaNodeMap.NewNfaNode
    │             │      └─ CompileRegexp（再帰）
    │             │
    │             └─ NfaToDfa
    │                    ├─ EClosure
    │                    ├─ ComputeMoves
    │                    └─ GetDfaNode
    │
    └─ writeSpecToFile
           ├─ writeLightMode
           ├─ writeModuleExpression
           ├─ writeOpens
           ├─ writeTopCode
           ├─ writeUnicodeTables
           │      ├─ writeUnicodeTranslationArray
           │      └─ writeUnicodeActionsArray
           ├─ writeRules
           ├─ writeBottomCode
           └─ writeFooter
```

### データフロー図

```
[入力]                    [処理]                              [出力]

.fsl仕様ファイル ───────▶ Parser.spec ──────────────────────▶ Spec (AST)
                               │
                               ▼
                         LexerStateToNfa
                               │
                               ▼
                         NfaNode集合
                               │
                               ▼
                         NfaToDfa
                               │
                               ▼
                         DfaNode集合
                               │
                               ▼
                         writeSpecToFile
                               │
                               ├───────────────────────────────▶ .fs ファイル
                               │
                               └───────────────────────────────▶ .fsi ファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| fslex.fs | `buildtools/fslex/fslex.fs` | ソース | メインエントリーポイント |
| fslexast.fs | `buildtools/fslex/fslexast.fs` | ソース | AST定義とNFA/DFA変換 |
| fslexdriver.fs | `buildtools/fslex/fslexdriver.fs` | ソース | コード生成とファイル出力 |
| fslexlex.fs | `buildtools/fslex/fslexlex.fs` | ソース | 仕様ファイルのレキサー |
| fslexpars.fs | `buildtools/fslex/fslexpars.fs` | ソース | 仕様ファイルのパーサー |
| Arg.fs | `buildtools/fslex/Arg.fs` | ソース | コマンドライン引数解析 |
| Lexing.fs | `buildtools/fslex/Lexing.fs` | ソース | レキシングユーティリティ |
| Parsing.fs | `buildtools/fslex/Parsing.fs` | ソース | パーシングユーティリティ |
