# 帳票設計書 3-IREP C構造体ダンプ (cstruct形式)

## 概要

mrubyの中間表現(IREP)をC言語の構造体初期化コードとして出力する帳票設計書である。`mrb_dump_irep_cstruct`関数により生成され、cfunc形式より効率的なロードが可能な組み込み向け形式である。

### 本帳票の処理概要

本帳票は、mrubyコンパイラ(mrbc)がRubyスクリプトをコンパイルした結果得られる中間表現(IREP)を、C言語の構造体リテラルとして出力する機能である。cfunc形式（No.2）がバイナリデータをuint8_t配列として出力するのに対し、cstruct形式はmrb_irep構造体やmrb_irep_pool構造体を直接C言語の初期化子として出力する。これにより、実行時のバイナリ解析（デシリアライズ）が不要となり、より高速なロードが実現できる。

**業務上の目的・背景**：組み込みシステムにおいて、起動時間の短縮が重要な要件である場合に使用される。cfunc形式ではロード時にRiteBinaryフォーマットの解析が必要だが、cstruct形式ではC構造体がコンパイル時に直接初期化されるため、実行時の解析コストがゼロとなる。ROM上に配置された構造体をそのまま参照できる点も大きな利点である。

**帳票の利用シーン**：mrbcコマンドに`-B`オプションと`-S`オプションを同時に指定して実行する場面で使用される。例: `mrbc -B my_script -S script.rb`。特に、ROM容量に余裕があり起動速度を重視する組み込みシステムで利用される。

**主要な出力内容**：
1. mrubyヘッダーファイルのインクルード文（`mruby.h`, `irep.h`, `debug.h`, `proc.h`, `presym.h`）
2. マクロ定義（`mrb_BRACED`, `mrb_DEFINE_SYMS_VAR`）
3. IREP構造体の各コンポーネント（iseq配列、pool配列、syms配列、reps配列、lv配列）
4. mrb_irep構造体の初期化子
5. RProc構造体の宣言
6. シンボル初期化関数（`{initname}_init_syms`）

**帳票の出力タイミング**：mrbcコマンドを`-B <symbol> -S`オプション付きで実行した際に出力される。

**帳票の利用者**：組み込みシステムエンジニア、性能最適化を行うmruby開発者。

## 帳票種別

Cソースコードファイル（.c形式テキストファイル、構造体初期化コード）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | CLIコマンド (mrbc) | `mrbc -B <symbol> -S [options] script.rb` | mrbcコマンド実行（-B -Sオプション指定） |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | Cソースコード (.c) |
| 用紙サイズ | N/A（テキストファイル） |
| 向き | N/A |
| ファイル名 | 命名規則: `{入力ファイル名(拡張子なし)}.c` （-oオプションで任意指定可能） |
| 出力方法 | ファイル書き込み（fprintf/fputs） |
| 文字コード | ASCII |

### PDF固有設定

N/A

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

出力されるCソースコードは、ヘッダー部（インクルード・マクロ）、明細部（子IREP→自IREP構造体の逆順出力）、フッター部（RProc構造体・初期化関数）の構成をとる。

