Home

Awesome

このesolangはTSG夏合宿2018のために作られました.

2020/5/3アップデート

言語仕様をきれいにしました. 旧ドキュメントはREADME-old.mdにあります.

Bots

TSGのslackの#sandboxではさまざまなbotが動いています.

例)

http://hakatashi.hatenadiary.com/entry/2017/12/03/173400 http://kurogoma.hatenablog.com/entry/2017/12/08/000000 http://hakatashi.hatenadiary.com/entry/2017/12/03/185033

初期にはbotが暴走してメッセージを垂れ流すなどの事件も起こっていました. 今回の"Bots"はこれを参考にして作りました.

動かし方

python3 interpreter.py ソースコード で実行できます.

実行オプション

デバッグ用命令

プログラム中に #s もしくは #e を書いておくと,その時点でのスタックもしくは環境を表示します.

Syntax(文法)

<program> ::= <stack>

<stack> ::= <element>*

<element> ::= <ident> | <number> | <operator> | <funcdef>

<funcdef> ::= <ident> "(){" <stack> "}" | <ident> "(" <arguments> "){" <stack> "}"
<arguments> ::= <ident> | <ident> "," <arguments>

<ident> ::= [0-9A-Za-z]+
<number> ::= [0-9]+
<operator> ::= [+-*/@?] | "ic" | "id" | "oc" | "od"

Syntaxの日本語訳

botsのプログラムは1つのstackです. stackは,複数個のelementの列です. elementには4種類あります.

関数定義は,まず関数名,その次に0個以上の関数の引数を","で区切って"()"でかこったもの,その後に関数のボディであるstackを"{}"でかこったもの,を並べた列です.

プログラム例

たとえば,以下はどれも文法的に正しいbotsのプログラムです.(実行時エラーは発生したりする)

ic + 1 od @ 0
hoge hug4 PiYo 123 000 + - * / @ ?
g(x){ + 1 x ? + @ 0 x oc }
f(){ ic g f }
f
11 f(x){
  56 g(y,z,r){
    h(){}
  } 78 
} 90

Semantics(プログラムの挙動)

<!-- プログラムの状態は,「スタック」と「環境」からなります.「スタック」は「データ」のスタックとし,「環境」はidから関数定義への部分関数とします.プログラムの「データ」は「文字列」もしくは「数値」です. 初期状態では,「スタック」はソースコードで記述されたスタックとし,「環境」は組み込み関数の定義(後述)のみとします. プログラムは,「スタック」のトップにある「データ」に従って「スタック」と「環境」を書き換える,というステップを繰り返すことによって実行されます. 以下の説明では,「スタック」の書き換えの1ステップを `e x1 x2 x3 ... xn S` -> `y1 y2 ... ym S` の形で書くことにします.これは,『「スタック」のトップにある「データ」がeのとき,「スタック」の先頭からn+1個の「データ」をe,x1,...,xnとし,「スタック」の残りの「データ」列をSとすると,1ステップ後には「スタック」は `y1 y2 ... ym S` というデータ列になっている』ということを意味しています. -->

プログラムの状態はデータの列であるスタックで表現されます.データは「識別子」もしくは「数値」もしくは「関数定義」です.初期状態では,状態スタックはソースコードで記述されたスタックとします.

プログラムは,スタックのトップにあるデータに従ってスタックを書き換える,というステップを繰り返すことによって実行されます.

以降の説明では,スタックの書き換えの1ステップを

e x1 x2 x3 ... xn S -> y1 y2 ... ym S

の形で書くことにします.これは,『スタックのトップにあるデータがeのとき,スタックの先頭からn+1個のデータをe,x1,...,xnとし,残りのデータ列をSとすると,1ステップ後にはスタックは y1 y2 ... ym S というデータ列になっている』ということを意味しています.

組み込み関数の挙動

+ - * /

