Clemは、ファーストクラスの機能を備えた最小のスタックベースのプログラミング言語です。あなたの目的はクレム言語のインタプリタを書くことです。ここにあるリファレンス実装に含まれるすべての例を適切に実行する必要があります。
- いつものように、標準の抜け穴が適用されます。
- バイトカウントによる最小のエントリが優先されます。
クレム語
Clemは、ファーストクラスの機能を備えたスタックベースのプログラミング言語です。クレムを学ぶ最良の方法はclem
、引数なしでインタプリタを実行することです。インタラクティブモードで起動し、使用可能なコマンドで遊ぶことができます。サンプルプログラムを実行するには、「example」がプログラムclem example.clm
の名前であると入力します。この簡単なチュートリアルは、始めるのに十分なはずです。
関数には2つの主要なクラスがあります。原子関数と複合関数。複合関数は、他の複合関数とアトミック関数で構成されるリストです。複合関数にそれ自体を含めることはできません。
原子関数
アトミック関数の最初のタイプは定数です。定数は、単に整数値です。たとえば、-10。インタープリターが定数を検出すると、それをスタックにプッシュします。clem
今すぐ実行します。入力-10
プロンプトで。君は見るべきだ
> -10
001: (-10)
>
値001
はスタック内の関数の位置を表し、入力し(-10)
た定数です。+11
プロンプトで入力してください。君は見るべきだ
> +11
002: (-10)
001: (11)
>
(-10)
がスタックの2番目の位置に移動し(11)
、最初の位置を占めていることに注意してください。これがスタックの性質です!これが-
減分コマンドでもあることに気づくでしょう。たび-
または+
番号の前に、彼らはその数ではなく、対応するコマンドの兆候を示しています。他のすべてのアトミック関数はコマンドです。合計14あります。
@ Rotate the top three functions on the stack
# Pop the function on top of the stack and push it twice
$ Swap the top two functions on top of the stack
% Pop the function on top of the stack and throw it away
/ Pop a compound function. Split off the first function, push what's left,
then push the first function.
. Pop two functions, concatenate them and push the result
+ Pop a function. If its a constant then increment it. Push it
- Pop a function. If its a constant then decrement it. Push it
< Get a character from STDIN and push it to the stack. Pushes -1 on EOF.
> Pop a function and print its ASCII character if its a constant
c Pop a function and print its value if its a constant
w Pop a function from the stack. Peek at the top of the stack. While it is
a non-zero constant, execute the function.
プロンプトでコマンドを入力すると、コマンドが実行されます。入力#
(重複コマンド)プロンプトで。君は見るべきだ
> #
003: (-10)
002: (11)
001: (11)
>
(11)が複製されていることに注意してください。今タイプ%
(dropコマンド)プロンプトで。君は見るべきだ
> %
002: (-10)
001: (11)
>
コマンドをスタックにプッシュするには、単にそれを括弧で囲みます。入力(-)
プロンプトで。これにより、デクリメント演算子がスタックにプッシュされます。君は見るべきだ
> (-)
003: (-10)
002: (11)
001: (-)
>
複合関数
複数のアトミック関数を括弧で囲んで、複合関数を形成することもできます。プロンプトで複合関数を入力すると、スタックにプッシュされます。入力($+$)
プロンプトで。君は見るべきだ
> ($+$)
004: (-10)
003: (11)
002: (-)
001: ($ + $)
>
技術的には、スタック上のすべてが複合関数です。ただし、スタック上の複合関数の一部は単一のアトミック関数で構成されています(この場合、便宜上、それらはアトミック関数と見なします)。スタック上の複合関数を操作する場合、.
コマンド(連結)が役立つことがよくあります。.
今すぐ入力してください。君は見るべきだ
> .
003: (-10)
002: (11)
001: (- $ + $)
>
スタックの最初の関数と2番目の関数が連結され、スタックの2番目の関数が結果のリストの最初に来ることに注意してください。スタック上にある関数(それがアトミックかコンパウンドか)を実行するには、w
コマンド(while)を発行する必要があります。w
命令は、スタック上の最初の機能をポップし、あれば、スタック上の第二の機能が非ゼロで一定であるとしてそれを繰り返し実行します。入力するとどうなるかを予測してみてくださいw
。次に、と入力しw
ます。君は見るべきだ
> w
002: (1)
001: (0)
>
それはあなたが期待したことですか?スタックの上にある2つの数値が追加され、それらの合計が残ります。もう一度やってみましょう。最初にゼロをドロップし、と入力して10をプッシュします%10
。君は見るべきだ
> %10
002: (1)
001: (10)
>
次に、関数全体を一度に入力しますが%
、最後にゼロを追加してゼロを取り除きます。入力(-$+$)w%
プロンプトで。君は見るべきだ
> (-$+$)w%
001: (11)
>
(このアルゴリズムは、スタックの最初の定数が正の場合にのみ機能することに注意してください)。
文字列
文字列も存在します。それらは主に構文上の砂糖ですが、非常に便利です。インタプリタは文字列に遭遇すると、各文字を最後から最初にスタックにプッシュします。%
前の例から11をドロップするために入力します。次に、0 10 "Hi!"
プロンプトを入力します。0
NULLターミネータを挿入しますと、10
改行文字を挿入します。君は見るべきだ
> 0 10 "Hi!"
005: (0)
004: (10)
003: (33)
002: (105)
001: (72)
>
(>)w
NULLターミネータに遭遇するまで、スタックから文字を印刷するために入力します。君は見るべきだ
> (>)w
Hi!
001: (0)
>
結論
うまくいけば、これでインタプリタを使い始めるのに十分なはずです。言語設計は比較的単純なものでなければなりません。何かがひどく不明確であるかどうかを知らせてください:)いくつかのことは意図的に曖昧なままにされました:値は署名されなければならず、少なくとも 16ビットであり、スタックはすべての参照プログラムを実行するのに十分な大きさでなければなりません。多くの詳細は刻まれていません本格的な言語仕様を投稿するには法外に大きいため(ここではまだ記述していません:P)。疑わしい場合は、リファレンス実装を模倣してください。