SlideShare a Scribd company logo
言語処理系入門
第 10 回:コンパイラ III :コード生成,実
行時ライブラリ, GC
2010 年 1 月 8 日(金)
服部 健太
コンパイラのバックエンド
ソース
プログラム 字句・構文解析 型検査 CPS 変換
Cps.convTyping.checkparse
クロージャ変換コード生成
目的
コード
実行時
ライブラリ
中間言語
抽象構文木
GC など実行時に必要な処理
実行時にロード・リンクされる
C 言語で実装されることが多い
C 言語,アセンブリコード,
VM の中間言語(バイトコード) etc 今日のトピックス
2010/1/8 2言語処理系入門 10
クロージャ変換した後
 K ::= def x1 = E1 and … and xn = En
 | let x1 = E1 and … and xn = En in K
 | let rec x1 = E1 and … and xn = En in K
 | if V then K1 else K2
 | case V of l1 -> K1 | … | ln -> Kn
 | V (V1, … ,Vn)
 E ::= V
 |{V1;…; Vn }
 | code f (x1,…,xn) = K in E
 | V#l | V1#l <- V2
 | op(V1, … ,Vn)
 V ::= c | x∈Var
 l ∈ Nat
大域変数の定義
2010/1/8 3言語処理系入門 10
コード生成の前処理
 let rec の除去
 let 式とフィールド更新の組み合わせに変換する
[[let rec x = { …, li = x,… } in E]] ⇒
let x = { …, li = null,… }
in let _ = x#i<-x in E
 レコード生成,フィールド参照・更新をプリミティブ演算に変
換
[[{V1,…, Vn}]]  ⇒
let r = record(n) in
let _ = setfld(r,1,V1) and … _ = setfld(r,n,Vn)
in r
 code のリフトアップ
 式の中に散らばった code 定義を抜き出して集める
 残りの式は,最初に実行される code の本体となる
2010/1/8 4言語処理系入門 10
コード生成の元言語
 C ::= code f (x1,…,xn) = K
 K ::= def x1 = E1 and … and xn = En
 | let x1 = E1 and … and xn = En in K
 | if V then K1 else K2
 | case V of l1 -> K1 | … | ln -> Kn
 | V (V1, … ,Vn)
 E ::= V
 | op(V1, … ,Vn)
 V ::= c | x∈Var
 l ∈ Nat
2010/1/8 5言語処理系入門 10
末尾呼び出しの処理
 CPS では,関数呼び出しはすべて末尾呼び出し
 これをそのまま C 言語の関数呼び出しに変換すると,
いずれスタックオーバーフローとなりうまくいかない
 解決方法
 ラベルと goto 文を使う
 switch 文を使う
 ディスパッチャから関数を呼び出す( Trampoline ス
タイル)
code f(x) =
…
g(x’)
code g(y) =
…
h(y’)
code h(z) =
…
j(z’)
2010/1/8 6言語処理系入門 10
Trampoline Style
 ディスパッチャの構造
void dispatch(func_t f) {
while ((f = f()) != NULL);
}
 f は関数ポインタ
 f を呼び出すと次に実行すべき関数のポインタを
返す
void *some_func(void) {
…
return next_func;
}
2010/1/8 7言語処理系入門 10
コード生成(1)
 変換関数
 [[ ・ ]] は変換元の式 Kclosure と環境 ρ を受け取り, C 言語の
コードを出力する
 環境 ρ は,変数からその変数に割り当てられたインデック
スを返す関数
 変数,定数
 [[x]]ρ⇒
locals[ρ(x)] x DOM(ρ)∈
x otherwise
 [[n]]ρ⇒ CONST_INT(n) n∈Integer
 [[b]]ρ⇒ CONST_BOOL(b) b∈{true,false}
 プリミティブ演算子適用
 [[op(V1,…, Vn)]]ρ ⇒ op([[V1]]ρ,…,[[Vn]]ρ)
2010/1/8 8言語処理系入門 10
コード生成(2)
 def 式
 大域変数としてそのまま使用する
[[def x1 = E1 and … xn = En]]ρ ⇒
x1 = [[E1]]ρ;
…
xn = [[En]]ρ;
 let 式
 局所変数の空いてる場所に代入していく
[[let x1 = E1 and … xn = En in K]]ρ ⇒
locals[l1] = [[E1]]ρ;
…
locals[ln] = [[En]]ρ;
[[K]]ρ{x1→l1,x2→l2,…,xn→ln}
where li = ρ.size + i - 1 for each 1≦i≦n
2010/1/8 9言語処理系入門 10
コード生成(3)
 if 式
[[if V then K1 else K2]]ρ ⇒
if ([[V]]ρ == CONST_TRUE)
{ [[K1]]ρ } else { [[K2]]ρ }
 case 式
[[case V of l1 -> K1 | … | ln -> Kn]]ρ ⇒
switch (GET_LABEL([[V]]ρ)) {
case l1: { [[K1]]ρ }
…
case ln: { [[Kn]]ρ }
}
2010/1/8 10言語処理系入門 10
コード生成(4)
 関数定義
[[code f (x1,…,xn) = K]]φ ⇒
  void* f(void) {
locals[0] = args[0]; …
locals[n-1] = args[n-1];
  [[K]]{x1→0,…,xn→n-1}
}
 関数呼び出し
