Upgrade to Pro — share decks privately, control downloads, hide ads and more …

オレオレ言語 soramame の紹介

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

オレオレ言語 soramame の紹介

Avatar for Daiki Matsunaga

Daiki Matsunaga

August 16, 2015
Tweet

More Decks by Daiki Matsunaga

Other Decks in Programming

Transcript

  1. 特徴 • 仮想機械で実行 • 手続き型言語 • 再代入可能 • 静的型付き(型推論) •

    基本型(int, double, bool, string) • リスト、タプル、構造体 • ユーザ定義演算子 • クロージャ • 継続 • 並行実行・並列実行 • チャンネル通信
  2. プログラム例(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
  3. プログラム例(2) //並行実行・チャンネル通信のテスト fun main(){ var c=new(channel(int)) async fun(){ sleep(1000) print(“hello\n”)

    ; c ! 1; }() async fun(){ sleep(2000) print(“world!\n”) ; c ! 2; }() c?; c?; } 出力: (1秒待つ) hello (もう1秒待つ) world!
  4. プログラム例(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() }
  5. 仮想機械 • スタックマシン • mallocでヒープ領域にスタックフレームなどを確保 • スタックフレームは連結リストになっている – 呼び出し元のスタックフレームを指す DynamicLink

    と、自分を 生成した関数のスタックフレームを指す StaticLink を持つ – 継続は、生成時にスタックフレームをコピーする方法で実現 • C++のスマートポインタ(shared_ptr)で参照カウンタ方式の ガベージコレクション(循環参照は回収されない)
  6.  ローカル変数領域|x=100  オペランドスタック  プログラム・カウンタ  関数へのポインタ 関数: main

    x=999 関数:f 仮想機械 (ヒープ領域) 大域環境 var x:int = 100 fun main(){ var x=999 //ここではx=999 f() } fun f(){ print_int(x) //ここではx=100 } StaticLink DynamicLink
  7. 並行実行・並列実行 • C++のスレッドライブラリ(std::thread) を使用 • そのためマルチコア対応 並列実行 • 構文: async

    func(arg1, arg2, …, argn) <argn> …… <arg2> <arg1> <func> invoke 0 1 生成されるバイトコード
  8. チャンネル通信 var chan = new( channel( int ) ) //チャンネルオブジェクト生成

    chan ! 3    //チャンネルへ値 3 を送信 var a = chan?    //チャンネルから受信 makechannel チャンネルオブジェクトをスタックにプッシュ storelocal00 ローカル変数0にスタックトップの値をセット pushi3 整数 3 をプッシュ loadlocal00 ローカル変数0の値をプッシュ channel_send スタックトップのチャンネルに値送信 loadlocal00 ローカル変数0の値をプッシュ channel_receive チャンネルから受信し、プッシュ storelocal01 ローカル変数1にスタックトップの値をセット ソ ー ス 生 成 さ れ る バ イ ト コ ー ド
  9. 機械語一覧(スタック) 名前 引数 説明 スタックの変化 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 ]
  10. 機械語一覧(算術演算・論理演算) 名前 引数 説明 スタックの変化 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 ]
  11. 機械語一覧(呼び出し・変数) 名前 引数 説明 スタックの変化 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 ]
  12. 機械語一覧(復帰・変数) 名前 引数 説明 スタックの変化 ret リターン [ ] →

    [ ] ret_withvalue スタックトップの値を 戻り先のオペランドスタックにプッシュし、 リターン [ value ] → [ 戻り先: value ] storelocal flame, index 指定された変数領域の値を スタックトップの値にする [ value ] → [ ] storefield name スタックトップの構造体の フィールドnameの値を変更 [ structure , value ] → [ ] storebyindex リストの、 指定されたインデックスの値を変更 [ int , list , value ] → [ ] storelocal00 現在のフレームの0番目の変数領域の値を スタックトップの値にする [ value ] → [ ] ・・・ storelocal05 現在のフレームの5番目の変数領域の値を スタックトップの値にする [ value ] → [ ]
  13. 機械語一覧(クロージャ生成・ジャンプ) 名前 引数 説明 スタックの 変化 makeclosure number コンスタントプール:numberにある関数情報と 現在のスタックフレームから

    クロージャオブジェクトを生成、プッシュ [ ] → [ closure ] skip distance distanceをプログラム・カウンタへ加算 [ ] → [ ] iffalse_skip distance スタックトップがfalseの時distanceを プログラム・カウンタへ加算 [ bool ] → [ ] back distance distanceだけをプログラム・カウンタから減算 [ ] → [ ]
  14. 機械語一覧(比較演算) 名前 引数 説明 スタックの変化 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 ]
  15. 機械語一覧(リスト・構造体・継続) 名前 引数 説明 スタックの変化 makelist len スタックからlen個だけ 値を取ってきて リストオブジェクトを生成、

    プッシュ [ value1 , value2 , … , valuen ] → [ list ] makedata name, len メンバの数がlenの構造体を 生成 [ name1 , value1 , … , namen , valuen ] → [ structure ] makecontinuation 継続をスタックへプッシュ [ ] → [ continuation ] resume_continuation スタックトップの継続を 呼び出す [ continuation ] → [ ]
  16. 機械語一覧(チャンネル通信・スタック) 名前 引数 説明 スタックの変化 makechannel チャンネルオブジェクトを生成し スタックへプッシュ [ ]

    → [ channel ] channel_send スタックトップのチャンネルへ 送信 [ channel , value ] → [ ] channel_receive スタックトップのチャンネルから 受信 [ channel ] → [ value ] dup スタックトップの値を複製 [ value ] → [ value , value ] clean オペランドスタックを空にする [ …… ] → [ ]
  17. 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> }
  18. 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>
  19. 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>
  20. 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> ")"
  21. 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> <newobjexpr> ::= "new" "(" <type> ")"
  22. 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> ]
  23. 字句構造(1) • コメント – // 行末までコメント – /* … */

    複数行コメント 入れ子にできる • 識別子 – 英数字・アンダースコアの並び(先頭は数字不可) – 大文字小文字は区別される • キーワード var fun new channel if while else return true false data group continuation callcc async
  24. 字句構造(2) • リテラル – 整数リテラル • 10進表記のみ – 浮動小数点数リテラル –

    文字リテラル • シングルクオーテーションで1文字を囲んだもの • 整数(ASCIIコード値)として扱われる – 文字列リテラル • ダブルクオーテーションで文字列を囲んだもの • 以下のエスケープシーケンスを使用可 – 改行(\n)、円記号(\\)、水平タブ(\t)、垂直タブ(\v)、バックスペース(\b)、シングルクオーテーション(\')、 ダブルクオーテーション(\")、ベル文字(\a) – 真偽値リテラル • true / false • 演算子 • 以下の文字の1〜6文字の並び – %$\#=~|^+-*/<>&!?@
  25. 式(1) • 整数リテラル – ex: 758 – バイトコード: ipush ,

    (数値) -1〜5の場合は専用の命令有り • 浮動小数点数リテラル – ex: 1.4142 – バイトコード: ldc, (コンスタントプール番号...コンパイル時に決定) • 文字リテラル – ex: 'A' • 真偽値リテラル – ex: true – バイトコード: bpush, (0/1)
  26. 式(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
  27. 式(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) – バイトコード: リストと同じ
  28. 式(4) • 構造体リテラル – ex: Point{x=10, y=50} – バイトコード: <exprn>,

    (fieldnのコンスタントプール番号), …, <expr1>, (field1のコンスタン トプール番号), makedata, (構造体名のコンスタントプール番号), (メンバ数: n) • new式 – ex: new( channel(int) ) – 現在はチャンネル型しか指定できない... – バイトコード: makechannel • リスト/タプル添字式 – ex: a[3] – バイトコード: <list>, <index>, loadbyindex
  29. 式(5) • 構造体メンバ参照式 – ex: b.size – バイトコード: <structure>, loadfield,

    (フィールド文字列のコンスタントプール番号) • 単項演算式 – ex: b! -6 – バイトコード: 専用の命令があればそれが使用される。 ユーザ定義演算子であれば、1引数関数の呼び出しとなる。 • 二項演算子 – ex: 1+1 3*6 – バイトコード: 専用の命令があればそれが使用される。 ユーザ定義演算子であれば、2引数関数の呼び出しとなる。 • 丸括弧で囲まれた式 – ( 123 + 456 )
  30. 文(1) • プログラムは文の集合 • 文の終端 – 改行またはセミコロン – ' }

    ' の手前の文は、セミコロンが省略できる • 変数宣言文 – var a:int, b=true – カンマで区切って複数の変数を一度に宣言できる – コロンの後に型を記述 • 省略する場合は、続いて初期化が必要 • 初期化する式で型推論が行われる • トップレベルでの変数宣言の場合は、型の記述が必須 • 再帰が行われる無名関数を代入する場合も、型の記述が必須 • 構造体宣言文 – data Point{ x: int y: int } – トップレベルにのみ記述できる
  31. 文(2) • 関数定義文 – トップレベルにのみ記述できる – fun name(arg1,arg2,…,argn)=>type{ … }

    – 戻り値の型を省略した場合、void型となる • 演算子定義文 – トップレベルにのみ記述できる – fun op optype , assoc , pred (...)=>type{ … } – opは演算子 – optypeはunary又はbinary – assocはleft又はright – predは優先順位 – 1・2引数関数の定義である (実際に、関数と同じ領域に登録され、 ユーザ定義演算子を使用すると関数呼び出しのコードが吐かれる)
  32. 文(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)
  33. 型(1) • 整数型: int – C++のint相当 • 浮動小数点数型: double –

    C++のdouble相当 • 論理型: bool – C++のbool相当 • 文字列型: string – 内部でC++のstringを利用 • リスト型: [ t ] – 内部でC++のlistを利用 – 範囲外アクセスを行うとランタイムエラーになる
  34. 型(2) • タプル型: ( t1, t2, …, tn) – 内部でC++のlistを利用

    – リストと同じように要素の参照、書き換えが可能 – アクセス時の添字は定数である必要がある(型を決定するため) • 構造体型 – 内部でC++のmapを利用 • 関数型: fun( args )=>t • 継続型: continuation( t ) • チャンネル型: channel( t )
  35. 組み込み関数(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の型変換
  36. 組み込み関数(2) • 出力 – void print(string) – void print_int(int) –

    void print_double(double) – void print_bool(bool) • 並列 – int hardware_concurrency() //論理コア数を取得 – void sleep(int) //指定時間(ミリ秒単位)待つ
  37. 組み込み関数(3) • グラフィックス(GLUT) – 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)
  38. 優先順位 演算子 結合性 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項: 代入) 右結合 演算子