Parrot-examples
Parrot-プログラミングの例
Parrotプログラミングはアセンブリ言語プログラミングに似ており、低レベルで作業する機会が得られます。 Parrotプログラミングのさまざまな側面を理解するためのプログラミング例のリストを以下に示します。
- リンク:/parrot/parrot_examples#parrot_hello_world [クラシックハローワールド!]
- リンク:/parrot/parrot_examples#parrot_registers [レジスターの使用]
- リンク:/parrot/parrot_examples#parrot_squares [平方和]
- リンク:/parrot/parrot_examples#parrot_fibonacci [フィボナッチ数]
- リンク:/parrot/parrot_examples#parrot_factorial [階乗の計算]
- リンク:/parrot/parrot_examples#parrot_pbc [PBCへのコンパイル] *リンク:/parrot/parrot_examples#parrot_pir [PIR vs. PASM]
[#parrot_hello_world]#クラシックHello world!#
次のコードを含むhello.pirというファイルを作成します。
.sub _main
print "Hello world!\n"
end
.end
次に、次のように入力して実行します。
parrot hello.pir
予想どおり、これにより「Hello world!」というテキストが表示されます。コンソールで、新しい行が続きます(\ nのため)。
上記の例では、「。sub _main」は、「。end」が検出されるまで、後続の命令が「_main」という名前のサブルーチンを構成することを示しています。 2行目には、印刷指示が含まれています。 この場合、定数文字列を受け入れる命令のバリアントを呼び出しています。 アセンブラーは、使用する命令のバリアントを決定します。 3行目には、インタープリターを終了させる「終了」命令が含まれています。
[#parrot_registers]#レジスタの使用#
hello.pirを変更して、最初に文字列Hello world!\ nをレジスターに格納してから、そのレジスターを印刷命令で使用できます。
.sub _main
set S1, "Hello world!\n"
print S1
end
.end
ここで、使用するレジスタを正確に述べました。 ただし、S1を$ S1に置き換えることにより、使用するレジスタの選択をParrotに委任できます。 set命令を記述する代わりに=表記を使用することもできます。
.sub _main
$S0 = "Hello world!\n"
print $S0
end
.end
PIRをさらに読みやすくするために、名前付きレジスタを使用できます。 これらは後に実数のレジスタにマッピングされます。
.sub _main
.local string hello
hello = "Hello world!\n"
print hello
end
.end
'.local’ディレクティブは、指定されたレジスターが現在のコンパイル単位内(つまり、.subと.endの間)でのみ必要であることを示します。 「.local」に続くのがタイプです。 これは、int(Iレジスタの場合)、float(Nレジスタの場合)、string(Sレジスタの場合)、pmc(Pレジスタの場合)、またはPMCタイプの名前です。
[#parrot_squares] #Summing squares#
この例では、さらにいくつかの命令とPIR構文を紹介します。 #で始まる行はコメントです。
.sub _main
# State the number of squares to sum.
.local int maxnum
maxnum = 10
# Some named registers we'll use.
# Note how we can declare many
# registers of the same type on one line.
.local int i, total, temp
total = 0
# Loop to do the sum.
i = 1
loop:
temp = i* i
total += temp
inc i
if i <= maxnum goto loop
# Output result.
print "The sum of the first "
print maxnum
print " squares is "
print total
print ".\n"
end
.end
PIRは、アセンブリよりも高レベルに見える構文糖を少し提供します。 例えば:
temp = i * i
より多くのアセンブリのように書くための単なる別の方法です:
mul temp, i, i
And:
if i <= maxnum goto loop
と同じです:
le i, maxnum, loop
And:
total += temp
と同じです:
add total, temp
原則として、Parrot命令がレジスターの内容を変更するときは常に、アセンブリー形式で命令を書き込むときの最初のレジスターになります。
アセンブリ言語で通常行われているように、ループと選択は、上記のように条件分岐ステートメントとラベルの観点から実装されます。 アセンブリプログラミングは、gotoの使用が悪い形ではない1つの場所です!
[#parrot_fibonacci]#フィボナッチ数#
フィボナッチ数列は次のように定義されます:1と1の2つの数値を取ります。 次に、シリーズの最後の2つの数字を繰り返し加算して、次の数字を作成します:1、1、2、3、5、8、13など。 フィボナッチ数fib(n)は、シリーズのn番目の数です。 以下は、最初の20個のフィボナッチ数を見つける簡単なParrotアセンブラプログラムです。
# Some simple code to print some Fibonacci numbers
print "The first 20 fibonacci numbers are:\n"
set I1, 0
set I2, 20
set I3, 1
set I4, 1
REDO: eq I1, I2, DONE, NEXT
NEXT: set I5, I4
add I4, I3, I4
set I3, I5
print I3
print "\n"
inc I1
branch REDO
DONE: end
これはPerlの同等のコードです:
print "The first 20 fibonacci numbers are:\n";
my $i = 0;
my $target = 20;
my $a = 1;
my $b = 1;
until ($i == $target) {
my $num = $b;
$b += $a;
$a = $num;
print $a,"\n";
$i++;
}
- 注:*興味深い点として、Perlでフィボナッチ数列を印刷する最も短く確実な最も美しい方法の1つはperl -le '$ b = 1;です。 $ b + = $ a 'を印刷しながら$ a + = $ bを印刷します。
[#parrot_factorial]#再帰的階乗計算#
この例では、階乗関数を定義し、再帰的に呼び出して階乗を計算します。
.sub _fact
# Get input parameter.
.param int n
# return (n > 1 ? n *_fact(n - 1) : 1)
.local int result
if n > 1 goto recurse
result = 1
goto return
recurse:
$I0 = n - 1
result = _fact($I0)
result* = n
return:
.return (result)
.end
.sub _main :main
.local int f, i
# We'll do factorial 0 to 10.
i = 0
loop:
f = _fact(i)
print "Factorial of "
print i
print " is "
print f
print ".\n"
inc i
if i <= 10 goto loop
# That's it.
end
.end
最初に_factサブを見てみましょう。 先ほど説明したポイントは、サブルーチンの名前がすべてアンダースコアで始まる理由です! これは、ラベルが特定のサブルーチンにスコープされているのではなく、グローバルであることを示す方法としてのみ行われます。 これは、ラベルが他のサブルーチンから見えるようになるため重要です。
最初の行の.param int nは、このサブルーチンが1つの整数パラメーターを取り、残りのサブに対してnという名前で渡されたレジスターを参照することを指定します。
以下の内容の多くは、行の読み取りを除き、以前の例で見られました。
result = _fact($I0)
このPIRの単一行は、実際にはPASMのかなりの数の行を表しています。 最初に、レジスタ$ I0の値が適切なレジスタに移動され、_fact関数によって整数パラメータとして受信されます。 次に、他の呼び出し関連レジスタがセットアップされ、続いて_factが呼び出されます。 次に、_factが返されると、_factによって返された値が、名前の結果を指定してレジスタに配置されます。
_factサブの.endの直前に、.returnディレクティブを使用して、レジスタに保持されている値を確認します。名前付き結果は、subを呼び出すコードによって戻り値として表示されるように、正しいレジスタに配置されます。
mainでの_factの呼び出しは、sub _fact自体内での_factの再帰呼び出しと同じように機能します。 新しい構文の唯一の残りのビットは、.sub _mainの後に記述された:mainです。 デフォルトでは、PIRは実行がファイルの最初のサブルーチンから始まると想定します。 この動作は、:mainで始まるサブをマークすることで変更できます。
[#parrot_pbc] #PBCへのコンパイル#
PIRをバイトコードにコンパイルするには、-oフラグを使用して、拡張子が.pbcの出力ファイルを指定します。
parrot -o factorial.pbc factorial.pir
[#parrot_pir] #PIR対 PASM#
PIRは、次を実行することでPASMに変換できます。
parrot -o hello.pasm hello.pir
最後の例のPASMは次のようになります。
_main:
set S30, "Hello world!\n"
print S30
end
PASMは、レジスターの割り当てを処理せず、名前付きレジスターのサポートも提供しません。 また、.subディレクティブと.endディレクティブはありません。代わりに、命令の開始時にそれらをラベルに置き換えます。