加減乗除を行います.除算は切り捨て(pythonの//と同じ負方向への丸め)です.

+ a b f S -> f (a+bの値) S

- a b f S -> f (a-bの値) S

* a b f S -> f (a*bの値) S

/ a b f S -> f (a/bの値) S

たとえば, + 4 5 - 6 * 7 / 8 @

+ 4 5 - 6 * 7 / 8 @
    - 9 6 * 7 / 8 @
        * 3 7 / 8 @
           / 21 8 @
                @ 2 

となります.

ic,id

文字,数字を入力します。

ic f S -> f (読みこんだ文字の文字コード) S

id f S -> f (読みこんだ数字の値) S

たとえば,123を入力した場合、(1の文字コードは49)
ic + 2 @

ic + 2 @
+ 49 2 @
@ 51

id + 2 @

id + 2 @
+ 123 2 @
@ 125

となります.

oc,od

文字,数字を出力します。

oc a S -> S (文字コードがaの文字が出力される)

od a S -> S (10進表記したaの値が出力される)

たとえば,oc 49

oc 49

となり,1が出力され, od 49

od 49

となり,49が出力されます.

?

条件分岐です.

? a f g S -> f S (aが0でない数値のとき)

? 0 f g S -> g S

たとえば, id ? oc od 49 は, もし0が入力されたら

id ? oc od 49
 ? 0 oc od 49
        od 49

となり,49が出力されます.

もし1が入力されたら

id ? oc od 49
 ? 1 oc od 49
        oc 49

となり,1が出力されます.

@

プログラムを終了させます.

@ a S -> S (exitコードaでプログラムを終了させる)

たとえば, @ 123 は,exitコード123でプログラムを終了させます.

関数定義と関数実行の挙動

funcdef, ident

関数定義と関数適用を行います.

スタックのトップが f(a1, ... ,an){ d1 ... dm } という関数定義の場合,「fがスタックトップにあった際の挙動」が変更されます. (このため,正確にはプログラムの状態は「スタック」と「環境」の2つ組,とするべきですが,簡便のため省きました.)

funcdef S -> S (ただし環境がアップデートされる)

関数が定義された状態で関数を適用すると,定義に従ってスタックが書き換えられます. たとえば, f(x){+ 1 x} f 42 というプログラムを実行すると,スタックの遷移は以下のようになります.

f(x){+ 1 x} f 42 @
f 42 @
+ 1 42 @
@ 43

f 42 という関数適用を1ステップ進めると,fの本体である + 1 xx42に置換した + 1 42 になります.

より詳しく書くと,関数ff(a1, ... ,an){ d1 ... dm } として定義されているとき,

f x1 ... xn S -> d1[x1/a1, ... xn/an] ... dm[x1/a1, ... xn/an] S

とします.ここで,d[x1/a1, ... xn/an] は,

たとえば, f(x){ g(x){ + x 4 } } f 3 g 2 @

f(x){ g(x){ + x 4 } } f 3 g 2 @
f 3 g 2 @
g(x){ + 3 4 } g 2 @
g 2 @
+ 3 4 @
@ 7

となります.(g中のxが置換されていることに注意してください)

Semantics まとめ

+ a b f S -> f (a+bの値) S
- a b f S -> f (a-bの値) S
* a b f S -> f (a*bの値) S
/ a b f S -> f (a/bの値) S

ic f S -> f (読みこんだ文字の文字コード) S
id f S -> f (読みこんだ数字の値) S

oc a S -> S (画面に文字コードがaの文字が出力される)
od a S -> S (画面に10進表記したaの値が出力される)

? a f g S -> f S (aが0でない数値のとき)
? 0 f g S -> g S

@ a S -> S (exitコードaでプログラムを終了させる)

funcdef S -> S (ただし環境がアップデートされる)

f x1 ... xn S -> d1[x1/a1, ... xn/an] ... dm[x1/a1, ... xn/an] S (関数fがf(a1, ... ,an){ d1 ... dm }として定義されている)

Misc