[[V(V1,…,Vn)]]ρ ⇒
args[0] = [[V1]]ρ; …
args[n-1] = [[Vn]]ρ;
return [[V]]ρ;
関数に与える引数を args にセット
受け取った引数を locals にセット
2010/1/8 11言語処理系入門 10
生成コードの例
#include <tfunlc.h>
obj_t __g_fact__;
static void *__t16__(void);
static void *__t23__(void);
static void *__t19__(void);
static obj_t args[] __attribute__((unused));
static obj_t locals[] __attribute__((unused));
static obj_t *globals[] __attribute__((unused));
static void *__t16__(void) {
locals[0] = args[0];
locals[1] = args[1];
locals[2] = args[2];
locals[3] = OP_GETFLD(locals[0],CONST_LBL(1));
locals[4] = OP_EQ(locals[2],CONST_INT(0));
locals[5] = OP_RECORD(CONST_LBL(2));
OP_SETFLD(locals[5],CONST_LBL(0),__t23__);
OP_SETFLD(locals[5],CONST_LBL(1),locals[1]);
if (locals[4] == CONST_TRUE) {
locals[6] = OP_GETFLD(locals[5],CONST_LBL(0));
args[0] = locals[5];
args[1] = CONST_INT(1);
return locals[6];
} else {
locals[6] = OP_SUB(locals[2],CONST_INT(1));
locals[7] = OP_RECORD(CONST_LBL(3));
OP_SETFLD(locals[7],CONST_LBL(0),__t19__);
OP_SETFLD(locals[7],CONST_LBL(1),locals[5]);
OP_SETFLD(locals[7],CONST_LBL(2),locals[2]);
locals[8] = OP_GETFLD(locals[3],CONST_LBL(0));
args[0] = locals[3];
args[1] = locals[7];
args[2] = locals[6];
return locals[8];
}
return (void*)HALT;
}
static void *__t23__(void) {
locals[0] = args[0];
locals[1] = args[1];
locals[2] = OP_GETFLD(locals[0],CONST_LBL(1));
locals[3] = OP_GETFLD(locals[2],CONST_LBL(0));
args[0] = locals[2];
args[1] = locals[1];
return locals[3];
}
static void *__t19__(void) {
locals[0] = args[0];
locals[1] = args[1];
locals[2] = OP_GETFLD(locals[0],CONST_LBL(2));
locals[3] = OP_GETFLD(locals[0],CONST_LBL(1));
locals[4] = OP_MUL(locals[2],locals[1]);
locals[5] = OP_GETFLD(locals[3],CONST_LBL(0));
args[0] = locals[3];
args[1] = locals[4];
return locals[5];
}
static void *__def_0__(void) {
locals[0] = OP_RECORD(CONST_LBL(2));
OP_SETFLD(locals[0],CONST_LBL(0),__t16__);
OP_SETFLD(locals[0],CONST_LBL(1),locals[0]);
__g_fact__ = locals[0];
return (void*)HALT;
}
int main() {
globals[0] = &__g_fact__;
gc_init(globals, 1, locals, 9);
exn_init();
if (tfl_run(__def_0__) < 0) return -1;
return 0;
}
static obj_t args[3];
static obj_t locals[9];
static obj_t *globals[1];
2010/1/8 12言語処理系入門 10
実行時ライブラリ
 以下のように,実行時に必要な定義をあらかじめ C
言語でライブラリとして実装しておく
 strcat, print_int, など一部のプリミティブ演算子の実装
 デフォルトの例外ハンドラ定義
 ディスパッチャ定義
 GC
 etc…
 生成したコードと実行時ライブラリをリンクするこ
とで実行ファイルが出来上がる.
 サンプルプログラムでは, rtlib/ の下に実行時ライ
ブラリのソースがある
2010/1/8 13言語処理系入門 10
ゴミ集め( Garbage Collection )
 使われないオブジェクトを回収する
 「使われない」の定義
 ルート集合から到達できないオブジェクト
 ルート集合={レジスタ,大域変数,スタック上の局所変数, etc }
 代表的な手法
 参照カウント
 各オブジェクトが被参照数を表すカウンタを保持
 被参照数が 0 になったら解放される
 マーク&スイープ
 ゴミ集め時にルート集合からオブジェクトを辿って,印をつけておく
 ヒープ領域をスキャンし,印のついていないオブジェクトを回収する
 コピー GC
 ヒープを 2 つの領域に分割し,片方だけ使う.
 一方の領域が満杯になったら,ルート集合からオブジェクトを辿りなが
ら,もう片方の領域にコピーしていく.
2010/1/8 14言語処理系入門 10
オブジェクト(ポインタ)の識別
方法
 GC で回収されるもの
 文字列バッファ,レコード
 GC で回収されないもの
 (ヒープに割り付けられないもの)
 整数値,真偽値, Unit
 文字列定数
 ポインタと非ポインタをどうやって識別するか?
 Exact 方式
 下位 1 ビット分をタグとして使用する
 Conservative GC
 それっぽいものはすべてポインタとみなす
ヒープ領域x: 123
truey:
z:
“hello”
w:
5 true
レジスタ等
25 “b”
2010/1/8 15言語処理系入門 10
データ表現
 基本型
 Unit,Bool,Int,etc.
 下位 1 ビット分をタグとして使用
 レコード型
 複数のデータを含むオブジェクト
 ヒープに確保される
 バッファ型
 可変文字列に使用
 ヒープに確保される
int
sz
sz “hello,worldn”
bool
2010/1/8 16言語処理系入門 10
Cheney’s Algorithm
 エレガントなコピー GC のアルゴリズム
 余分な記憶領域が不要
 free と scan の 2 つのポインタだけで OK
 処理の概要
 オブジェクトを移動先の空き領域 (free ポインタの指す先 )
にコピーし, free ポインタを先に進める
 コピー先のオブジェクトの中をスキャンし,ポインタが含
まていたら,その先のオブジェクトをチェックし, scan
ポインタを進める
 もし,まだ移動してなかったら,そのオブジェクトを移動し