```
┌─────────────────────────────────────┐
│  #include <mruby.h> 等              │
│  マクロ定義                          │
├─────────────────────────────────────┤
│  子IREP群の構造体定義（再帰・逆順）   │
│  ├─ pool配列                        │
│  ├─ syms配列                        │
│  ├─ iseq配列                        │
│  ├─ lv配列                          │
│  ├─ debug情報 (optional)            │
│  └─ mrb_irep構造体                  │
├─────────────────────────────────────┤
│  const struct RProc {initname}[]    │
│  {initname}_init_syms() 関数         │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | インクルード文 | mruby.h, irep.h, debug.h, proc.h, presym.h | 固定文字列 | テキスト |
| 2 | mrb_BRACEDマクロ | 可変長引数を波括弧で囲むヘルパーマクロ | 固定文字列 | テキスト |
| 3 | mrb_DEFINE_SYMS_VARマクロ | シンボル配列定義用マクロ | 固定文字列 | テキスト |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | reps配列 | 子IREPへのポインタ配列 | `irep->reps` | `static const mrb_irep *{name}_reps_{n}[]` | 可変 |
| 2 | pool配列 | リテラルプール | `irep->pool` | `static const mrb_irep_pool {name}_pool_{n}[]` | 可変 |
| 3 | syms配列 | シンボルテーブル | `irep->syms` | `mrb_DEFINE_SYMS_VAR({name}_syms_{n}, ...)` | 可変 |
| 4 | iseq配列 | 命令列 | `irep->iseq` | `static const mrb_code {name}_iseq_{n}[]` (20バイトごと改行) | 可変 |
| 5 | lv配列 | ローカル変数名 | `irep->lv` | `mrb_DEFINE_SYMS_VAR({name}_lv_{n}, ...)` | 可変 |
| 6 | debug情報 | デバッグ行番号情報 | `irep->debug_info` | 行番号配列、ファイル構造体、デバッグ情報構造体 | 可変 |
| 7 | irep構造体 | IREP本体 | `irep` | `static const mrb_irep {name}_irep_{n}` | 可変 |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | RProc構造体 | ルートプロシージャ | irep_0への参照 | `const struct RProc {initname}[]` |
| 2 | init_syms関数 | 実行時シンボル初期化関数 | init_syms_code文字列 | `static void {initname}_init_syms(mrb_state *mrb)` |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 入力ファイル | コンパイル対象のRubyスクリプトファイル(.rb) | Yes |
| -B \<symbol\> | 生成される構造体名（initname） | Yes |
| -S フラグ | cstruct形式を指定 | Yes |
| -s フラグ | static修飾子を付加する場合に指定 | No |
| -g フラグ | デバッグ情報を含める場合に指定 | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | IREP構造の深さ（子→親の順に出力） | 降順 |

### 改ページ条件

- iseq配列: 20バイトごとに改行
- debug行番号配列(ary形式): 10エントリごとに改行

## データベース参照仕様

### 参照テーブル一覧

本帳票はデータベースを参照しない。インメモリのIREPデータ構造体を直接C構造体リテラルに変換する。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| mrb_irep (構造体) | IREP本体データ | コンパイル結果から直接取得 |
| mrb_irep_pool (構造体) | リテラルプール | `irep->pool` |
| mrb_irep_debug_info (構造体) | デバッグ情報 | `irep->debug_info` |

### テーブル別参照項目詳細

#### mrb_irep

| 参照項目（フィールド名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| nlocals | 構造体初期化子のnlocals | 常時 | uint16_t |
| nregs | 構造体初期化子のnregs | 常時 | uint16_t |
| clen | 構造体初期化子のclen | 常時 | uint16_t |
| iseq | iseq配列（0x%02x形式） | 常時 | mrb_code配列 |
| pool | pool配列（型別初期化子） | plen > 0 | mrb_irep_pool配列 |
| syms | syms配列（MRB_SYM等マクロ） | slen > 0 | mrb_sym配列 |
| reps | reps配列（irep構造体ポインタ） | rlen > 0 | mrb_irep*配列 |
| lv | lv配列（MRB_SYM等マクロ） | lv != NULL | mrb_sym配列 |
| debug_info | デバッグ構造体 | MRB_DUMP_DEBUG_INFOフラグあり | mrb_irep_debug_info |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| iseq配列長 | `irep->ilen + sizeof(mrb_irep_catch_handler) * irep->clen` | なし | キャッチハンドラ分を含む |
| IREP番号(n) | 再帰的に `max + i` で採番 | なし | cdump_irep_struct内で管理 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[mrbcコマンド実行 -B -S] --> B[コマンドライン引数解析]
    B --> C[Rubyスクリプトコンパイル]
    C --> D[dump_file呼び出し]
    D --> E[mrb_dump_irep_cstruct呼び出し]
    E --> F[ヘッダー・マクロ出力]
    F --> G[cdump_irep_struct 再帰呼び出し]
    G --> H{子IREPあり?}
    H -->|Yes| I[子IREPを再帰処理]
    I --> H
    H -->|No| J[pool配列出力]
    J --> K[syms配列出力]
    K --> L[iseq配列出力]
    L --> M[lv配列出力]
    M --> N{デバッグ情報あり?}
    N -->|Yes| O[デバッグ構造体出力]
    N -->|No| P[mrb_irep構造体出力]
    O --> P
    P --> Q[RProc構造体出力]
    Q --> R[init_syms関数出力]
    R --> S[完了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| MRB_DUMP_INVALID_ARGUMENT (-6) | fp==NULL, initname==NULL, initname空文字 | `invalid C language symbol name` | -Bオプションの引数を確認 |
| MRB_DUMP_WRITE_FAULT (-2) | fprintf失敗 | `error in mrb dump ({outfile}) -2` | ディスク容量の確認 |
| MRB_DUMP_INVALID_IREP (-5) | デバッグ情報が複雑すぎる場合（flen!=1） | - | -gフラグを外すか、単一ファイルのスクリプトを使用 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1スクリプトファイルのIREP構造に依存 |
| 目標出力時間 | ミリ秒単位 |
| 同時出力数上限 | 1 |

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

- 出力されるCソースにはシンボル名、リテラル値、命令列が平文で含まれる
- MRB_SYM等のマクロ経由でシンボル名が可読形式で出力される
- `static`修飾子（-sフラグ）でシンボルの外部リンケージを防止可能

## 備考

- cstruct形式は`simple_debug_info`関数により、デバッグ情報が単一ファイルの場合のみサポートされる（flen==1の条件）
- シンボル名のうち、MRB_SYMマクロで表現できないもの（演算子記号等）は`{initname}_init_syms`関数内で`mrb_intern_lit`を使って実行時に解決される
- 演算子シンボルは`operator_table`（122-153行目）で名前に変換される（例: "+" → MRB_OPSYM(add)）
- RProc構造体は`MRB_GC_RED`, `MRB_OBJ_IS_FROZEN`フラグ付きで出力される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | irep.h | `include/mruby/irep.h` | `struct mrb_irep`（55-80行目）: 出力される構造体のフィールド構成 |
| 1-2 | irep.h | `include/mruby/irep.h` | `mrb_irep_pool`（30-40行目）: pool配列の型定義 |
| 1-3 | dump.h | `include/mruby/dump.h` | フラグ定義（20-22行目）: MRB_DUMP_DEBUG_INFO, MRB_DUMP_STATIC |

**読解のコツ**: cstruct形式はmrb_irep構造体をそのままC初期化子として出力するため、irep.hの構造体定義と出力コードの対応関係を理解することが鍵。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mrbc.c | `mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c` | `dump_file`関数（264-265行目）: dump_struct==TRUEの場合mrb_dump_irep_cstructを呼び出し |
| 2-2 | mrbc.c | `mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c` | `parse_args`関数（116行目）: -Sオプションでdump_struct=TRUEを設定 |

**主要処理フロー**:
1. **116行目**: -Sオプション検出、`args->dump_struct = TRUE`
2. **264行目**: dump_file内で`args->dump_struct`を判定
3. **265行目**: mrb_dump_irep_cstruct呼び出し

#### Step 3: cstructダンプのコア処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | cdump.c | `src/cdump.c` | `mrb_dump_irep_cstruct`（449-497行目）: メイン関数。ヘッダー出力→cdump_irep_struct→RProc→init_syms |
| 3-2 | cdump.c | `src/cdump.c` | `cdump_irep_struct`（337-427行目）: 再帰的にIREP構造体をCコードとして出力 |
| 3-3 | cdump.c | `src/cdump.c` | `cdump_pool`（28-73行目）: リテラルプールの型別出力 |
| 3-4 | cdump.c | `src/cdump.c` | `cdump_syms`（240-255行目）: シンボル配列の出力 |
| 3-5 | cdump.c | `src/cdump.c` | `cdump_sym`（191-237行目）: 個別シンボルの出力（MRB_SYMマクロ等の使い分け） |
| 3-6 | cdump.c | `src/cdump.c` | `cdump_debug`（272-334行目）: デバッグ情報の構造体出力 |

**主要処理フロー**:
- **455-462行目**: ヘッダーインクルード出力
- **467-477行目**: マクロ定義出力
- **480行目**: cdump_irep_struct再帰呼び出し
- **482-490行目**: RProc構造体出力
- **491-495行目**: init_syms関数出力

#### Step 4: シンボル名の変換ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | cdump.c | `src/cdump.c` | `sym_name_word_p`等（76-114行目）: シンボル名の分類関数群 |
| 4-2 | cdump.c | `src/cdump.c` | `operator_table`（122-153行目）: 演算子シンボルの名前変換テーブル |
| 4-3 | cdump.c | `src/cdump.c` | `sym_operator_name`（155-175行目）: 二分探索による演算子名検索 |

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

```
main() [mrbc.c:284]
    │
    └─ dump_file() [mrbc.c:258]
           │
           └─ mrb_dump_irep_cstruct() [cdump.c:449]
                  │
                  ├─ fprintf() ← ヘッダー・マクロ出力
                  │
                  ├─ cdump_irep_struct() [cdump.c:337]  ← 再帰
                  │      │
                  │      ├─ cdump_irep_struct() ← 子IREP再帰
                  │      ├─ cdump_pool() [cdump.c:28]
                  │      ├─ cdump_syms() [cdump.c:240]
                  │      │      └─ cdump_sym() [cdump.c:191]
                  │      │             ├─ sym_name_word_p() [cdump.c:76]
                  │      │             ├─ sym_operator_name() [cdump.c:155]
                  │      │             └─ (各分類関数)
                  │      ├─ cdump_debug() [cdump.c:272]  ← オプション
                  │      │      └─ simple_debug_info() [cdump.c:261]
                  │      └─ fprintf() ← irep構造体出力
                  │
                  ├─ fprintf() ← RProc構造体出力
                  └─ fputs() ← init_syms関数出力
