本プロジェクトは以下のモジュールで構成されています:
lexer.rs- 字句解析器.ソースコードをトークン列に変換token.rs- トークン定義.キーワード,演算子,識別子などのトークン型を定義ast.rs- 構文解析器.トークン列を解析してASTを生成ast/decl.rs- 変数・関数・型の宣言をパースast/expr.rs- 式(演算子,関数呼び出しなど)をパースast/stmt.rs- 文(if, while, returnなど)をパース
node.rs- ASTノードの定義と型推論node/kind.rs- ノードの種類(変数,二項演算,関数呼び出しなど)node/operator.rs- 演算子の定義(単項演算子,二項演算子)
decl.rs- 宣言情報.Decl(変数・関数宣言)とMemberDecl(構造体メンバ宣言)を定義types.rs- 型システム.int, char, ポインタ, 配列, 構造体などの型を管理types/kind.rs- 型の種類を定義types/spec.rs- 型指定子と修飾子(const, staticなど)を管理types/table.rs- グローバル型テーブル.型をIDで管理し重複を防止types/type_ref.rs- 型参照(TypeRef).型テーブルへの軽量な参照
func.rs- 関数定義の管理.パラメータ,ローカル変数,スタックサイズを扱うsymbol.rs- シンボル定義.変数・関数・列挙定数の情報を保持symbol/table.rs- スコープ付きシンボルテーブル.名前解決とスコープ管理
x86.rs- x86-64アセンブリコード生成器x86/expr.rs- 式のコード生成x86/stmt.rs- 文のコード生成x86/reg.rs- レジスタ管理
asm_builder.rs- アセンブリコードのビルダー.生成したアセンブリを文字列に整形し、簡易な最適化を実装
main.rs- エントリーポイント.コマンドライン引数(-d/--debug,-o/--optimize,-i/--input,-f/--file)を解析し,コンパイルパイプラインを実行utils.rs- ユーティリティ.Span(ソースコード位置情報)とAlignUp(アライメント計算)を定義errors.rs- エラー定義とエラーメッセージのフォーマット.ソースコード位置情報を含む詳細なエラー表示
ソースコード
↓
[Lexer] 字句解析
↓
トークン列
↓
[AST] 構文解析 + 意味解析
↓
抽象構文木(型チェック済み)
↓
[Generator] コード生成
↓
[AsmBuilder] 最適化(オプション)
↓
x86-64アセンブリ
コード内で一貫して使用している略語の一覧です.C言語の文法用語に基づいています.
| 略語 | 正式名称 | 意味 |
|---|---|---|
decl |
declaration | 宣言(変数宣言,関数宣言など) |
spec |
specifier | 指定子(型指定子,ストレージクラス指定子など) |
qual |
qualifier | 修飾子(const,volatileなど) |
param |
parameter | パラメータ,引数 |
func |
function | 関数 |
ptr |
pointer | ポインタ |
abst |
abstract | 抽象(abstract declarator) |
expr |
expression | 式 |
stmt |
statement | 文 |
注意: declarator,initializerは文法上重要な概念のため省略していません.
- 基本的なデータ型(
int,char,short,long,float,double,void) - ポインタ型
- 配列(1次元、多次元)
- 構造体(
struct) - 自己参照構造体(リンクリスト、二分木など)
- 構造体の前方宣言
- 入れ子構造体
- グローバル型テーブルによる型の統一管理
-
union型 -
enum型 -
typedef(型エイリアス) - 型キャスト(明示的な型変換)
-
unsigned型の完全なサポート -
long long型
- 算術演算子(
+,-,*,/,%) - ビット演算子(
&,|,^,~,<<,>>) - 比較演算子(
==,!=,<,<=,>,>=)※ポインタとNULL(0)の比較も対応 - 論理演算子(
&&,||,!) - 代入演算子(
=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=) - インクリメント/デクリメント(
++,--)前置・後置 - 三項演算子(
? :) -
sizeof演算子 - アドレス演算子(
&)と参照外し演算子(*) - アロー演算子(
->)とドット演算子(.)※連鎖的なアロー演算子も対応 - 配列添字演算子(
[]) - カンマ演算子(
,) - 浮動小数点数の演算
- 変数宣言と初期化
- 関数定義
- 関数呼び出し
- 配列初期化子(1次元)
- ポインタ配列の初期化
- サイズ省略配列の初期化(
int a[] = {...}) - グローバル変数
- グローバル変数の初期化
- 型修飾子の構文解析(
const,volatile,restrict) - ストレージクラス指定子の構文解析(
auto,extern,register,static,typedef) - 関数指定子の構文解析(
inline) - 可変長引数(
...)の構文解析 - 関数プロトタイプ宣言のシンボルテーブル登録
- 多次元配列の初期化子(
int a[2][3] = {{1,2,3}, {4,5,6}}) - 構造体の初期化子(
struct Point p = {1, 2}) - 初期化子の末尾カンマ対応(
int a[] = {1, 2, 3,}) - 抽象宣言子(abstract declarator)
- 型修飾子の意味解析と実装(
const,volatile,restrict) - ストレージクラス指定子の実装(
static,externの完全なサポート) - 関数指定子の実装(
inline) - 代入時の型チェックの強化
- グローバル変数の定数式評価
-
if文、else文 -
while文 -
for文 -
do-while文 -
break文、continue文 -
return文 -
goto文とラベル -
switch文 -
case文、default文
- ブロックスコープ
- ローカル変数
- グローバル変数
- 文字列リテラル
- 数値リテラル(10進数、8進数、16進数)
- 文字列リテラルの連結(
"Hello" "World")
- 構造体のメンバアクセス
- 構造体のメンバオフセット計算
- 構造体の値渡し・値返し
- 標準ライブラリ関数のサポート(現状は外部関数を呼び出す機能のみ)
-
#include -
#define -
#ifdef,#ifndef,#endif -
#if,#elif,#else - マクロ展開
- 条件付きコンパイル
- 最適化(冗長なpush/pop命令の削除、
--optimizeフラグで有効化) - ソースコード位置情報付きエラーメッセージ
- 警告メッセージ
- エラーメッセージの更なる改善
- Intel記法とAT&T記法でのレジスタのsrc,dstの違いに注意.
- スタックはLIFOであることに注意.特に関数呼び出し.
- レジスタのバイト数によってレジスタの名称が異なるので注意.
- 32ビットのレジスタを呼び出した場合のみ上位が0クリアされることに注意.
- 関数呼び出しは,ABIに基づいた16バイトアラインメントが必要.
- 関数が呼び出された後にスタックポインタを下げて領域を確保する際に16の倍数にしておくと,16バイトアラインメントが維持される.
- なるべくpushでスタックに結果を一時退避させるのではなく,レジスタに直接飛ばす.スタックリークの発生要因になり得る.
- 加算・減算にはポインタの計算が含まれることに注意.
- ASTの作成と同時に意味解析をやるので,BNF通りにパースすることが難しい場合がある.あまりBNFにこだわらないこと.
- BNFが左再帰の場合は無限ループに陥らないよう関数に工夫が必要.
- トークナイザは比較的実装が容易なので,インクリメンタルに開発するのではなく最初から全部作っても大丈夫そう.
- 型はグローバルテーブルで一元管理し,TypeRefでID参照することで重複を防ぐ.
- 自己参照構造体は,構造体定義開始時に不完全型として登録し,メンバパース後に完全型に更新することで実現.
- 入れ子構造体は再帰下降パーサーの関数スタックフレームによって自然に処理される.
- Rustの場合,連結リストを作ると記述が冗長になるので,Vecで代用できる部分はなるべくVecで代用する.
- 最初から網羅的に実装しようとすると破綻する.諦めが肝心.
- デバッグモード(
--debug)でシンボルテーブルや関数情報を確認できる. - 最適化(
--optimize)はデフォルトで有効.無効化する場合は--optimize=falseを指定. - 冗長なpush/pop命令は最適化で自動削除される.
gdb ./bin/tmp
(gdb) b 11 # アセンブリ上の確認したい行を指定し,ブレイクポイントを打つ
(gdb) run # ブレイクポイントまで実行
(gdb) info registers # レジスタの状態を確認