,新しいポインタをセット
 すでに移動済みなら,移動先のポインタをセット
 scan ポインタが free ポインタに追いついたら終了
2010/1/8 17言語処理系入門 10
Cheney’s Algorithm の動作
A
B C
D E F G
Fromspace
Tospace
free
scan
2010/1/8 18言語処理系入門 10
Cheney’s Algorithm の動作
A’A
B C
D E F G
Fromspace
Tospace
free
scan
A’
移動先のアド
レスを入れて
おく
2010/1/8 19言語処理系入門 10
Cheney’s Algorithm の動作
A’
B’ C’
A
B C
D E F G
Fromspace
Tospace
free
scan
A’
B’ C’
2010/1/8 20言語処理系入門 10
Cheney’s Algorithm の動作
A’
B’
D’ E’
C’
F’ G’
A
B C
D E F G
Fromspace
Tospace
free
scan
A’
B’ C’ D’ E’ F’
G’
2010/1/8 21言語処理系入門 10
Cheney’s Algorithm の動作
A’
B’
D’ E’
C’
F’ G’
A
B C
D E F G
Fromspace
Tospace
free
scan
A’
B’ C’ D’ E’ F’
G’
2010/1/8 22言語処理系入門 10
Cheney’s Algorithm の実装(1)
flip() =
to_space, from_space = from_space, to_space;
heap_top = to_space + space_size;
scan = free = to_space;
foreach (r in route_set)
r = copy(r);
while (scan < free) {
sz = size(scan);
for (p = scan + 1; p < scan + sz; p++)
*p = copy(*p);
scan += sz;
}
2010/1/8 23言語処理系入門 10
Cheney’s Algorithm の実装(2)
copy(p) =
if (is_noptr(p)) return p;
if (is_forwarded(p))
return forward_address(p);
else
addr = free;
sz = size(p);
memcpy(heap_free,p,sizeof(obj_t)*sz);
free += sz;
forward_address(p) = addr;
return addr;
2010/1/8 24言語処理系入門 10
本講座で触れられなかった話題
 モジュールシステムと分割コンパイル
 トップレベルの(大域)環境を分割して扱えるように
する
 パターンマッチコンパイル
 複雑なパターンマッチ式を,単純な case 式の組み合
わせに変換する
 エスケープ解析
 変数の指し示すオブジェクトがその変数の静的スコー
プを抜けて,生存しうるかどうかを解析する
 型付き中間言語
 中間言語にも型情報を持たせることで,生成コードを
最適化しやすくなる
 その他たくさん...
2010/1/8 25言語処理系入門 10
演習課題
 今週のサンプルプログラムを動かしてみよ
 簡単なプログラムをコンパイルし,生成され
たコードを確かめよ
 以下のようなプリミティブ演算子を追加せよ
 read_line
 int_to_str, str_to_int, etc.
 文字列が適切な形式でなかったら例外を投げる
2010/1/8 26言語処理系入門 10

More Related Content

What's hot

Polyphony IO まとめ
Polyphony IO まとめPolyphony IO まとめ
Polyphony IO まとめ
ryos36
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプ
Kohsuke Yuasa
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11えぴ 福田
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性
Hibiki Yamashiro
 
Emcjp item33,34
Emcjp item33,34Emcjp item33,34
Emcjp item33,34
MITSUNARI Shigeo
 
C#勉強会
C#勉強会C#勉強会
C#勉強会
hakugakucafe
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
natrium11321
 
Functional Way
Functional WayFunctional Way
Functional Way
Kent Ohashi
 
おいしいLisp
おいしいLispおいしいLisp
おいしいLisp
Kent Ohashi
 
Tokyo.R 白熱教室「これからのRcppの話をしよう」
Tokyo.R 白熱教室「これからのRcppの話をしよう」Tokyo.R 白熱教室「これからのRcppの話をしよう」
Tokyo.R 白熱教室「これからのRcppの話をしよう」
Nagi Teramo
 
GC in C++0x
GC in C++0xGC in C++0x
GC in C++0x
yak1ex
 
C++ lecture-0
C++ lecture-0C++ lecture-0
C++ lecture-0sunaemon
 
C++入門?
C++入門?C++入門?
C++入門?
tsudaa
 
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core GuidelinesBoost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Shintarou Okada
 
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)
Yuto Takei
 
Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料
Atsuo Ishimoto
 
Emcjp item21
Emcjp item21Emcjp item21
Emcjp item21
MITSUNARI Shigeo
 
Pythonを用いた高水準ハードウェア設計環境の検討
Pythonを用いた高水準ハードウェア設計環境の検討Pythonを用いた高水準ハードウェア設計環境の検討
Pythonを用いた高水準ハードウェア設計環境の検討
Shinya Takamaeda-Y
 
Rでisomap(多様体学習のはなし)
Rでisomap(多様体学習のはなし)Rでisomap(多様体学習のはなし)
Rでisomap(多様体学習のはなし)Kohta Ishikawa
 

What's hot (20)

Polyphony IO まとめ
Polyphony IO まとめPolyphony IO まとめ
Polyphony IO まとめ
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプ
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性
 
Emcjp item33,34
Emcjp item33,34Emcjp item33,34
Emcjp item33,34
 
C#勉強会
C#勉強会C#勉強会
C#勉強会
 
C++11
C++11C++11
C++11
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
Functional Way
Functional WayFunctional Way
Functional Way
 
おいしいLisp
おいしいLispおいしいLisp
おいしいLisp
 
Tokyo.R 白熱教室「これからのRcppの話をしよう」
Tokyo.R 白熱教室「これからのRcppの話をしよう」Tokyo.R 白熱教室「これからのRcppの話をしよう」
Tokyo.R 白熱教室「これからのRcppの話をしよう」
 
