Parrot-examples

提供:Dev Guides
移動先:案内検索

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ディレクティブはありません。代わりに、命令の開始時にそれらをラベルに置き換えます。