世界を動かす技術を、日本語で。

500行のPythonでCコンパイラを書く (2023)

2025年9月4日原文(vgel.me)

概要

  • Python で500行以内の Cコンパイラ を作成した挑戦記
  • 単一パス で構文解析とコード生成を同時に実施
  • WebAssembly をターゲットとした独自設計
  • いくつかのC言語機能を 省略 しつつ、主要機能を実装
  • 補助クラス や構造についても解説

500行Python製Cコンパイラ開発記

目標と概要

  • Python500行 以内にCコンパイラを実装する試み
  • 省略可能な機能を削り、 シンプル かつ 理解しやすい 設計を目指す
  • ブログ記事内で全コードは紹介できないため、 設計判断削除した機能アーキテクチャ の概要を解説

単一パスコンパイラの選択

  • 単一パス 方式を採用し、構文解析中に即時コード生成
  • 構文木(AST) を生成しない設計
  • 一般的なコンパイラは「構文木生成→コード生成」の 2パス 構成
    • 解析とコード生成を分離しやすい
    • 最適化中間表現 の導入が容易
  • 500行制限のため、 解析と生成を統合
    • 例: ~演算子 のパース時に即時WebAssembly命令を出力
    • 構文木ノード や中間表現は未使用

WebAssemblyをターゲットに選定

  • WebAssembly を出力対象とした理由は興味本位
  • WebAssembly はC言語向きではなく、独自の難しさ
    • goto非対応、代わりに block/break構造 を利用
    • レジスタ非搭載スタックマシン 方式
      • Cの スタック とWASMのスタックは別管理が必要
      • 自前で メモリ上のスタック を用意
  • x86/ARM等の従来ISAより 複雑化 した可能性

エラーハンドリング

  • die関数 による簡易的なエラー処理のみ
  • 異常時は スタックトレース と曖昧なエラーメッセージを出力
  • Rustコンパイラ のような高機能エラー表示は非対応

実装しなかった機能

  • structenumunionプリプロセッサ浮動小数点型long/double
  • 多次元配列前置/後置インクリメントキャスト式標準ライブラリやI/O
  • typedefポインタ 等、C言語実装の肝となる部分は維持

実装済み機能

  • 算術演算子優先順位 の正しい処理
  • int/short/char型文字列定数 (エスケープ対応)
  • 多重ポインタ正しいポインタ演算
  • 一次元配列関数定義・呼び出し
  • typedef 対応(lexer hack活用)

テストケースとサンプルプログラム

  • c-testsuite の34/220テストをパス
  • swap関数フィボナッチ関数 等、実用的なCプログラムも実行可能

補助クラス群の概要

  • Emitter

    • WebAssemblyコードの 整形出力 を担当
    • インデントや no_emit メソッドによる出力制御
  • StringPool

    • 文字列定数を 連続領域 にまとめて管理
    • 既存文字列の再利用や アドレス管理 を実装
    • 最終的に rodataセクション として出力
  • Lexer

    • C言語の トークン分割 を担当
    • peek/next/try_next による柔軟なトークン取得
    • lexer hack でtypedefや型名判定を実現
      • 型情報を動的に Lexer へフィードバックし、型名/変数名の区別を管理
  • CType

    • C言語型( intshort など)の情報を管理するデータクラス
    • ポインタレベル配列サイズ の情報も保持
    • 多次元配列 は非対応
  • FrameVar/StackFrame

    • C言語の スタックフレーム管理 を担当
    • WASMのスタックが使えないため、 独自のメモリスタック を構築
    • 各関数ごとに ローカル変数・引数 のスロット割当と スタックサイズ計算

まとめ

  • 500行制限 の中で、C言語の本質的な機能を Python で実装
  • 単一パスWebAssembly対応 など、制約下での工夫が満載
  • 構文木や最適化を省略しつつ、 実用的なCサブセット をコンパイル可能
  • 補助クラス もシンプルながら必要十分な設計

Hackerたちの意見

500行のCでPythonコンパイラを書いてみて。

バイトコードを処理するPython VMは、そんなに馬鹿げた量のCで作れるかもしれない。500行は無理だと思うけど、管理できる範囲ではあるんじゃないかな?特に古いリリースをターゲットにすれば。

多分できると思うけど、君は気に入らないだろうな。辞書はリンクリストにして、キーを探すのは線形探索になる...(C++をもらえたらstd::mapを使うけど)C標準ライブラリを使うのは許してくれるよね?もしその500行のCでstrlenやmallocを実装しなきゃならないなら、ちょっと無理かも。500行は厳しいけど、IOCCCのおかげで行数を減らすためのトリックがたくさんあるし、言語自体はそんなに大きくない。100%有効なPythonコードが与えられる前提で進めるけど、もしバグやエラーがあったらそれは未定義の動作だからね。Pythonの素晴らしさの大部分は言語そのものじゃなくてライブラリにあると思う。Pythonライブラリの大部分もCで書かれてるはずだから(速度のために)、有用なライブラリがないから、私の500行のPythonコンパイラは役に立たないだろうね。

その手の人になりたくはないけど、Pythonはインタプリタ言語だよね。とはいえ、技術的にはPythonを実行可能なファイルにコンパイルするものを作ることはできるかも?結局、ここはハッカーニュースだし。

たぶん、500行くらいのPythonicでマクロが多めのCかな。マクロのLOCがカウントされないなら、だけど。

以前: 500行のPythonでCコンパイラを書く - https://news.ycombinator.com/item?id=37383913 - 2023年9月(165件のコメント)

この記事はCコンパイラをAVR向けに自分で書けるかもって思わせるくらい分かりやすい。実際にできるかもしれないけど、簡単ではないだろうな。コンパイラの仕組みをちゃんと調べたことはなかったけど、意外と言語学と似てる部分があるね。

それは、チョムスキーが形式文法の理論を発明したときに自然言語と抽象文法の普遍性を研究していたからだよ。コンピュータ科学者たちは後に、プログラミング言語の文法構造を形式化するために同じ理論を使えることに気づいたんだ。¹https://en.wikipedia.org/wiki/Chomsky_hierarchy

「コンパイラは以前から動いていて、言語学と驚くほど似ている/関連している。」コンパイラは明確に定義された文法を持つ言語を変換するから、言語学とのつながりは意外と驚くべきことじゃないかもね。

DNA/ゲノム分析でも似たような経験があるよ。DNA分析の大部分はパーサー理論に基づいてた。この論文がDNA分析とチョムスキー階層の入門だったんだ:https://www.jstor.org/stable/29774782(無料のコピーは見つけられなかったけど)。確か、RNAの擬似ノットは文脈自由文法を必要とするんだよね。

Cのサブセットコンパイラで、たった500行くらいのC4を勉強してみるといいよ。面白いのは、自分自身をコンパイルできるところだね。: https://news.ycombinator.com/item?id=8558822

ぐるっと回ってきたね。

Hacker Newsで議論の続きを見る