GC in C++0x
GC in C++0xGC in C++0x
GC in C++0x
 
C++ lecture-0
C++ lecture-0C++ lecture-0
C++ lecture-0
 
C++入門?
C++入門?C++入門?
C++入門?
 
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core GuidelinesBoost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
 
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)
 
Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料
 
Emcjp item21
Emcjp item21Emcjp item21
Emcjp item21
 
Pythonを用いた高水準ハードウェア設計環境の検討
Pythonを用いた高水準ハードウェア設計環境の検討Pythonを用いた高水準ハードウェア設計環境の検討
Pythonを用いた高水準ハードウェア設計環境の検討
 
Rでisomap(多様体学習のはなし)
Rでisomap(多様体学習のはなし)Rでisomap(多様体学習のはなし)
Rでisomap(多様体学習のはなし)
 

Similar to 言語処理系入門€10

C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0
信之 岩永
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Spring
anyakichi
 
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
mganeko
 
C++0x総復習
C++0x総復習C++0x総復習
C++0x総復習
道化師 堂華
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
Noboru Irieda
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61
TATSUYA HAYAMIZU
 
第1回勉強会スライド
第1回勉強会スライド第1回勉強会スライド
第1回勉強会スライド
koturn 0;
 
言語処理系入門€8
言語処理系入門€8言語処理系入門€8
言語処理系入門€8
Kenta Hattori
 
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
Shin-ya Koga
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
啓 小笠原
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
信之 岩永
 
Coqでsprintf
CoqでsprintfCoqでsprintf
Coqでsprintf
Masaki Hara
 
Coqでsprintf
CoqでsprintfCoqでsprintf
Coqでsprintf
Masaki Hara
 
20130316 プログラミング言語Go
20130316 プログラミング言語Go20130316 プログラミング言語Go
20130316 プログラミング言語Go
Yoshifumi Yamaguchi
 
C# linq入門 意図編
C# linq入門 意図編C# linq入門 意図編
C# linq入門 意図編
Fujio Kojima
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 

Similar to 言語処理系入門€10 (20)

C++14 Overview
C++14 OverviewC++14 Overview
C++14 Overview
 
C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Spring
 
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
 
C++0x総復習
C++0x総復習C++0x総復習
C++0x総復習
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61
 
第1回勉強会スライド
第1回勉強会スライド第1回勉強会スライド
第1回勉強会スライド
 
言語処理系入門€8
言語処理系入門€8言語処理系入門€8
言語処理系入門€8
 
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
 
Rの高速化
Rの高速化Rの高速化
Rの高速化
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
 
Coqでsprintf
CoqでsprintfCoqでsprintf
Coqでsprintf
 
Coqでsprintf
CoqでsprintfCoqでsprintf
Coqでsprintf
 
20130316 プログラミング言語Go
20130316 プログラミング言語Go20130316 プログラミング言語Go
20130316 プログラミング言語Go
 
C# linq入門 意図編
C# linq入門 意図編C# linq入門 意図編
C# linq入門 意図編
 
Objc lambda
Objc lambdaObjc lambda
Objc lambda
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 

More from Kenta Hattori

オブジェクト指向入門2
オブジェクト指向入門2オブジェクト指向入門2
オブジェクト指向入門2
Kenta Hattori
 
オブジェクト指向入門1
オブジェクト指向入門1オブジェクト指向入門1
オブジェクト指向入門1
Kenta Hattori
 
オブジェクト指向入門10
オブジェクト指向入門10オブジェクト指向入門10
オブジェクト指向入門10
Kenta Hattori
 
オブジェクト指向入門9
オブジェクト指向入門9オブジェクト指向入門9
オブジェクト指向入門9
Kenta Hattori
 
オブジェクト指向入門8
オブジェクト指向入門8オブジェクト指向入門8
オブジェクト指向入門8
Kenta Hattori
 
オブジェクト指向入門7
オブジェクト指向入門7オブジェクト指向入門7
オブジェクト指向入門7
Kenta Hattori
 
オブジェクト指向入門6
オブジェクト指向入門6オブジェクト指向入門6
オブジェクト指向入門6
Kenta Hattori
 
オブジェクト指向入門5
オブジェクト指向入門5オブジェクト指向入門5
オブジェクト指向入門5
Kenta Hattori
 
オブジェクト指向入門4
オブジェクト指向入門4オブジェクト指向入門4
オブジェクト指向入門4
Kenta Hattori
 
オブジェクト指向入門3
オブジェクト指向入門3オブジェクト指向入門3
オブジェクト指向入門3
Kenta Hattori
 
ソフトウェア・テスト入門2
ソフトウェア・テスト入門2ソフトウェア・テスト入門2
ソフトウェア・テスト入門2
Kenta Hattori
 
ソフトウェア・テスト入門1
ソフトウェア・テスト入門1ソフトウェア・テスト入門1
ソフトウェア・テスト入門1
Kenta Hattori
 
ソフトウェア・テスト入門8
ソフトウェア・テスト入門8ソフトウェア・テスト入門8
ソフトウェア・テスト入門8
Kenta Hattori
 
ソフトウェア・テスト入門7
ソフトウェア・テスト入門7ソフトウェア・テスト入門7
ソフトウェア・テスト入門7
Kenta Hattori
 
ソフトウェア・テスト入門6
ソフトウェア・テスト入門6ソフトウェア・テスト入門6
ソフトウェア・テスト入門6
Kenta Hattori
 
