Pythonで自作言語

# 自己紹介
初投稿なので自己紹介します。
SUPERFIRE777です。
こう書いて「スーパーファイヤートリプルセブン」と読みます。
[twitter](https://twitter.com/superfire777)や[YouTube](https://www.youtube.com/channel/UC1PTZsX1cQDs9SEoPJebEWg)でも活動していて、趣味でPythonを触ってます。
よろしくお願いします。

# どんな言語？
スタックを使ってプログラムを組んでいきます。
プログラムを実行するプログラムはPythonで書いていて、中身は240行くらいあります。
# 環境
```
Windows11
Python 3.11.2
```
`match-case`構文を使っているので、`Python 3.10`以上でしか動かないと思います。

# 言語仕様
表内のA, B, ...はスタックからpopした値です。

## スタック操作
| 命令 | 意味 |
| --- | --- |
| `数値` | 数値をPush |
| `{ ... }` | ...を文字列としてPush |
| `A dup` | Aを2個Pushする |
| `clear` | スタックをクリアする |

## 特殊命令
| 命令 | 意味 |
| --- | --- |
| `A #` | 何もしない |
| `A exec` | Aをプログラムとして実行 |

`#`はコメントアウトなどの用途で使えます。
例えば、`{ hogehogeを実行 } #`などです。

## 標準入出力
|  命令  |  意味  |
| ---- | ---- |
| `input` |  文字列で入力を受け取ってPush  |
| `A print`  |  Aに何もつけず表示  |
| `A printsp` | Aに半角スペースをつけて表示 |
| `A println`  | Aに改行をつけて表示 |
| `stack` | スタックの中身を表示 |

つまり`input print`でオウム返しができます。

## 数値計算
|命令|意味|
|---|---|
|`A B +` | A+BをPush |
|`A B -` | A-BをPush |
|`A B *` | A*BをPush |
|`A B /` | A÷BをPush |
|`A B %` | AをBで割った余りをPush |
|`A B **` | $ A^B $をPush |

例えば、
`5 2 +`は`7.0`に、
`5 2 -`は`3.0`に
なります。

## 比較命令
|命令|意味|
|---|---|
|`A B >` | $A > B$なら1.0を、そうでなければ0.0をPush |
|`A B <` | $A < B$なら1.0を、そうでなければ0.0をPush |
|`A B >=` | $A \ge B$なら1.0を、そうでなければ0.0をPush |
|`A B <=` | $A \le B$なら1.0を、そうでなければ0.0をPush |
|`A B ==` | $A = B$なら1.0を、そうでなければ0.0をPush |
|`A B !=` | $A \ne B$なら1.0を、そうでなければ0.0をPush |

## 型変換
| 命令 | 意味 |
| --- | --- |
| `A tofloat` | Aをfloat型に変換|
| `A toint` | Aをint型に変換 |
| `A tostr` | Aをstr型に変換 |

例えば、`input toint`で整数で入力を受け取ることができます。

## 変数
このプログラミング言語では、変数を使用することができます。
| 命令 | 意味 |
| --- | --- |
| `A B set` | AにBを代入 |
| `A get` | Aの値を取得してPush |
| `A delete` | 変数Aを削除 |

定義されていない変数や`delete`で削除された変数の値は`undefined`になります。

例えば、
```
a 5 set
a a get 1 + set
```
でPythonの
```py
a = 5
a = a + 1
```
に相当することができます。

## 条件分岐
| 命令 | 意味 |
| --- | --- |
| `A B if` | $A \ne 0$ならBをプログラムとして実行 |
| `A B unless` | $A=0$ならBをプログラムとして実行 |

例えば、
```
{ 年齢: } printsp
age input tofloat set
age get 18 >= dup
	{ { 成人 } println } if
	{ { 未成年 } println } unless
```
で成人判定ができます。

この`if`、`unless`はネストできます。
例えば、
```
FizzBuzz
{ i get 15 % 0 == dup
	{ FizzBuzz println } if
	{ i get 3 % 0 == dup 
		{ Fizz println } if 
		{ i get 5 % 0 == dup
			{ Buzz println } if
			{ i get println } unless 
		} unless
	} unless
} set
```
でFizzBuzzのループの中身を変数`FizzBuzz`に代入することができます。

## 繰り返し
| 命令 | 意味 |
| --- | --- |
| `A B C D for` | 変数AをBからCまで1ずつ増やしながらDをプログラムとして実行 |
| `A B while` | 変数Aが$A \ne 0$を満たす間Bをプログラムとして実行 |

例えば、前定義した`FizzBuzz`を使って
`i 1 100 { FizzBuzz get exec } for`
と書くことによってFizzBuzzを実行できます。

以下は、`while`を使ったプログラムの例です。
```
x 1 set

sum 0 set

x {
	{ 整数入力: } printsp
	x input toint set
	sum sum get x get + set 
} while

{ 合計は } print
sum get toint println
```
このプログラムは`0`が入力されるまで入力された整数を足し続け、`0`が入力されたら合計を表示するというプログラムです。

変数が`0`にならなければループが回り続けるので、
```
x 1 set
x { { Infinite Loop } println } while
```
で「Infinite Loop」を無限に出力させることができます。

## 文字列関連
| 命令 | 意味 |
| --- | --- |
| `space` | 半角スペースをPush |
| `A B strcat` | AとBが両方文字列ならAとBを文字列結合したものを、そうでなければ"undefined"をPush |
| `A B C replace` | AのBをCに置換したものをPush |

例えば、
```
string
	{ Hello } space strcat
	{ World } strcat 
set
string get println
string
	string get space { - } replace
set
string get println
```
上記のプログラムの実行結果は、
```
Hello World
Hello-World
```
になります。

# おわりに
ここまで見てくださってありがとうございます。
言語に要素を付け足していって、それがうまく動いた時の達成感は凄くありました。
ところで、Python 3.10の新機能である`match-case`を使うと、いちいち条件分岐で`token == ...`って書かなくていいので便利ですね。
こういう言語とかを作るときに再帰が有用であることも学べました。
他にも`defaultdict`で`undefined`の仕様が簡単に作れることとか、変数のありがたみとか。
言語を作ることで色んなことが学べるので、皆さんも是非作ってみてください！