Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
1
オレオレ言語 soramame の紹介
松永 大輝
2
自己紹介
●
松永 大輝 (@matsu1834)
●
京都工芸繊維大学 1年生
●
滋賀から来ました
●
カーネルVM 初参加
1000km
3
soramame言語について
●
3月〜6月頃にかけて開発
●
開発言語はC++
●
Windows ・ Ubuntu・Debianで動作確認
●
名前について
– 昔、作ったソフトに野菜の名前をつけていたから
– 春に開発したから
4
特徴
●
仮想機械で実行
●
手続き型言語
●
再代入可能
●
静的型付き(型推論)
●
基本型(int, double, bool, string)
●
リスト、タプル、構造体
●
ユーザ定義演算子
●
クロージャ
●
継続
●
並行実行...
5
プログラム例(1)
//クロージャのテスト
fun make_adder()=> fun()=>int{
var n=0
return fun(){
n=n+1; return n;
}
}
fun main(){
var a=make_a...
6
プログラム例(2)
//並行実行・チャンネル通信のテスト
fun main(){
var c=newchannel(int,2)
async fun(){
sleep(1000)
print(“hellon”) ; c ! 1;
}()
a...
7
プログラム例(3)
/* リサージュ曲線  */
fun main(){
    glut_openwindow("Lissajous")
    glut_setdisplayfunc(fun(){
        glut_clear(...
8
プログラム例(4)
//継続で脱出
fun main(){
var x=callcc(c,int){
return product([1,2,3,0,6,7],c)
}
print_int(x)
}
fun product(lst:[int...
9
字句構造(1)
●
コメント
– // 行末までコメント
– /* … */ 複数行コメント 入れ子にできる
●
識別子
– 英数字・アンダースコアの並び(先頭は数字不可)
– 大文字小文字は区別される
●
キーワード
var fun ne...
10
字句構造(2)
●
リテラル
– 整数リテラル
●
10進表記のみ
– 浮動小数点数リテラル
– 文字リテラル
●
シングルクオーテーションで1文字を囲んだもの
●
整数(ASCIIコード値)として扱われる
– 文字列リテラル
●
ダブル...
11
式(1)
バイトコード欄にて...
– <>で囲われたものは、それを計算してスタックに置く命令列である
– ()で囲われたものは即値
●
整数リテラル
– ex: 758
– バイトコード:
ipush , (数値)
-1〜5の場合は専用...
12
式(2)
●
文字列リテラル
– ex: “hello,world”
– バイトコード:
ldc, (コンスタントプール番号...コンパイル時に決定)
●
識別子
– ex: x _data Aichi
– バイトコード:
loadloc...
13
式(3)
●
クロージャリテラル
– fun(arg1,arg2,...argn)=>type { ... }
– バイトコード:
makeclosure, (コンスタントプールの番号...コンパイル時に決まる)
●
call/cc式
–...
14
式(4)
●
構造体リテラル
– ex: Point{x=10, y=50}
– バイトコード:
<exprn>, (fieldnのコンスタントプール番号), …, <expr1>, (field1のコンスタン
トプール番号), make...
15
式(5)
●
構造体メンバ参照式
– ex: b.size
– バイトコード:
<structure>, loadfield, (フィールド文字列のコンスタントプール番号)
●
単項演算式
– ex: b! -6
– バイトコード:
専用...
16
式(4)
●
構造体リテラル
– ex: Point{x=10, y=50}
– バイトコード:
<exprn>, (fieldnのコンスタントプール番号), …, <expr1>, (field1のコンスタン
トプール番号), make...
17
文(1)
●
プログラムは文の集合
●
文の終端
– 改行またはセミコロン
– ' } ' の手前の文は、改行・セミコロンが省略できる
●
変数宣言文
– var a:int, b=true
– カンマで区切って複数の変数を一度に宣言でき...
18
文(2)
●
関数定義文
– トップレベルにのみ記述できる
– fun name(arg1,arg2,…,argn)=>type{ … }
– 戻り値の型を省略した場合、void型となる
●
演算子定義文
– トップレベルにのみ記述できる...
19
文(3)
●
式文
●
return文
– return [式];
– バイトコード:
<式>, ret_withvalue (戻り値有りの場合) | ret (戻り値無しの場合)
●
async文
– async [関数呼び出し式];
...
20
型(1)
●
整数型: int
– C++のint相当
●
浮動小数点数型: double
– C++のdouble相当
●
論理型: bool
– C++のbool相当
●
文字列型: string
– 内部でC++のstringを利用...
21
型(2)
●
タプル型: ( t1, t2, …, tn)
– 内部でC++のlistを利用
– リストと同じように要素の参照、書き換えが可能
– アクセス時の添字は定数である必要がある(型を決定するため)
●
構造体型
– 内部でC++...
22
組み込み関数(1)
●
数学
– int rand()
– int abs()
– double sin(double)
– double cos(double)
– double tan(double)
– double asin(do...
23
組み込み関数(2)
●
出力
– void print(string)
– void print_int(int)
– void print_double(double)
– void print_bool(bool)
●
並列
– in...
24
組み込み関数(3)
●
グラフィックス - OpenGL(GLUT)を利用。簡単な2Dグラフィックス、マウス・キーボードイベントが使える。
– void glut_mainloop()
– void glut_clear()
– void...
25
優先順位 演算子 結合性
70
-(単項: 符号反転)!(単項: 論理否定 )
?(単項: チャンネル受信)
@?(単項: リスト長)@>(単項: cdr)@<(単項: car)
右結合
40 *(2項)/(2項)%(2項)
左結合
20...
26
演算子の定義
●
演算子:  %$#=~|^+-*/<>&!?@ の1〜6文字の並び
●
単項演算子は1引数、二項演算子は2引数の関数
fun [演算子] [単項/二項],[結合規則],[優先順位](引数リスト)=>[戻り値の型]{
}
...
27
パーサ
●
ファイル単位でパース
●
自作LRパーサ
(BNFを配列の形でソースコード内に記述)
●
式のパースを、ユーザ定義演算子のために
あとから行う
28
コンパイラ
●
構文木を生成し、型検査を行い、コード生成
●
定数畳み込み
●
関数のアドレス・double値などは
定数領域(コンスタントプール)へ登録
●
関数定義・グローバル変数には型を書かせる
●
ローカル変数の型を省略した場合、...
29
コードジェネレータ
●
末尾呼び出し・asyncのコード生成
– 呼び出しのバイトコード(invoke)の後ろに
即値で印をつけておく
– 実行時にそれを見て、末尾呼び出しだと分かれば
不要なものを記憶しない。asyncなら、新たにス
レ...
30
仮想機械
●
スタックマシン
●
mallocでヒープ領域にスタックフレームなどを確保
●
スタックフレームは連結リストになっている
– スタックフレームは以下の要素で構成される
●
変数領域
●
プログラム・カウンタ
●
オペランドスタ...

ローカル変数領域
x=100 :大域環境

オペランドスタック

プログラム・カウンタ

関数へのポインタ
関数:
main
関数:f
スコープ・ルール
(ヒープ領域)
var x:int=100
fun main(){
var x=...
32
並行実行・並列実行
●
C++のスレッドライブラリ(std::thread)
を使用
●
そのためマルチコア対応
並列実行
●
構文:
async func(arg1, arg2, …, argn)
33
並行実行・並列実行
/* asyncにより別スレッドで動いている関数から
   main関数で作った継続を評価 */
fun main(){
var cont:continuation(int)
var x= 1 + callcc(c,i...
34
チャンネル通信
●
std::threadのcondition_variable(条件変数)を利用し、
スレッドの中断・再開を実装
●
チャンネルは双方向
●
チャンネルはFIFOバッファを持つ(有限サイズ・チャンネル生
成時に0以上で指...
35
チャンネル通信
var chan = newchannel( int , 1 ) //チャンネルオブジェクト生成
chan ! 3    //チャンネルへ 数値 3 を送信
var a = chan?    //チャンネルから受信
pus...
36
デモ
●
async・チャンネル通信(プログラム例2)
●
リサージュ曲線(プログラム例3)
●
継続(プログラム例4)
●
クイックソート・ユーザ定義演算子・filter・map
●
スリープソート
●
15パズル
●
マンデルブロ集合
37
参考文献
●
LLVMによるプログラミング言語の実装(日本語訳)
http://peta.okechan.net/blog/
●
文法と言語-自由文脈文法とLR構文解析-
http://vrl.sys.wakayama-u.ac.jp/S...
38
御清聴ありがとうございました
39
文法定義 BNF(1)
<eol> ::= ";" | "n" | <EMPTY>
<S> ::= <program>
<program> ::= <EMPTY>
| <program> <functiondef>
| <program>...
40
文法定義 BNF(2)
<functiondef> ::= 
  "fun" <IDENT> "(" <param_list> ")" [ <op_n> <type> ] "{" <block> "}"
  | "fun"  <op_n>...
41
文法定義 BNF(3)
<expression> ::= { <primary> | <operator_n> | <parenexpr> }+
<intvalexpr> ::= <INTVAL>
<doublevalexpr> ::= ...
42
文法定義 BNF(4)
<variableexpr> ::= <IDENTIFIER>
<parenexpr> ::= "(" <expression> ")"
<closureexpr> ::= "fun" "(" <parameter...
43
文法定義 BNF(5)
<datadef> ::= "data" <IDENTIFIER> "{" <datamember_list> "}"
<datamember_list> ::= <EMPTY>
| <datamember_lis...
44
文法定義 BNF(6)
<block> ::= <statement_list>
<statement_list> ::= <EMPTY>
| <statement_list> <statement>
| <statement_list>...
45
機械語一覧(スタック)
名前 引数 説明 スタックの変化
ipush value 整数値プッシュ [ ] → [ int ]
bpush value 論理値プッシュ [ ] → [ bool ]
pushnull nullプッシュ [ ]...
46
機械語一覧(算術演算・論理演算)
名前 引数 説明 スタックの変化
iadd 整数足し算 [ int , int ] → [ int ]
dadd 実数足し算 [ double , double ] → [ double ]
isub 整...
47
機械語一覧(呼び出し・変数)
名前 引数 説明 スタックの変化
invoke
is_tail, 
is_async
呼び出し
[ closure/continuation ,
arg1 , arg2, … , argn ]
→ [ ]
l...
48
機械語一覧(復帰・変数)
名前 引数 説明 スタックの変化
ret リターン [ ] → [ ]
ret_withvalue
スタックトップの値を
戻り先のオペランドスタックにプッシュし、
リターン
[ value ] →
[ 戻り先: ...
49
機械語一覧(クロージャ生成・ジャンプ)
名前 引数 説明
スタックの
変化
makeclosure number
コンスタントプール:numberにある関数情報と
現在のスタックフレームから
クロージャオブジェクトを生成、プッシュ
[ ]...
50
機械語一覧(比較演算)
名前 引数 説明 スタックの変化
icmpeq == (int) [ int , int ] → [ bool ]
icmpne != (int) [ int , int ] → [ bool ]
icmplt <...
51
機械語一覧(リスト・構造体・継続)
名前 引数 説明 スタックの変化
makelist len
スタックからlen個だけ
値を取ってきて
リストオブジェクトを生成、
プッシュ
[ value1 , value2 ,
… , valuen ...
52
機械語一覧(チャンネル通信・スタック)
名前 引数 説明 スタックの変化
makechannel
指定のバッファ容量のチャンネル
オブジェクトを生成しスタックへ
プッシュ
[ int ] → [ channel ]
channel_sen...
Upcoming SlideShare
Loading in …5
×

オレオレ言語soramame

1,960 views

Published on

第1回カーネルVM名古屋での発表資料
ソースコード:https://github.com/matsud224/soramame

Published in: Software
  • Be the first to comment

オレオレ言語soramame

  1. 1. 1 オレオレ言語 soramame の紹介 松永 大輝
  2. 2. 2 自己紹介 ● 松永 大輝 (@matsu1834) ● 京都工芸繊維大学 1年生 ● 滋賀から来ました ● カーネルVM 初参加 1000km
  3. 3. 3 soramame言語について ● 3月〜6月頃にかけて開発 ● 開発言語はC++ ● Windows ・ Ubuntu・Debianで動作確認 ● 名前について – 昔、作ったソフトに野菜の名前をつけていたから – 春に開発したから
  4. 4. 4 特徴 ● 仮想機械で実行 ● 手続き型言語 ● 再代入可能 ● 静的型付き(型推論) ● 基本型(int, double, bool, string) ● リスト、タプル、構造体 ● ユーザ定義演算子 ● クロージャ ● 継続 ● 並行実行・並列実行 ● チャンネル通信
  5. 5. 5 プログラム例(1) //クロージャのテスト fun make_adder()=> fun()=>int{ var n=0 return fun(){ n=n+1; return n; } } fun main(){ var a=make_adder() var b=make_adder() print_int(a()) print_int(b()) print_int(a()) print_int(b()) } 出力: 1122
  6. 6. 6 プログラム例(2) //並行実行・チャンネル通信のテスト fun main(){ var c=newchannel(int,2) async fun(){ sleep(1000) print(“hellon”) ; c ! 1; }() async fun(){ sleep(2000) print(“world!n”) ; c ! 2; }() c?; c?; } 出力: (1秒待つ) hello (もう1秒待つ) world!
  7. 7. 7 プログラム例(3) /* リサージュ曲線  */ fun main(){     glut_openwindow("Lissajous")     glut_setdisplayfunc(fun(){         glut_clear()         glut_begin_point()         var a=4.0,b=3.0,t=0.0         while(t<1000.0){             glut_color3i(255,0,0)             glut_vertex2i(d2i(sin(a*t)*50.0)+100,                         d2i(cos(b*t)*50.0)+100)             t=t+1.0         }         glut_end()         glut_flush()   })   glut_mainloop() }
  8. 8. 8 プログラム例(4) //継続で脱出 fun main(){ var x=callcc(c,int){ return product([1,2,3,0,6,7],c) } print_int(x) } fun product(lst:[int],cont:continuation(int))=>int { if(@?lst==0){ return 1 } if(@<lst==0){ cont(0) }else{ return @<lst * product(@>lst,cont) } } 出力: 0
  9. 9. 9 字句構造(1) ● コメント – // 行末までコメント – /* … */ 複数行コメント 入れ子にできる ● 識別子 – 英数字・アンダースコアの並び(先頭は数字不可) – 大文字小文字は区別される ● キーワード var fun newchannel channel if while  else return true false data group  continuation callcc async
  10. 10. 10 字句構造(2) ● リテラル – 整数リテラル ● 10進表記のみ – 浮動小数点数リテラル – 文字リテラル ● シングルクオーテーションで1文字を囲んだもの ● 整数(ASCIIコード値)として扱われる – 文字列リテラル ● ダブルクオーテーションで文字列を囲んだもの ● 以下のエスケープシーケンスを使用可 – 改行(n)、円記号()、水平タブ(t)、垂直タブ(v)、バックスペース(b)、シングルクオーテーション(')、 ダブルクオーテーション(")、ベル文字(a) – 真偽値リテラル ● true / false ● 演算子 ● 以下の文字の1〜6文字の並び – %$#=~|^+-*/<>&!?@
  11. 11. 11 式(1) バイトコード欄にて... – <>で囲われたものは、それを計算してスタックに置く命令列である – ()で囲われたものは即値 ● 整数リテラル – ex: 758 – バイトコード: ipush , (数値) -1〜5の場合は専用の命令有り ● 浮動小数点数リテラル – ex: 1.4142 – バイトコード: ldc, (コンスタントプール番号...コンパイル時に決定) ● 文字リテラル – ex: 'A' ● 真偽値リテラル – ex: true – バイトコード: bpush, (0/1)
  12. 12. 12 式(2) ● 文字列リテラル – ex: “hello,world” – バイトコード: ldc, (コンスタントプール番号...コンパイル時に決定) ● 識別子 – ex: x _data Aichi – バイトコード: loadlocal, x, y ( x はスタックフレームを遡る回数、y は変数領域の番号、 x, y はコンパイル時に決定) ● 呼び出し式 – callee( arg1 , arg2, … , argn) – バイトコード: <arg1>, <arg2>, …, <argn>, invoke, x, 0 末尾呼び出しならばxは1、違えば0
  13. 13. 13 式(3) ● クロージャリテラル – fun(arg1,arg2,...argn)=>type { ... } – バイトコード: makeclosure, (コンスタントプールの番号...コンパイル時に決まる) ● call/cc式 – callcc(varname, type){ … } – typeは式自身の型 – typeは省略可(void型となる) – バイトコード: makecontinuation, makeclosure, (コンスタントプールの番号), invoke, 0, 0 ● リストリテラル – ex: [ 1, 2, 3, 4, 5 ] – バイトコード: <itemn>, …, <item2>, <item1>, (リストの長さ:n), makelist ● タプルリテラル – ex: (“nagoya”, false, 758) – バイトコード: リストと同じ
  14. 14. 14 式(4) ● 構造体リテラル – ex: Point{x=10, y=50} – バイトコード: <exprn>, (fieldnのコンスタントプール番号), …, <expr1>, (field1のコンスタン トプール番号), makedata, (構造体名のコンスタントプール番号), (メンバ数: n) ● newchannel式 – newchannel( type , capacity ) – capacityはバッファのサイズで0以上の整数で指定 – バイトコード: <capacity> , makechannel ● リスト/タプル添字式 – ex: a[3] – バイトコード: <list>, <index>, loadbyindex
  15. 15. 15 式(5) ● 構造体メンバ参照式 – ex: b.size – バイトコード: <structure>, loadfield, (フィールド文字列のコンスタントプール番号) ● 単項演算式 – ex: b! -6 – バイトコード: 専用の命令があればそれが使用される。 ユーザ定義演算子であれば、1引数関数の呼び出しとなる。 ● 二項演算子 – ex: 1+1 3*6 – バイトコード: 専用の命令があればそれが使用される。 ユーザ定義演算子であれば、2引数関数の呼び出しとなる。 ● 丸括弧で囲まれた式 – ( 123 + 456 )
  16. 16. 16 式(4) ● 構造体リテラル – ex: Point{x=10, y=50} – バイトコード: <exprn>, (fieldnのコンスタントプール番号), …, <expr1>, (field1のコンスタン トプール番号), makedata, (構造体名のコンスタントプール番号), (メンバ数: n) ● newchannel式 – newchannel( type , capacity ) – capacityはバッファのサイズで0以上の整数で指定 – バイトコード: <capacity> , makechannel ● リスト/タプル添字式 – ex: a[3] – バイトコード: <list>, <index>, loadbyindex
  17. 17. 17 文(1) ● プログラムは文の集合 ● 文の終端 – 改行またはセミコロン – ' } ' の手前の文は、改行・セミコロンが省略できる ● 変数宣言文 – var a:int, b=true – カンマで区切って複数の変数を一度に宣言できる – コロンの後に型を記述 ● 省略する場合は、続いて初期化が必要 ● 初期化する式で型推論が行われる ● トップレベルでの変数宣言の場合は、型の記述が必須 ● 再帰が行われる無名関数を代入する場合も、型の記述が必須 ● 構造体宣言文 – data Point{ x: int y: int } – トップレベルにのみ記述できる
  18. 18. 18 文(2) ● 関数定義文 – トップレベルにのみ記述できる – fun name(arg1,arg2,…,argn)=>type{ … } – 戻り値の型を省略した場合、void型となる ● 演算子定義文 – トップレベルにのみ記述できる – fun op optype , assoc , pred (...)=>type{ … } – opは演算子 – optypeはunary又はbinary – assocはleft又はright – predは優先順位 – 1・2引数関数の定義である (実際に、関数と同じ領域に登録され、 ユーザ定義演算子を使用すると関数呼び出しのコードが吐かれる)
  19. 19. 19 文(3) ● 式文 ● return文 – return [式]; – バイトコード: <式>, ret_withvalue (戻り値有りの場合) | ret (戻り値無しの場合) ● async文 – async [関数呼び出し式]; – バイトコード: <arg1>, <arg2>, …, <argn>, invoke, 0, 1 ● if文 – if(cond){ … then_clause … }else{ … else_clause ... } – else節は省略可 – バイトコード: <cond>, iffalse_skip, (then_clauseの長さ +2), <then_clause>, skip, (else_clauseの長さ), <else_clause> ● while文 – while(cond){ … clause ... } – バイトコード: <cond>, iffalse_skip, (clauseの長さ +2), <clause>, back, (clauseの長さ +3)
  20. 20. 20 型(1) ● 整数型: int – C++のint相当 ● 浮動小数点数型: double – C++のdouble相当 ● 論理型: bool – C++のbool相当 ● 文字列型: string – 内部でC++のstringを利用 ● リスト型: [ t ] – 内部でC++のlistを利用 – 範囲外アクセスを行うとランタイムエラーになる
  21. 21. 21 型(2) ● タプル型: ( t1, t2, …, tn) – 内部でC++のlistを利用 – リストと同じように要素の参照、書き換えが可能 – アクセス時の添字は定数である必要がある(型を決定するため) ● 構造体型 – 内部でC++のmapを利用 ● 関数型: fun( args )=>t ● 継続型: continuation( t ) ● チャンネル型: channel( t ) ● int/double/boolは値型。ほかは参照型。
  22. 22. 22 組み込み関数(1) ● 数学 – int rand() – int abs() – double sin(double) – double cos(double) – double tan(double) – double asin(double) – double acos(double) – double atan(double) – double sqrt(double) – int pow(int,int) ● 型変換 – double i2d(int) //int→doubleの型変換 – int d2i(double) //double→intの型変換
  23. 23. 23 組み込み関数(2) ● 出力 – void print(string) – void print_int(int) – void print_double(double) – void print_bool(bool) ● 並列 – int hardware_concurrency() //論理コア数を取得 – void sleep(int) //指定時間(ミリ秒単位)待つ
  24. 24. 24 組み込み関数(3) ● グラフィックス - OpenGL(GLUT)を利用。簡単な2Dグラフィックス、マウス・キーボードイベントが使える。 – void glut_mainloop() – void glut_clear() – void glut_flush() – void glut_begin_point() – void glut_begin_line() – void glut_begin_strip() – void glut_begin_lineloop() – void glut_begin_triangle() – void glut_begin_quad() – void glut_begin_trianglefan() – void glut_begin_polygon() – void glut_end() – void glut_postredisp() – void glut_setkeyboardfunc(fun(int,int,int)=>void) – void glut_setmousefunc(fun(int,int,int,int)=>void) – void glut_openwindow(string) //タイトルを指定 – void glut_vertex2i(int,int) – void glut_color3i(int,int,int) //RGBをそれぞれ0~255の範囲で指定 – void glut_char(int)
  25. 25. 25 優先順位 演算子 結合性 70 -(単項: 符号反転)!(単項: 論理否定 ) ?(単項: チャンネル受信) @?(単項: リスト長)@>(単項: cdr)@<(単項: car) 右結合 40 *(2項)/(2項)%(2項) 左結合 20 +(2項)-(2項) @+(2項: リスト連結) 10 <<(2項)>>(2項) 8 >(2項)>=(2項)<(2項)<=(2項)!=(2項)==(2項) 5 &&(2項)||(2項) 2 !(2項: チャンネル送信) =(2項: 代入) 右結合 演算子
  26. 26. 26 演算子の定義 ● 演算子:  %$#=~|^+-*/<>&!?@ の1〜6文字の並び ● 単項演算子は1引数、二項演算子は2引数の関数 fun [演算子] [単項/二項],[結合規則],[優先順位](引数リスト)=>[戻り値の型]{ } //累乗 fun ^ binary,right,50(x:int,y:int)=>int{ return pow(x,y) } //関数合成 fun $ binary,right,60(f:fun(int)=>int,g:fun(int)=>int)=>fun(int)=>int{ return fun(x:int){ return f(g(x)) } }
  27. 27. 27 パーサ ● ファイル単位でパース ● 自作LRパーサ (BNFを配列の形でソースコード内に記述) ● 式のパースを、ユーザ定義演算子のために あとから行う
  28. 28. 28 コンパイラ ● 構文木を生成し、型検査を行い、コード生成 ● 定数畳み込み ● 関数のアドレス・double値などは 定数領域(コンスタントプール)へ登録 ● 関数定義・グローバル変数には型を書かせる ● ローカル変数の型を省略した場合、初期値から型推論
  29. 29. 29 コードジェネレータ ● 末尾呼び出し・asyncのコード生成 – 呼び出しのバイトコード(invoke)の後ろに 即値で印をつけておく – 実行時にそれを見て、末尾呼び出しだと分かれば 不要なものを記憶しない。asyncなら、新たにス レッドを生成。
  30. 30. 30 仮想機械 ● スタックマシン ● mallocでヒープ領域にスタックフレームなどを確保 ● スタックフレームは連結リストになっている – スタックフレームは以下の要素で構成される ● 変数領域 ● プログラム・カウンタ ● オペランドスタック ● 関数へのポインタ ● 呼び出し元のスタックフレームを指すポインタ ● 自分を生成した関数のスタックフレームを指すポインタ – 継続は、生成時にスタックフレームをコピーする方法で実現 ● C++のスマートポインタ(shared_ptr)で参照カウンタ方式のガベージコ レクション(循環参照は回収されない)
  31. 31.  ローカル変数領域 x=100 :大域環境  オペランドスタック  プログラム・カウンタ  関数へのポインタ 関数: main 関数:f スコープ・ルール (ヒープ領域) var x:int=100 fun main(){ var x=999 //ここではx=999 f() if(x>100){ var x=3 //ここではx=3 } //ここではx=999 } fun f(){ print_int(x) //ここではx=100 } 自身を生成した関数の スタックフレームを指すポインタ 呼び出し元を指すポインタ スタックフレーム x1 =999, x2 =3
  32. 32. 32 並行実行・並列実行 ● C++のスレッドライブラリ(std::thread) を使用 ● そのためマルチコア対応 並列実行 ● 構文: async func(arg1, arg2, …, argn)
  33. 33. 33 並行実行・並列実行 /* asyncにより別スレッドで動いている関数から    main関数で作った継続を評価 */ fun main(){ var cont:continuation(int) var x= 1 + callcc(c,int){ cont=c return 3 } print_int(x) if(x==4){ async f1(cont) sleep(1000) } } fun f1(c:continuation(int)){ c(5) } 出力: 4 6
  34. 34. 34 チャンネル通信 ● std::threadのcondition_variable(条件変数)を利用し、 スレッドの中断・再開を実装 ● チャンネルは双方向 ● チャンネルはFIFOバッファを持つ(有限サイズ・チャンネル生 成時に0以上で指定) ● 送信時にバッファがいっぱいだったらブロックされる ● 受信時に受け取る値がなければブロックされる ● 構文: newchannel ( type , capacity ) //チャンネル生成 chan ! value //チャンネルへ送信 chan? //チャンネルから受信
  35. 35. 35 チャンネル通信 var chan = newchannel( int , 1 ) //チャンネルオブジェクト生成 chan ! 3    //チャンネルへ 数値 3 を送信 var a = chan?    //チャンネルから受信 pushi1 数値1をプッシュ makechannel チャンネルオブジェクトをスタックにプッシュ storelocal00 ローカル変数0にスタックトップの値をセット pushi3 数値 3 をプッシュ loadlocal00 ローカル変数0の値をプッシュ channel_send スタックトップのチャンネルに値送信 loadlocal00 ローカル変数0の値をプッシュ channel_receive チャンネルから受信し、プッシュ storelocal01 ローカル変数1にスタックトップの値をセット ソ ー ス 生 成 さ れ る バ イ ト コ ー ド
  36. 36. 36 デモ ● async・チャンネル通信(プログラム例2) ● リサージュ曲線(プログラム例3) ● 継続(プログラム例4) ● クイックソート・ユーザ定義演算子・filter・map ● スリープソート ● 15パズル ● マンデルブロ集合
  37. 37. 37 参考文献 ● LLVMによるプログラミング言語の実装(日本語訳) http://peta.okechan.net/blog/ ● 文法と言語-自由文脈文法とLR構文解析- http://vrl.sys.wakayama-u.ac.jp/SS/ ● Scheme演習 http://www-ui.is.s.u-tokyo.ac.jp/~hara2001/scheme ● Javaアセンブラ「Jasmin」でバイトコードの世界を覗いてみよう hakkaku.net ● 数理科学的バグ撲滅方法論のすすめ itpro.nikkeibp.co.jp
  38. 38. 38 御清聴ありがとうございました
  39. 39. 39 文法定義 BNF(1) <eol> ::= ";" | "n" | <EMPTY> <S> ::= <program> <program> ::= <EMPTY> | <program> <functiondef> | <program> "var" <variabledef_list> <eol> <type> ::= <IDENTIFIER> | "fun" "(" <type_list> ")" <operator_n> <type> | "[" <type> "]" | "(" <type_list> ")" | "continuation" "(" <type> ")" | "channel" "(" <type> ")" <type_list> ::= <EMPTY> | <type> { "," <type> }
  40. 40. 40 文法定義 BNF(2) <functiondef> ::=    "fun" <IDENT> "(" <param_list> ")" [ <op_n> <type> ] "{" <block> "}"   | "fun"  <op_n>   <IDENT> "," <IDENT> "," <INTVAL> "(" <parameter_list> ")"  [ <operator_n> <type> ] "{" <block> "}" <parameter_list> ::= <EMPTY> | <parameter_list> { "," <parameter> } <parameter> ::= <IDENTIFIER> ":" <type> <variabledef_list> ::= <variabledef> | <variabledef_list> "," <variabledef> <variabledef> ::= <IDENTIFIER> ":" <type> | <IDENTIFIER> [ ":" <type> ] <operator_n> <expression>
  41. 41. 41 文法定義 BNF(3) <expression> ::= { <primary> | <operator_n> | <parenexpr> }+ <intvalexpr> ::= <INTVAL> <doublevalexpr> ::= <DOUBLEVAL> <boolvalexpr> ::= <BOOLVAL> <stringvalexpr> ::= <STRINGVAL> <operator_n> ::= <OPERATOR> <funcallexpr> ::= ( <primary> | <parenexpr> ) "(" <arg_list> ")" <primary> ::= <intvalexpr> | <doublevalexpr> | <boolvalexpr> | <stringvalexpr> | <funcallexpr> | <closureexpr> | <callccexpr>  | <variableexpr> | <listvalexpr> | <tuplevalexpr> | <dataexpr> | <newobjexpr> | <listrefexpr> | <datamemberrefexpr>
  42. 42. 42 文法定義 BNF(4) <variableexpr> ::= <IDENTIFIER> <parenexpr> ::= "(" <expression> ")" <closureexpr> ::= "fun" "(" <parameter_list> ")"  [ <operator_n> <type> ] "{" <block> "}" <callccexpr> ::= "callcc" "(" <IDENTIFIER> [ "," <type> ]  “)" "{" <block> "}" <arg_list> ::= <EMPTY> | <expression> { "," <expression> } <tuple_list> ::=  ( <expression> | <tuple_list> )  ","   <expression> <listvalexpr> ::= "[" <arg_list> "]" <tuplevalexpr> ::= "(" <tuple_list> ")"
  43. 43. 43 文法定義 BNF(5) <datadef> ::= "data" <IDENTIFIER> "{" <datamember_list> "}" <datamember_list> ::= <EMPTY> | <datamember_list> <IDENTIFIER> ":" <type> <eol>  <dataexpr> ::= <IDENTIFIER> "{" <initassign_list> "}" <initassign_list> ::= <EMPTY> | <IDENTIFIER> <operator_n> <expression> | <initassign_list> "," <IDENTIFIER> <operator_n>  <expression> <listrefexpr> ::= ( <primary> | <parenexpr> ) "[" <expression>  "]" <datamemberrefexpr> ::= ( <primary> | <parenexpr> ) "."           <IDENTIFIER> <newchanexpr> ::= "newchannel" "(" <type> “,” <expression> ")" | "newchannel" "(" <type> ")"
  44. 44. 44 文法定義 BNF(6) <block> ::= <statement_list> <statement_list> ::= <EMPTY> | <statement_list> <statement> | <statement_list> "var" <variabledef_list> <eol> <statement> ::= <expression> <eol>  | <returnstatement> <eol> | <asyncstatement> <eol> | <ifstatement> | <whilestatement> <whilestatement> ::= "while" "(" <expression> ")" "{" <block> "}" <asyncstatement> ::= "async" <expression> <ifstatement> ::= "if" "(" <expression> ")" "{" <block> "}"    [ "else" "{" <block> "}" ] <returnstatement> ::= "return" [ <expression> ]
  45. 45. 45 機械語一覧(スタック) 名前 引数 説明 スタックの変化 ipush value 整数値プッシュ [ ] → [ int ] bpush value 論理値プッシュ [ ] → [ bool ] pushnull nullプッシュ [ ] → [ ref(null) ] pushim1 定数(-1)プッシュ [ ] → [ int ] pushi0 定数(0)プッシュ [ ] → [ int ] pushi1 定数(1)プッシュ [ ] → [ int ] pushi2 定数(2)プッシュ [ ] → [ int ] pushi3 定数(3)プッシュ [ ] → [ int ] pushi4 定数(4)プッシュ [ ] → [ int ] pushi5 定数(5)プッシュ [ ] → [ int ] ldc number コンスタントプールの指定番号 のアイテムをプッシュ [ ] → [ value ]
  46. 46. 46 機械語一覧(算術演算・論理演算) 名前 引数 説明 スタックの変化 iadd 整数足し算 [ int , int ] → [ int ] dadd 実数足し算 [ double , double ] → [ double ] isub 整数引き算 [ int , int ] → [ int ] dsub 実数引き算 [ double , double ] → [ double ] imul 整数掛け算 [ int , int ] → [ int ] dmul 実数掛け算 [ double , double ] → [ double ] idiv 整数割り算 [ int , int ] → [ int ] ddiv 実数割り算 [ double , double ] → [ double ] band 論理積 [ bool , bool ] → [ bool ] bor 論理和 [ bool , bool ] → [ bool ] imod 余り [ int , int ] → [ int ] ineg 整数・符号反転 [ int ] → [ int ] bnot 否定 [ bool ] → [ bool ] dneg 実数・符号反転 [ double ] → [ double ] ilshift 左シフト [ int , int ] → [ int ]
  47. 47. 47 機械語一覧(呼び出し・変数) 名前 引数 説明 スタックの変化 invoke is_tail,  is_async 呼び出し [ closure/continuation , arg1 , arg2, … , argn ] → [ ] loadlocal flame, index 指定位置のローカル変数の値を プッシュ [ ] → [ value ] loadbyindex リストの指定されたインデックス の値をプッシュ [ int , list ] → [ value ] loadfield name スタックトップの構造体の フィールドnameの値をプッシュ [ structure ] → [ value ] loadlocal00 現在のスタックフレームの変数領 域の0番目の値をプッシュ [ ] → [ value ] ・・・ loadlocal05 現在のスタックフレームの変数領 域の5番目の値をプッシュ [ ] → [ value ]
  48. 48. 48 機械語一覧(復帰・変数) 名前 引数 説明 スタックの変化 ret リターン [ ] → [ ] ret_withvalue スタックトップの値を 戻り先のオペランドスタックにプッシュし、 リターン [ value ] → [ 戻り先: value ] storelocal flame, index 指定された変数領域の値を スタックトップの値にする [ value ] → [ ] storefield name スタックトップの構造体の フィールドnameの値を変更 [ structure , value ] → [ ] storebyindex リストの、 指定されたインデックスの値を変更 [ int , list , value ] → [ ] storelocal00 現在のフレームの0番目の変数領域の値を スタックトップの値にする [ value ] → [ ] ・・・ storelocal05 現在のフレームの5番目の変数領域の値を スタックトップの値にする [ value ] → [ ]
  49. 49. 49 機械語一覧(クロージャ生成・ジャンプ) 名前 引数 説明 スタックの 変化 makeclosure number コンスタントプール:numberにある関数情報と 現在のスタックフレームから クロージャオブジェクトを生成、プッシュ [ ] → [ closure ] skip distance distanceをプログラム・カウンタへ加算 [ ] → [ ] iffalse_skip distance スタックトップがfalseの時distanceを プログラム・カウンタへ加算 [ bool ] → [ ] back distance distanceだけをプログラム・カウンタから減算 [ ] → [ ]
  50. 50. 50 機械語一覧(比較演算) 名前 引数 説明 スタックの変化 icmpeq == (int) [ int , int ] → [ bool ] icmpne != (int) [ int , int ] → [ bool ] icmplt < (int) [ int , int ] → [ bool ] icmple <= (int) [ int , int ] → [ bool ] icmpgt > (int) [ int , int ] → [ bool ] icmpge >= (int) [ int , int ] → [ bool ] dcmpeq == (double) [ double , double ] → [ bool ] dcmpne != (double) [ double , double ] → [ bool ] dcmplt < (double) [ double , double ] → [ bool ] dcmple <= (double) [ double , double ] → [ bool ] dcmpgt > (double) [ double , double ] → [ bool ] dcmpge >= (double) [ double , double ] → [ bool ] bcmpeq == (bool) [ bool , bool ] → [ bool ] bcmpne != (bool) [ bool , bool ] → [ bool ]
  51. 51. 51 機械語一覧(リスト・構造体・継続) 名前 引数 説明 スタックの変化 makelist len スタックからlen個だけ 値を取ってきて リストオブジェクトを生成、 プッシュ [ value1 , value2 , … , valuen ] → [ list ] makedata name, len メンバの数がlenの構造体を 生成 [ name1 , value1 , … , namen , valuen ] → [ structure ] makecontinuation 継続をスタックへプッシュ [ ] → [ continuation ] resume_continuation スタックトップの継続を 呼び出す [ continuation ] → [ ]
  52. 52. 52 機械語一覧(チャンネル通信・スタック) 名前 引数 説明 スタックの変化 makechannel 指定のバッファ容量のチャンネル オブジェクトを生成しスタックへ プッシュ [ int ] → [ channel ] channel_send スタックトップのチャンネルへ 送信 [ channel , value ] → [ ] channel_receive スタックトップのチャンネルから 受信 [ channel ] → [ value ] dup スタックトップの値を複製 [ value ] → [ value , value ] clean オペランドスタックを空にする [ …… ] → [ ]

×