ソフトウェア・テスト入門5
ソフトウェア・テスト入門5ソフトウェア・テスト入門5
ソフトウェア・テスト入門5
Kenta Hattori
 
ソフトウェア・テスト入門4
ソフトウェア・テスト入門4ソフトウェア・テスト入門4
ソフトウェア・テスト入門4
Kenta Hattori
 
ソフトウェア・テスト入門3
ソフトウェア・テスト入門3ソフトウェア・テスト入門3
ソフトウェア・テスト入門3
Kenta Hattori
 
アルゴリズムとデータ構造15
アルゴリズムとデータ構造15アルゴリズムとデータ構造15
アルゴリズムとデータ構造15
Kenta Hattori
 
アルゴリズムとデータ構造14
アルゴリズムとデータ構造14アルゴリズムとデータ構造14
アルゴリズムとデータ構造14
Kenta Hattori
 

More from Kenta Hattori (20)

オブジェクト指向入門2
オブジェクト指向入門2オブジェクト指向入門2
オブジェクト指向入門2
 
オブジェクト指向入門1
オブジェクト指向入門1オブジェクト指向入門1
オブジェクト指向入門1
 
オブジェクト指向入門10
オブジェクト指向入門10オブジェクト指向入門10
オブジェクト指向入門10
 
オブジェクト指向入門9
オブジェクト指向入門9オブジェクト指向入門9
オブジェクト指向入門9
 
オブジェクト指向入門8
オブジェクト指向入門8オブジェクト指向入門8
オブジェクト指向入門8
 
オブジェクト指向入門7
オブジェクト指向入門7オブジェクト指向入門7
オブジェクト指向入門7
 
オブジェクト指向入門6
オブジェクト指向入門6オブジェクト指向入門6
オブジェクト指向入門6
 
オブジェクト指向入門5
オブジェクト指向入門5オブジェクト指向入門5
オブジェクト指向入門5
 
オブジェクト指向入門4
オブジェクト指向入門4オブジェクト指向入門4
オブジェクト指向入門4
 
オブジェクト指向入門3
オブジェクト指向入門3オブジェクト指向入門3
オブジェクト指向入門3
 
ソフトウェア・テスト入門2
ソフトウェア・テスト入門2ソフトウェア・テスト入門2
ソフトウェア・テスト入門2
 
ソフトウェア・テスト入門1
ソフトウェア・テスト入門1ソフトウェア・テスト入門1
ソフトウェア・テスト入門1
 
ソフトウェア・テスト入門8
ソフトウェア・テスト入門8ソフトウェア・テスト入門8
ソフトウェア・テスト入門8
 
ソフトウェア・テスト入門7
ソフトウェア・テスト入門7ソフトウェア・テスト入門7
ソフトウェア・テスト入門7
 
ソフトウェア・テスト入門6
ソフトウェア・テスト入門6ソフトウェア・テスト入門6
ソフトウェア・テスト入門6
 
ソフトウェア・テスト入門5
ソフトウェア・テスト入門5ソフトウェア・テスト入門5
ソフトウェア・テスト入門5
 
ソフトウェア・テスト入門4
ソフトウェア・テスト入門4ソフトウェア・テスト入門4
ソフトウェア・テスト入門4
 
ソフトウェア・テスト入門3
ソフトウェア・テスト入門3ソフトウェア・テスト入門3
ソフトウェア・テスト入門3
 
アルゴリズムとデータ構造15
アルゴリズムとデータ構造15アルゴリズムとデータ構造15
アルゴリズムとデータ構造15
 
アルゴリズムとデータ構造14
アルゴリズムとデータ構造14アルゴリズムとデータ構造14
アルゴリズムとデータ構造14
 

Recently uploaded

RaySheet Product Description Documentation - 2024.6.19
RaySheet Product Description Documentation - 2024.6.19RaySheet Product Description Documentation - 2024.6.19
RaySheet Product Description Documentation - 2024.6.19
GrapeCity, inc.
 
Bhyve Management Daemon Version 3.0 on FreBSD
Bhyve Management Daemon Version 3.0 on FreBSDBhyve Management Daemon Version 3.0 on FreBSD
Bhyve Management Daemon Version 3.0 on FreBSD
Yuichiro Naito
 
シグネチャで始めるRustプログラミング - Superteam Japan Developer Event
シグネチャで始めるRustプログラミング - Superteam Japan Developer Eventシグネチャで始めるRustプログラミング - Superteam Japan Developer Event
シグネチャで始めるRustプログラミング - Superteam Japan Developer Event
K Kinzal
 
RayBarcode Product Description Documentation - 2024.6.19
RayBarcode Product Description Documentation - 2024.6.19RayBarcode Product Description Documentation - 2024.6.19
RayBarcode Product Description Documentation - 2024.6.19
GrapeCity, inc.
 
クラウドネイティブにおけるセキュアなソフトウェア・サプライ・チェーンの考え方とベストプラクティス.pdf
クラウドネイティブにおけるセキュアなソフトウェア・サプライ・チェーンの考え方とベストプラクティス.pdfクラウドネイティブにおけるセキュアなソフトウェア・サプライ・チェーンの考え方とベストプラクティス.pdf
クラウドネイティブにおけるセキュアなソフトウェア・サプライ・チェーンの考え方とベストプラクティス.pdf
TatsuyaHanayama
 
RayPen Product Description Documentation - 2024.6.19
RayPen Product Description Documentation - 2024.6.19RayPen Product Description Documentation - 2024.6.19
RayPen Product Description Documentation - 2024.6.19
GrapeCity, inc.
 
Solanaで始めるRustプログラミング - Superteam Japan Developer Event
Solanaで始めるRustプログラミング - Superteam Japan Developer EventSolanaで始めるRustプログラミング - Superteam Japan Developer Event
Solanaで始めるRustプログラミング - Superteam Japan Developer Event
K Kinzal
 