```

### データフロー図

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

.rb スクリプト ───▶ mrb_load_file_cxt() ───▶ mrb_irep (メモリ上)

mrb_irep ───────▶ mrb_dump_irep_cstruct() ──▶ .c ファイル
                   │                             │
                   ├─ ヘッダー・マクロ出力          │
                   ├─ cdump_irep_struct (再帰)    │
                   │   ├─ reps[] ポインタ配列      │
                   │   ├─ pool[] 初期化子          │
                   │   ├─ syms[] MRB_SYMマクロ     │
                   │   ├─ iseq[] バイトコード配列   │
                   │   ├─ lv[] ローカル変数名      │
                   │   ├─ debug (optional)        │
                   │   └─ mrb_irep 構造体初期化子   │
                   ├─ RProc構造体宣言              │
                   └─ init_syms関数               │
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cdump.c | `src/cdump.c` | ソース | cstruct形式ダンプのコア実装。mrb_dump_irep_cstruct, cdump_irep_struct等 |
| dump.h | `include/mruby/dump.h` | ヘッダー | ダンプフラグ定義、エラーコード定義 |
| irep.h | `include/mruby/irep.h` | ヘッダー | mrb_irep構造体、mrb_irep_pool構造体定義 |
| debug.h | `include/mruby/debug.h` | ヘッダー | mrb_irep_debug_info構造体定義 |
| mrbc.c | `mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c` | ソース | mrbcコマンドのエントリーポイント、-S/-Bオプション解析 |
| proc.h | `include/mruby/proc.h` | ヘッダー | RProc構造体定義（出力されるRProcの型） |