RaySheetで解決できるシナリオ10選-業務改善に貢献する機能 - RaySheet Documentation
RaySheetで解決できるシナリオ10選-業務改善に貢献する機能 - RaySheet DocumentationRaySheetで解決できるシナリオ10選-業務改善に貢献する機能 - RaySheet Documentation
RaySheetで解決できるシナリオ10選-業務改善に貢献する機能 - RaySheet Documentation
GrapeCity, inc.
 

Recently uploaded (8)

RaySheet Product Description Documentation - 2024.6.19
RaySheet Product Description Documentation - 2024.6.19RaySheet Product Description Documentation - 2024.6.19
RaySheet Product Description Documentation - 2024.6.19
 
Bhyve Management Daemon Version 3.0 on FreBSD
Bhyve Management Daemon Version 3.0 on FreBSDBhyve Management Daemon Version 3.0 on FreBSD
Bhyve Management Daemon Version 3.0 on FreBSD
 
シグネチャで始めるRustプログラミング - Superteam Japan Developer Event
シグネチャで始めるRustプログラミング - Superteam Japan Developer Eventシグネチャで始めるRustプログラミング - Superteam Japan Developer Event
シグネチャで始めるRustプログラミング - Superteam Japan Developer Event
 
RayBarcode Product Description Documentation - 2024.6.19
RayBarcode Product Description Documentation - 2024.6.19RayBarcode Product Description Documentation - 2024.6.19
RayBarcode Product Description Documentation - 2024.6.19
 
クラウドネイティブにおけるセキュアなソフトウェア・サプライ・チェーンの考え方とベストプラクティス.pdf
クラウドネイティブにおけるセキュアなソフトウェア・サプライ・チェーンの考え方とベストプラクティス.pdfクラウドネイティブにおけるセキュアなソフトウェア・サプライ・チェーンの考え方とベストプラクティス.pdf
クラウドネイティブにおけるセキュアなソフトウェア・サプライ・チェーンの考え方とベストプラクティス.pdf
 
RayPen Product Description Documentation - 2024.6.19
RayPen Product Description Documentation - 2024.6.19RayPen Product Description Documentation - 2024.6.19
RayPen Product Description Documentation - 2024.6.19
 
Solanaで始めるRustプログラミング - Superteam Japan Developer Event
Solanaで始めるRustプログラミング - Superteam Japan Developer EventSolanaで始めるRustプログラミング - Superteam Japan Developer Event
Solanaで始めるRustプログラミング - Superteam Japan Developer Event
 
RaySheetで解決できるシナリオ10選-業務改善に貢献する機能 - RaySheet Documentation
RaySheetで解決できるシナリオ10選-業務改善に貢献する機能 - RaySheet DocumentationRaySheetで解決できるシナリオ10選-業務改善に貢献する機能 - RaySheet Documentation
RaySheetで解決できるシナリオ10選-業務改善に貢献する機能 - RaySheet Documentation
 

言語処理系入門€10

  • 1. 言語処理系入門 第 10 回:コンパイラ III :コード生成,実 行時ライブラリ, GC 2010 年 1 月 8 日(金) 服部 健太
  • 2. コンパイラのバックエンド ソース プログラム 字句・構文解析 型検査 CPS 変換 Cps.convTyping.checkparse クロージャ変換コード生成 目的 コード 実行時 ライブラリ 中間言語 抽象構文木 GC など実行時に必要な処理 実行時にロード・リンクされる C 言語で実装されることが多い C 言語,アセンブリコード, VM の中間言語(バイトコード) etc 今日のトピックス 2010/1/8 2言語処理系入門 10
  • 3. クロージャ変換した後  K ::= def x1 = E1 and … and xn = En  | let x1 = E1 and … and xn = En in K  | let rec x1 = E1 and … and xn = En in K  | if V then K1 else K2  | case V of l1 -> K1 | … | ln -> Kn  | V (V1, … ,Vn)  E ::= V  |{V1;…; Vn }  | code f (x1,…,xn) = K in E  | V#l | V1#l <- V2  | op(V1, … ,Vn)  V ::= c | x∈Var  l ∈ Nat 大域変数の定義 2010/1/8 3言語処理系入門 10
  • 4. コード生成の前処理  let rec の除去  let 式とフィールド更新の組み合わせに変換する [[let rec x = { …, li = x,… } in E]] ⇒ let x = { …, li = null,… } in let _ = x#i<-x in E  レコード生成,フィールド参照・更新をプリミティブ演算に変 換 [[{V1,…, Vn}]]  ⇒ let r = record(n) in let _ = setfld(r,1,V1) and … _ = setfld(r,n,Vn) in r  code のリフトアップ  式の中に散らばった code 定義を抜き出して集める  残りの式は,最初に実行される code の本体となる 2010/1/8 4言語処理系入門 10
  • 5. コード生成の元言語  C ::= code f (x1,…,xn) = K  K ::= def x1 = E1 and … and xn = En  | let x1 = E1 and … and xn = En in K  | if V then K1 else K2  | case V of l1 -> K1 | … | ln -> Kn  | V (V1, … ,Vn)  E ::= V  | op(V1, … ,Vn)  V ::= c | x∈Var  l ∈ Nat 2010/1/8 5言語処理系入門 10
  • 6. 末尾呼び出しの処理  CPS では,関数呼び出しはすべて末尾呼び出し  これをそのまま C 言語の関数呼び出しに変換すると, いずれスタックオーバーフローとなりうまくいかない  解決方法  ラベルと goto 文を使う  switch 文を使う  ディスパッチャから関数を呼び出す( Trampoline ス タイル) code f(x) = … g(x’) code g(y) = … h(y’) code h(z) = … j(z’) 2010/1/8 6言語処理系入門 10
  • 7. Trampoline Style  ディスパッチャの構造 void dispatch(func_t f) { while ((f = f()) != NULL); }  f は関数ポインタ  f を呼び出すと次に実行すべき関数のポインタを 返す void *some_func(void) { … return next_func; } 2010/1/8 7言語処理系入門 10
  • 8. コード生成(1)  変換関数  [[ ・ ]] は変換元の式 Kclosure と環境 ρ を受け取り, C 言語の コードを出力する  環境 ρ は,変数からその変数に割り当てられたインデック スを返す関数  変数,定数  [[x]]ρ⇒ locals[ρ(x)] x DOM(ρ)∈ x otherwise  [[n]]ρ⇒ CONST_INT(n) n∈Integer  [[b]]ρ⇒ CONST_BOOL(b) b∈{true,false}  プリミティブ演算子適用  [[op(V1,…, Vn)]]ρ ⇒ op([[V1]]ρ,…,[[Vn]]ρ) 2010/1/8 8言語処理系入門 10
  • 9. コード生成(2)  def 式  大域変数としてそのまま使用する [[def x1 = E1 and … xn = En]]ρ ⇒ x1 = [[E1]]ρ; … xn = [[En]]ρ;  let 式  局所変数の空いてる場所に代入していく [[let x1 = E1 and … xn = En in K]]ρ ⇒ locals[l1] = [[E1]]ρ; … locals[ln] = [[En]]ρ; [[K]]ρ{x1→l1,x2→l2,…,xn→ln} where li = ρ.size + i - 1 for each 1≦i≦n 2010/1/8 9言語処理系入門 10
  • 10. コード生成(3)  if 式 [[if V then K1 else K2]]ρ ⇒ if ([[V]]ρ == CONST_TRUE) { [[K1]]ρ } else { [[K2]]ρ }  case 式 [[case V of l1 -> K1 | … | ln -> Kn]]ρ ⇒ switch (GET_LABEL([[V]]ρ)) { case l1: { [[K1]]ρ } … case ln: { [[Kn]]ρ } } 2010/1/8 10言語処理系入門 10
  • 11. コード生成(4)  関数定義 [[code f (x1,…,xn) = K]]φ ⇒   void* f(void) { locals[0] = args[0]; … locals[n-1] = args[n-1];   [[K]]{x1→0,…,xn→n-1} }  関数呼び出し [[V(V1,…,Vn)]]ρ ⇒ args[0] = [[V1]]ρ; … args[n-1] = [[Vn]]ρ; return [[V]]ρ; 関数に与える引数を args にセット 受け取った引数を locals にセット 2010/1/8 11言語処理系入門 10
  • 12. 生成コードの例 #include <tfunlc.h> obj_t __g_fact__; static void *__t16__(void); static void *__t23__(void); static void *__t19__(void); static obj_t args[] __attribute__((unused)); static obj_t locals[] __attribute__((unused)); static obj_t *globals[] __attribute__((unused)); static void *__t16__(void) { locals[0] = args[0]; locals[1] = args[1]; locals[2] = args[2]; locals[3] = OP_GETFLD(locals[0],CONST_LBL(1)); locals[4] = OP_EQ(locals[2],CONST_INT(0)); locals[5] = OP_RECORD(CONST_LBL(2)); OP_SETFLD(locals[5],CONST_LBL(0),__t23__); OP_SETFLD(locals[5],CONST_LBL(1),locals[1]); if (locals[4] == CONST_TRUE) { locals[6] = OP_GETFLD(locals[5],CONST_LBL(0)); args[0] = locals[5]; args[1] = CONST_INT(1); return locals[6]; } else { locals[6] = OP_SUB(locals[2],CONST_INT(1)); locals[7] = OP_RECORD(CONST_LBL(3)); OP_SETFLD(locals[7],CONST_LBL(0),__t19__); OP_SETFLD(locals[7],CONST_LBL(1),locals[5]); OP_SETFLD(locals[7],CONST_LBL(2),locals[2]); locals[8] = OP_GETFLD(locals[3],CONST_LBL(0)); args[0] = locals[3]; args[1] = locals[7]; args[2] = locals[6]; return locals[8]; } return (void*)HALT; } static void *__t23__(void) { locals[0] = args[0]; locals[1] = args[1]; locals[2] = OP_GETFLD(locals[0],CONST_LBL(1)); locals[3] = OP_GETFLD(locals[2],CONST_LBL(0)); args[0] = locals[2]; args[1] = locals[1]; return locals[3]; } static void *__t19__(void) { locals[0] = args[0]; locals[1] = args[1]; locals[2] = OP_GETFLD(locals[0],CONST_LBL(2)); locals[3] = OP_GETFLD(locals[0],CONST_LBL(1)); locals[4] = OP_MUL(locals[2],locals[1]); locals[5] = OP_GETFLD(locals[3],CONST_LBL(0)); args[0] = locals[3]; args[1] = locals[4]; return locals[5]; } static void *__def_0__(void) { locals[0] = OP_RECORD(CONST_LBL(2)); OP_SETFLD(locals[0],CONST_LBL(0),__t16__); OP_SETFLD(locals[0],CONST_LBL(1),locals[0]); __g_fact__ = locals[0]; return (void*)HALT; } int main() { globals[0] = &__g_fact__; gc_init(globals, 1, locals, 9); exn_init(); if (tfl_run(__def_0__) < 0) return -1; return 0; } static obj_t args[3]; static obj_t locals[9]; static obj_t *globals[1]; 2010/1/8 12言語処理系入門 10
  • 13. 実行時ライブラリ  以下のように,実行時に必要な定義をあらかじめ C 言語でライブラリとして実装しておく  strcat, print_int, など一部のプリミティブ演算子の実装  デフォルトの例外ハンドラ定義  ディスパッチャ定義  GC  etc…  生成したコードと実行時ライブラリをリンクするこ とで実行ファイルが出来上がる.  サンプルプログラムでは, rtlib/ の下に実行時ライ ブラリのソースがある 2010/1/8 13言語処理系入門 10
  • 14. ゴミ集め( Garbage Collection )  使われないオブジェクトを回収する  「使われない」の定義  ルート集合から到達できないオブジェクト  ルート集合={レジスタ,大域変数,スタック上の局所変数, etc }  代表的な手法  参照カウント  各オブジェクトが被参照数を表すカウンタを保持  被参照数が 0 になったら解放される  マーク&スイープ  ゴミ集め時にルート集合からオブジェクトを辿って,印をつけておく  ヒープ領域をスキャンし,印のついていないオブジェクトを回収する  コピー GC  ヒープを 2 つの領域に分割し,片方だけ使う.  一方の領域が満杯になったら,ルート集合からオブジェクトを辿りなが ら,もう片方の領域にコピーしていく. 2010/1/8 14言語処理系入門 10
  • 15. オブジェクト(ポインタ)の識別 方法  GC で回収されるもの  文字列バッファ,レコード  GC で回収されないもの  (ヒープに割り付けられないもの)  整数値,真偽値, Unit  文字列定数  ポインタと非ポインタをどうやって識別するか?  Exact 方式  下位 1 ビット分をタグとして使用する  Conservative GC  それっぽいものはすべてポインタとみなす ヒープ領域x: 123 truey: z: “hello” w: 5 true レジスタ等 25 “b” 2010/1/8 15言語処理系入門 10
  • 16. データ表現  基本型  Unit,Bool,Int,etc.  下位 1 ビット分をタグとして使用  レコード型  複数のデータを含むオブジェクト  ヒープに確保される  バッファ型  可変文字列に使用  ヒープに確保される int sz sz “hello,worldn” bool 2010/1/8 16言語処理系入門 10
  • 17. Cheney’s Algorithm  エレガントなコピー GC のアルゴリズム  余分な記憶領域が不要  free と scan の 2 つのポインタだけで OK  処理の概要  オブジェクトを移動先の空き領域 (free ポインタの指す先 ) にコピーし, free ポインタを先に進める  コピー先のオブジェクトの中をスキャンし,ポインタが含 まていたら,その先のオブジェクトをチェックし, scan ポインタを進める  もし,まだ移動してなかったら,そのオブジェクトを移動し ,新しいポインタをセット  すでに移動済みなら,移動先のポインタをセット  scan ポインタが free ポインタに追いついたら終了 2010/1/8 17言語処理系入門 10
  • 18. Cheney’s Algorithm の動作 A B C D E F G Fromspace Tospace free scan 2010/1/8 18言語処理系入門 10
  • 19. Cheney’s Algorithm の動作 A’A B C D E F G Fromspace Tospace free scan A’ 移動先のアド レスを入れて おく 2010/1/8 19言語処理系入門 10
  • 20. Cheney’s Algorithm の動作 A’ B’ C’ A B C D E F G Fromspace Tospace free scan A’ B’ C’ 2010/1/8 20言語処理系入門 10
  • 21. Cheney’s Algorithm の動作 A’ B’ D’ E’ C’ F’ G’ A B C D E F G Fromspace Tospace free scan A’ B’ C’ D’ E’ F’ G’ 2010/1/8 21言語処理系入門 10
  • 22. Cheney’s Algorithm の動作 A’ B’ D’ E’ C’ F’ G’ A B C D E F G Fromspace Tospace free scan A’ B’ C’ D’ E’ F’ G’ 2010/1/8 22言語処理系入門 10
  • 23. Cheney’s Algorithm の実装(1) flip() = to_space, from_space = from_space, to_space; heap_top = to_space + space_size; scan = free = to_space; foreach (r in route_set) r = copy(r); while (scan < free) { sz = size(scan); for (p = scan + 1; p < scan + sz; p++) *p = copy(*p); scan += sz; } 2010/1/8 23言語処理系入門 10
  • 24. Cheney’s Algorithm の実装(2) copy(p) = if (is_noptr(p)) return p; if (is_forwarded(p)) return forward_address(p); else addr = free; sz = size(p); memcpy(heap_free,p,sizeof(obj_t)*sz); free += sz; forward_address(p) = addr; return addr; 2010/1/8 24言語処理系入門 10
  • 25. 本講座で触れられなかった話題  モジュールシステムと分割コンパイル  トップレベルの(大域)環境を分割して扱えるように する  パターンマッチコンパイル  複雑なパターンマッチ式を,単純な case 式の組み合 わせに変換する  エスケープ解析  変数の指し示すオブジェクトがその変数の静的スコー プを抜けて,生存しうるかどうかを解析する  型付き中間言語  中間言語にも型情報を持たせることで,生成コードを 最適化しやすくなる  その他たくさん... 2010/1/8 25言語処理系入門 10
  • 26. 演習課題  今週のサンプルプログラムを動かしてみよ  簡単なプログラムをコンパイルし,生成され たコードを確かめよ  以下のようなプリミティブ演算子を追加せよ  read_line  int_to_str, str_to_int, etc.  文字列が適切な形式でなかったら例外を投げる 2010/1/8 26言語処理系入門 10