K.Sasada's Home Page

Parrot 入門 - The Parrot Primer

Tue, 22 Jul 2003 08:07:57 +0900、初稿（翻訳）

Tue, 22 Jul 2003 22:03:28 +0900、fukumori さんのご指摘により、修正（翻訳）感謝。

Fri, 25 Jul 2003 09:41:53 +0900、またまた fukumori さんのご指摘により、修正（翻訳）感謝。

Mon, 04 Aug 2003 16:58:55 +0900、多分公開してよさそうなんで、公開

Fri, 31 Oct 2003 09:29:38 +0900、shiroさんの指摘により修正（翻訳）感謝。

本稿について

本稿は The Parrot Primer を日本語っぽく翻訳したつもりになっているものです。意訳だか違訳だかわかりません。ご注意ください。

特に許可は貰ってないんですけど、一応聞いたほうがいいかな。

レイアウトはオリジナルではなく、うちのをそのまま。怒られるかな・・・。

これのオリジナルの著作者は・・・、Parrot を作ってる人たちだと思います。よく知りません。やっぱ、ちゃんと聞かないとダメだな。えーと、この文書はライセンス的にまずいので見ないでおいてください。私のメモです、メモ。

なんか、某MLに、こんなのが書いてあったんで、多分公開していいんだろう、ということで、公開。

Koichi Sasada, a Japanese university student has translated the Parrot Primer into Japanese and put it on his website. He wanted to know if he could publicise the translation. This summary is (at least in part) his answer.

これ、俺がML見てなかったらつたわんねーよなぁ。

Parrot へようこそ

これは「Parrot: Some Assembly Required」という記事をParrot の0.0.2 のリリースのために改稿したものです。これは Parrot 初心者にとって Parrot とは何か、どう使うのかを学ぶための最良の方法にするつもり。

This is an update to the article 'Parrot: Some Assembly Required' which appeared on http://www.perl.com for the 0.0.2 release of Parrot. It's intended as being the best way for the newcomer to Parrot to learn what Parrot is and how to use it.

Parrot とは？

第一に、とにもかくにも、Parrot って何？ なんでみんなこれについて大騒ぎしてんの？ えーと。もしあなたが箱の中で暮らしてでもいなければ、Perl コミュニティが新しい Perl のデザインと、その実装をしているのを知ってるよね。新バージョンのPerl、言語と実行処理系の両方。

First, though, what is Parrot, and why are we making such a fuss about it? Well, if you haven't been living in a box for the past year, you'll know that the Perl community has embarked on the design and implementation of a new version of Perl, both the language and the interpreter.

Parrot ってのは、Perl 6 ととっても強く結びついてるけど、 Perl 6 ってわけじゃない。それが何であるかを知るためには、Perl がどうやって動いているのか、ちょっと知っておかないといけない。Perl に君のプログラムを食べさせると、まず中間言語(IR:Intermediate Representation)かバイトコード(bytecode)にコンパイルされる。そいつらをPerl内部の（コンパイラとは）ほとんど別のサブシステムであるインタプリタに食わせ、解釈実行する。つまり、Perl を動かすには 2つの別個な段階(phase)があるってわけだ。「バイトコードへコンパイル」すること、「バイトコードを解釈実行」すること。これは別に Perl に限ったことではなくて、他の言語でも同じで、例えば Python とか Ruby とか Tcl とか、信じるか信じないかは別にして、Java とか。

Parrot is strongly related to Perl 6, but it is not Perl 6. To find out what it actually is, we need to know a little about how Perl works. When you feed your program into perl, it is first compiled into an internal representation, or bytecode; then this bytecode is fed to almost separate subsystem inside perl to be interpreted. So there are two distinct phases of perl's operation - compilation to bytecode, and interpretation of bytecode. This is not unique to Perl; other languages following this design include Python, Ruby, Tcl and, believe it or not, even Java.

これまでのバージョンの Perl では、これらの配置（コンパイラとインタプリタの位置付け、かな？）がとってもその場しのぎのものだった。コンパイラとインタプリタを包むようなデザインじゃなくて、インタプリタは結局コンパイラに依存しまくりだった。そうはいっても、インタプリタ（他の言語では仮想マシン(VM:Virtual Machine) って言うけど）はソフトウェアによるCPUと考えられてる。コンパイラはそのVMのためのマシンコード命令列を生成するものってね。Cコンパイラが実際のCPU上で動作するマシンコードを生成するようにね。

In previous versions of Perl, this arrangement has been pretty ad hoc: there hasn't been any overarching design to the interpreter or the compiler, and the interpreter has ended up being pretty reliant on certain features of the compiler. Nevertheless, the interpreter (some languages call it a Virtual Machine) can be thought of as a software CPU - the compiler produces "machine code" instructions for the virtual machine, which it then executes, much like a C compiler produces machine code to be run on a real CPU.

Perl 6 もコンパイラとインタプリタのデザインを別個にしようと計画している。これが、このサブプロジェクトを立ち上げた理由だ。これは Parrot と呼ばれ、ある程度限られてはいるが Perl 6 と独立している。Parrot は Perl 6 の VM になるはずで、Perl 6 上でバイトコードを実行するソフトウェアCPU なんだ。我々は Perl 6 コンパイラを作る前に Parrot に取り掛かっている。一度（出力コードの）ターゲットが決まっちゃったほうが、コンパイラ作るの楽だしね！

Perl 6 plans to separate out the design of the compiler and the interpreter. This is why we've come up with a subproject, which we've called Parrot, which has a certain, limited amount of independence from Perl 6. Parrot is destined to be the Perl 6 Virtual Machine, the software CPU on which we will run Perl 6 bytecode. We're working on Parrot before we work on the Perl 6 compiler because it's much easier to write a compiler once you've got a target to compile to!

Parrot という名前は、2001年のエイプリルフールのジョークから選ばれた。それは、Perl と Python が共同で次のバージョンのインタプリタを作るってものだった。これは、あるアイデアを反映するものだった。ゆくゆくは同様のほかの言語がそのVMとして Parrot を使うようになって、ある意味、動的言語のための共通ランタイム に Parrot をしたい、って意味だ。

The name "Parrot" was chosen after the 2001 April Fool's Joke which had Perl and Python collaborating on the next version of their interpreters. This is meant to reflect the idea that we'd eventually like other languages to use Parrot as their VM; in a sense, we'd like Parrot to become a "common language runtime" for dynamic languages.

今どこにいるの

これは、強調しなきゃいけないんだけど、我々はまだ開発の初期段階なんだ。

It should be stressed we're still in the early stages of development.

だけど、もう少し様子を見ようかな、なんて思わないでね！ Parrot は既に使えるんだ。もう2つの小さな言語が Parrot バイトコードにコンパイルできるようになっているし（後述）、Leon Brocard は Java バイトコードから、Parrot用のそれに自動的に変換するためにがんばってる。

But don't let that put you off! Parrot is still very much usable; we've already seen two mini-languages emerge which compile down to Parrot bytecode (more on that later), and Leon Brocard has been working on automatically converting Java bytecode to Parrot.

現在のところ、Parrot アセンブラ言語で簡単なプログラムを書くことができる。Parrotマシン語に変換するためのアセンブラと、それを動かすテスト用インタプリタを使ってね。たくさんの基本的なのとか超越数学関数とか、いくつかの基本的な文字列のサポートと、それからいくつかの条件演算なんかのサポートをしてるよ。

At the moment, it's possible to write simple programs in Parrot assembly language, use an assembler to convert them to machine code and then execute them on a test interpreter. We have support for a wide variety of ordinary and transcendental mathematical operations, some rudimentary string support, and some conditional operators.

どうやって手に入れるの

だから、 Parrot のコピーを手に入れて、詳しく調べてみよう。

So let's get ourselves a copy of Parrot, so that we can start investigating how to program in the Parrot assembler.

定期的に発行される、バージョン番号つきのリリースは CPANで手に入る（現在、それは ver.0.0.3 だけど）。でも、現段階では恐ろしいほどリリースごとに違いが出る。リリースに追従するのなら、CVSからコピーをとってくるべきだ。これは、それをどうやるかって例。

Periodic, numbered releases will appear on CPAN (we're currently on version 0.0.3), but at this stage of the project an awful lot is changing between releases. To really keep up to date with Parrot, we should get our copy from the CVS repository. Here's how we do that:

% cvs -d :pserver:anonymous@cvs.perl.org:/cvs/public login (Logging in to anonymous@cvs.perl.org) CVS password: [ and here we just press return ] % cvs -d :pserver:anonymous@cvs.perl.org:/cvs/public co parrot cvs server: Updating parrot U parrot/.cvsignore U parrot/Config_pm.in ....

また、ウェブでのCVSレポジトリへのインターフェースは http://cvs.perl.org/cvsweb/parrot/ にある。

There's also a web interface to the CVS repository, available at http://cvs.perl.org/cvsweb/parrot/.

CVS の使えない人のために、CVSのスナップショットが6時間ごとに作られてて、それはここ http://cvs.perl.org/snapshots/parrot/。

For those of you who can't use CVS, there are CVS snapshots built every six hours which you can find at http://cvs.perl.org/snapshots/parrot/.

さあ、Parrot をダウンロードした。次はビルドしなきゃいけない。こんなふうに。

Now we have downloaded Parrot, we need to build it; so:

% cd parrot % perl Configure.pl Parrot Configure Copyright (C) 2001 Yet Another Society Since you're running this script, you obviously have Perl 5--I'll be pulling some defaults from its configuration. ...

あなたのローカル設定について、いくつかの質問を聞かれるはずで、リターンキーさえ押しておけばいい。そして最後に、 make コマンドをタイプして。運がよければ Parrot のテスト用インタプリタが無事にビルドされるかもね。（もしできなかったら、苦情をいうためのアドレスはこの紹介の最後にあるよ・・・）

You'll then be asked a series of questions about your local configuration; you can almost always hit return for each one. Finally, you'll be told to type make; with any luck, Parrot will successfully build the test interpreter. (If it doesn't, the address to complain to is at the end of this introduction...)

テストスート

さあ、テストを動かそう。 make test ってタイプして、次のような実行結果をみてくれ。

Now we should run some tests; so type make test and you should see a readout like the following:

perl t/harness t/op/basic.....ok, 1/2 skipped: label constants unimplemented in assembler t/op/string....ok, 1/4 skipped: I'm unable to write it! All tests successful, 2 subtests skipped. Files=2, Tests=6, 2 wallclock secs ( 1.19 cusr + 0.22 csys = 1.41 CPU)

（もちろん、これよりもいっぱいテストはあるけど、大体の雰囲気はつかめると思う。いろいろな理由から、テストは省略されることもある。ただし失敗するテストが出てきたりするのはまずいので注意しよう）

(Of course, there are many more tests than this, but you get the idea; tests may be skipped - for one reason or another - but none of them should fail!)

問題の報告

もし、Parrot について問題があったら、bugs-parrot@bugs6.perl.org へ、その問題を書いて送ってくれ。そのときには、ビルド時に作った myconfig を含めてね。

If you have problems with parrot, please send a message to bugs-parrot@bugs6.perl.org with a description of your problem. Please include the myconfig file that was generated as part of the build process.

パロットのコンセプト - Parrot Concepts

Parrot アセンブリに入る前に、簡単にいくつかのコンセプトをみておきましょう。

Before we dive into programming Parrot assembly, let's take a brief look at some of the concepts involved.

型 - Types

Parrot CPU には、4つの基本的なデータ型がある。

The Parrot CPU has four basic data types:

INTVAL 整数型; ポインタを抱えるのに十分な大きさであることを保証. FLOATVAL アーキテクチャ依存の不動小数点型. STRING 抽象化されたエンコーディング独立な文字列型. PMC その他の型。たとえば (perl の) スカラー型や配列型.

INTVAL An integer type; guaranteed to be wide enough to hold a pointer. FLOATVAL An architecture-independent floating point type. STRING An abstracted, encoding-independent string type. PMC Other types lile a (perl) scalar or an array.

最初の3つの型はほとんど自明だね。最後の型、Parrot Magic Cookies は若干理解するのが難しいかも。でも、それでもいいや。PMC についてはこの記事の最後まで、いろいろ説明するからね。

The first three types are pretty much self-explanatory; the final type, Parrot Magic Cookies, are slightly more difficult to understand. But that's OK! We'll talk more about PMCs at the end of the article.

レジスタ - Registers

現在の Perl 5 の VM はスタックマシンだ（訳注：そうだったんだー）。値を伝えるために、そえをスタックへ積むってやつ。演算は、まず最初にスタックの上から値をロードして、実際に演算して、それからその結果をスタックの上にのっける。これはとっても楽だけど、とっても遅いんだ。例えば、二つの数を足すとき、3回のスタックへのプッシュ（訳注：a,b,resultのpush）と2回のスタックからのポップ（訳注：a,b のポップ）が必要になる。悪いことに、スタックは実行時におっきくなるから、メモリ割り当てはあなたがやって欲しくない時に起こる。

The current Perl 5 virtual machine is a stack machine - it communicates values between operations by keeping them on a stack. Operations load values onto the stack, do whatever they need to do, and put the result back onto the stack. This is very easy to work with, but it's very slow: to add two numbers together, you need to perform three stack pushes and two stack pops. Worse, the stack has to grow at runtime, and that means allocating memory just when you don't want to be allocating it.

だから、Parrot は伝統的に確立されたVMとは縁を切って、レジスタアーキテクチャ、実際のハードウェアCPUと類似したアーキテクチャを使おうと思う。これは別の利点がある。レジスタベースのCPUのための全ての文献がそのまんま利用できるってこと。コンパイラの書き方とか、最適化の仕方とかね。

So Parrot's going to break with the established tradition for virtual machines, and use a register architecture, more akin to the architecture of a real hardware CPU. This has another advantage: we can use all the existing literature on how to write compilers and optimizers for register-based CPUs for our software CPU!

Parrot は各型にそれぞれ専門のレジスタがある。32個の INTVAL 用レジスタ、32個の FLOATVAL レジスタ、32個の文字列型のレジスタ、そして 32個の PMC 型のレジスタだ。Parrot アセンブラでは、それらは I0...I31, N0...N31, S0...S31, P0...P31 って表現する。

Parrot has specialist registers for each type: 32 INTVAL registers, 32 FLOATVAL registers, 32 string registers and 32 PMC registers. In Parrot assembler, these are named I0...I31, N0...N31, S0...S31, P0...P31.

さて、いくつかアセンブラを見ていこうか。set 演算でレジスタの値を設定することができる。

Now let's look at some assembler. We can set these registers with the set operator:

set I1, 10 set N1, 3.1415 set S1, "Hello, Parrot"

全てのパロット演算は同じ書式になっている。演算の名前、目的レジスタ、そしてオペランド（訳注：これだけカタカナってかっこわるい）だ。

All Parrot ops have the same format: the name of the operator, the destination register, and then the operands.

演算 - Operations

たくさんの種類の演算を使うことができるよ。docs/core_ops.pod ファイルにそれらについて書いてある。少しアセンブラの式を加えてね。たとえば、レジスタに格納されている値や、定数なんかを印字できたりする。（訳注：そんな演算いれんなー）

There are a variety of operations you can perform: the file docs/core_ops.pod documents them, along with a little more about the assembler syntax. For instance, we can print out the contents of a register, or a constant:

print "The contents of register I1 is: " print I1 print "

"

また、レジスタでの数学的な演算とかやれる。

Or we can perform mathematical functions on registers:

add I1, I1, I2 # Add the contents of I2 to the contents of I1 mul I3, I2, I4 # Multiply I2 by I4 and store in I3 inc I1 # Increment I1 by one dec N3, 1.5 # Decrement N3 by 1.5

また、単純な文字列操作なんかもできる。

We can even perform some simple string manipulation:

set S1, "fish" set S2, "bone" concat S1, S2 # S1 is now "fishbone" set S3, "w" substr S4, S1, 1, 7 concat S3, S4 # S3 is now "wishbone" length I1, S3 # I1 is now 8

分岐 - Branches

フロー制御なしじゃ、ちょっとつまんないね。まず最初に、Parrot には分岐とラベルってのがある。分岐演算は Perl の goto と同じね。

Code gets a little boring without flow control; for starters, Parrot knows about branching and labels. The branch op is equivalent to Perl's goto:

branch TERRY JOHN: print "fjords

" branch END MICHAEL: print " pining" branch GRAHAM TERRY: print "It's" branch MICHAEL GRAHAM: print " for the " branch JOHN END: end

また、レジスタが true であるかの単純なテストもできる。

It can also do simple tests for whether or not a register contains a true value:

set I1, 12 set I2, 5 mod I3, I1, I2 if I3, REMAIND print "5 is an integer divisor of 12" branch DONE REMAIND: print "5 divides 12 with remainder " print I3 DONE: print "

" end

もし I3 が true だったら（つまり、ゼロでなければ）、 REMAIND へ分岐する。もし I3 がゼロなら、演算は失敗し、次の文を実行する。これを Perl でかくとこんな感じだ。

Note that if branches to REMAIND if I3 contains a true (i.e. non-zero) value; if I3 is zero, execution falls through to the next statement. Here's what that would look like in Perl, for comparison:

$i1 = 12; $i2 = 5; $i3 = $i1 % $i2; if ($i3) { print "5 divides 12 with remainder "; print $i3; } else { print "5 is an integer divisor of 12"; } print "

"; exit;

比較について言うと、十分な数値の比較器をもってる。eq, ne, lt, gt, le, ge とか。注意してほしいのは、別な型との比較が出来ないってこと。比較するときは、サフィックスに _i や _n を、どの型を用いているかを示すためにつけなきゃいけない。これを読んでるときにはアセンブラがそれを予測するべきなんだけど。

And speaking of comparison, we have the full range of numeric comparators: eq, ne, lt, gt, le and ge. Note that you can't use these operators on arguments of disparate types; you may even need to add the suffix _i or _n to the op to tell it what type of argument you are using - although the assembler ought to divine this for you, by the time you read this.

いくつかの Parrot プログラム - Some Parrot Programs

んじゃ、少し簡単なプログラムを見ていこうか。言語の感じをつかむためにね。

Now let's have a look at a few simple Parrot programs to give you a feel for the language.

時間の表示 - Displaying the Time

この小さなプログラムは UNIX 時間を毎秒（かそこら）で表示する。

This little program displays the Unix epoch time every second: (or so)

set I3, 3000000 REDO: time I1 print I1 print "

" set I2 0 SPIN: inc I2 le I2, I3, SPIN branch REDO end

最初に、整数レジスタ3に3百万をセットする。これは完全にいい加減な番号で、3百万というのは、私のマシンでParrotの命令が一秒間あたり平均6百万回実行できることを基準に、とりあえず選んだ値だ。それで、このプログラムには2つのループがある。外側のループは現在(UNIX)時間を整数レジスタ1に格納し、表示して（ついでに改行も）整数レジスタ2をゼロにセットする。内部ループは整数レジスタ2を3百万になるまでインクリメントしていく。到達したら、 REDO へ戻る。要は、ただビジーループでいくらか時間を過ごしているだけである。これは、単純に現状のParrotが sleep 演算を持っていないから。後でどうやってこれを実装するかをみてみようね。

First, we set integer register 3 to contain 3 million - that's a completely arbitrary number, due to the fact that Parrot averages a massive six million ops per second on my machine. Then the program consists of two loops: the outer loop stores the current Unix time in integer register 1, prints it out, prints a new line, and resets register 2 to zero. The inner loop increments register 2 until it reaches the 3 million we stored in register 3. When it is no longer less than (or equal to) 3 million, we go back to the REDO of the outer loop. In essence, we're just spinning around a busy loop to waste some time. This is only because Parrot doesn't currently have a "sleep" op; we'll see how to implement one later on.

どうやってこれを動かそうかね？ まず、これを Parrot バイトコードへアセンブルしなきゃいけない。 assemble.pl でね。だから、アセンブラを showtime.pasm としてコピーして、それから Parrot ディレクトリで次を動かしてね。

How do we run this? First, we need to assemble this into Parrot bytecode, with the assemble.pl provided. So, copy the assembler to a file showtime.pasm, and inside your Parrot directory, run:

perl assemble.pl showtime.pasm > showtime.pbc

（.pbc ってのは、Parrotバイトコードの意味ね）

(.pbc is the file extension for Parrot bytecode.)

フィボナッチ数の発見 - Finding a Fibonacci number

フィボナッチ数列というのは、次のようなものだね。まず、1,1 という二つの数列を用意する。そして、最後の二つの数字を足し合わせて、数列の後ろに加える、って手段を続ける。1, 1, 2, 3, 5, 8, 13 って感じ。フィボナッチ数 fib(n) は n番目のフィボナッチ数という意味。次に示すのは最初から20個のフィボナッチ数を見つける簡単なParrotアセンブラプログラムだ。

The Fibonacci series is defined like this: take two numbers, 1 and 1. Then repeatedly add together the last two numbers in the series to make the next one: 1, 1, 2, 3, 5, 8, 13, and so on. The Fibonacci number fib(n) is the n'th number in the series. Here's a simple Parrot assembler program which finds the first 20 Fibonacci numbers:

# Some simple code to print some Fibonacci numbers # Leon Brocard <acme@astray.com> print "The first 20 fibonacci numbers are:

" set I1, 0 set I2, 20 set I3, 0 set I4, 1 REDO: set I5, I4 add I4, I3, I4 set I3, I5 print I3 print "

" inc I1 lt I1, I2, REDO DONE: end

Perl にするとこうなる。

This is the equivalent code in Perl:

print "The first 20 fibonacci numbers are:

"; my $i = 0; my $target = 20; my $a = 0; my $b = 1; until ($i == $target) { my $num = $b; $b += $a; $a = $num; print $a,"

"; $i++; }

更なる例 - Further examples

Parrotアセンブラでできるこれ以上の例は parrot/examples/assembly というサブディレクトリや http://www.parrotcode.org/examples/ というウェブページで探してね。

Additional examples of what can be done with Parrot assembler can be found in the parrot/examples/assembly subdirectory, and on the web at http://www.parrotcode.org/examples/.

Jako

アセンブラでプログラミングするのはこれくらいにして、 Jako っていう中間レベルの言語をみてみよう。Jako は Gregor Purdy によって書かれた。彼は明らかにアセンブラでのプログラミングでひどく参っていたんだ。もう濡れ烏って感じ（訳注：やりすぎ？）。Jako はちょっと C に似てて、ちょっと Perl に似てて、Parrot で出来ることはなんでもできるけど、もうちょっと整理されてる。さて、もう一度フィボナッチなプログラムを試してみよう。

So much for programming in assembler; let's move on and look at a medium-level language - Jako. Jako was written by Gregor Purdy who obviously got sick (as a parrot) of programming in assembler. Jako looks a little bit like C and a little bit like Perl, and it can do anything you can do in Parrot assembler, but a little tidier. Let's try that Fibonacci program again:

print("The first 20 fibonacci numbers are:

"); var int i = 0; var int target = 20; var int a = 0; var int b = 1; var int num; while (i != target) { num = b; b += a; a = num; print("$a

"); i++; }

どれくらい Perl バージョンに似てるかに注目してみて。"$"記号を取っ払って、Perlish な untile をもっと普通の while と取り替えて、my を var int に取り替えて、とかなんとか。

Notice how similar this is to the Perl version? I stripped away the $ sigils, replaced the Perlish until with a more common while, replaced my with var int and I was nearly done.

Jako コンパイラ、jakoc は、Parrot のlanguages/jakoに入ってる。

The Jako compiler, jakoc, ships with Parrot in the languages/jako subdirectory:

% languages/jako/jakoc fib.jako > fib.pasm % perl assemble.pl fib.pasm > fib.pbc % ./parrot fib.pbc The first 20 fibonacci numbers are: 1 1 2 3 ...

次はなに？ - Where Next?

Parrot は実際非常に急速に開発が進んでいて、コンパイラのための準備には程遠い。この節では 我々の Parrot開発を手伝ってみてもいいかな、と興味を持ってもってくれた人のために書いてる。

Parrot is obviously developing very rapidly, and we've still got a long way to go before we are ready to a compiler to this platform. This section is for those who are interested in helping us take Parrot further.

演算の追加 - Adding operations

最初に、我々はもっと多くの演算を加えなきゃいけない。でも、それは注意深く考えないといけないし、全ての新しい演算の提案は Dan Sugalski 、Parrot デザイナにチェックしてもらわなければならない。

The first thing we need is a lot more operations; but this needs to be carefully thought out, and all new proposals for operations should be checked by Dan Sugalski, the Parrot designer.

とは言っても、Parrot に新しい演算を加えるのはとても単純だ。さっき不平を言ってた sleep 演算を足してみよう。

That said, adding operations to Parrot is actually very simple. Let's add the sleep operator we were complaining about earlier.

print "String" とか、レジスタの値を表示するために print I3 とか、書けるけど、Parrot の演算は多態(polymorphic)ではない。アセンブラがちょっとトリッキーなことやって対応してる。その2つの演算は2つの別々の演算として実装されてて、 print_sc っていう文字列定数を表示するためのものと、 print_i っていって整数レジスタの値を表示するものだ。このへんはプリプロセッサによっていいようにしてるから、オペコードを追加するために必要なのは core.ops ファイルに実装を足すことだけってわけだ。

Although we've been able to say print "String" and print I3 to print a register, Parrots ops are not polymorphic - this is some trickery carried out by the assembler. Those two operations would be implemented by two different ops, print_sc to print a string constant, and print_i to print an integer register. All this is handled by the preprocessor, so all we need to do to add an opcode is to add its implementation to the core.ops file.

この書しきってのがちょっと変わってて、Perlプログラムによって前処理される C なんだ。Cの関数は op foo() か、 inline op foo() って宣言しなきゃいけない。

The format of this file is a little funny; it's C which is pre-processed by a Perl program. The C functions should be declared either op foo () or inline op foo ().

この inline 接頭語はこの関数がすげー簡単であるってことのヒントになって、JIT（訳注：JITコンパイラ。Just In Compile ではない）とかの最適化でインライン化する対象になったりする。 inline じゃない演算の関数はもっと頑張らなきゃいけない。

The inline prefix is a hint for code generation that this is a very simple op function, which for JIT or other optimizations might be able to be converted inline. Non-inline op functions might require more work.

んで、特別なパターンがあって、一番大切なのは goto NEXT() だ。この式は次の演算へ移動ってことを示してる。次の演算の場所ってのは、この演算のサイズから計算された実際のCのコードで自動的に決まる。（訳注：すげー自信なし）

There are special patterns, the most important of which is goto NEXT(). The statement goto NEXT() means that the address of the next op should be worked out automatically during real C code generation based on the size of the current op.

引数は $1 とか $2 とか、そんな感じで書く。これは実際のCの引数じゃないけど、バイトコード列から取り出すことができる引数なんだ。

Arguments are denoted by $1, $2 and so on - they aren't actual arguments to the C function, but are pulled out of the bytecode stream.

というわけで、定数sleep演算をやってみよう。引数 $1 を渡して、これをsleep（訳注：(3)）に渡してみよう。

So let's do the constant sleep op first. We want to take the first parameter, $1, and pass it to sleep:

inline op sleep (i|ic) { sleep($1); goto NEXT(); }

これは、整数定数と整数レジスタで動く。

That works for both integer constant and integer register argument versions of the op function.

あとはテスト（t/op/basic.t参照）とドキュメント（core.opsにPODを足せば自動的に docs に入る）を加えればParrot CPUへの演算の追加は完了。んで、アセンブラは自動的にsleepで寝る時間を定数か変数か、判断する。んで、sleep っていってる演算をディスパッチするわけだ。これで、showtime の例をもっとうまく欠けるね。それはちょっとした練習問題になるってわけだ。

All that's missing is a test suite (see t/op/basic.t for an example) and some documentation (add your POD to core.ops and it'll be automatically added into the appropriate file in docs) and we've added our instructions to the Parrot CPU. The assembler will automatically determine whether we're sleeping for a constant time or a variable time, and will despatch the right op when we just say sleep. Now we can rewrite the showtime code a little more neatly - or rather, you can, as a nice little exercise!

Vtable データ型 - Vtable datatypes

PMC は Perl 5 の SV や Python のオブジェクトとかに似てる。PMC はいくつかの型のオブジェクトで、いくつかの演算をすることができる。例えば、

PMCs are almost like Perl 5's SVs and Python's Objects, only more so. A PMC is an object of some type, which can be instructed to perform various operations. So when we say

inc P1

これは PMCレジスタ 1 の値を増加させるんだけど、その増加するための方法ってのは PMC が知ってる。

to increment the value in PMC register 1, the increment method is called on the PMC - and it's up to the PMC how it handles that method.

PMC は、どうやって Parrot を言語独立にしていこうかって奴で、Perl の PMC は Python や Tcl のそれとは違う挙動だったりする。特定のメソッドはvtable っていう構造にある関数ポインタで、それぞれの PMC が vtable へのポインタをもってる。クラスのメソッドを実装してるやつね。（訳注：C++のvtable のイメージで、いいんだよなぁ？ 多分）だから、 Perl インタプリタはPerlっぽいクラスなライブラリとリンクしなきゃいけないし、PMC は Perl っぽい挙動しなきゃいけないね。

PMCs are how we plan to make Parrot language-independent - a Perl PMC would have different behavior from a Python PMC or a Tcl PMC. The individual methods are function pointers held in a structure called a vtable, and each PMC has a pointer to the vtable which implements the methods of its "class". Hence a Perl interpreter would link in a library full of Perl-like classes and its PMCs would have Perl-like behaviour.

PMC型というのは doc/vtables.pod に書いてあって、新しい PMC を次のように作ることができる。

The PMC types available are described in doc/vtables.pod; you can create a new PMC with

new P0, <typename>

そして、 core.ops のPMCをサポートする命令を使うことができる。 doc/vtables.pod には、どうやって PMC の vtable クラスを実装すればいいか書いてあるよ。

and then use any of the instructions in core.ops which support PMCs. doc/vtables.pod also tells you how to implement your own PMC vtable classes.

もっとやること - More Todos

たくさん Parrot でやりたいことが残ってて、例えばいくつかの I/O（もうちょっとプログラムを面白くするための）とか、一連の文字列関数（いろんなエンコーディングとか、それらの変換とか）とか、もっともっとドキュメント用意するとか、ほんとに、ほんとにもっともっとテストしなきゃいけないとか、いろんなプラットホームでParrot の移植性を確認したりとか、あと、もっと演算を用意したり、とか。

There are a huge number of things we want to do with Parrot: we need, for instance, to create some I/O operators to make programs actually interesting; we want to create a range of string functions to deal with various encodings and convert between them; we want more documentation; we really, really need more tests; we want to check Parrot's portability to various platforms; and finally, there are a load more ops that we need to implement.

Getting involved

かなりの数の人々がParrotにかかわってるけど、人手は多いに 越したことはない。手助けをしたいと思ったならば perl6-internals mailing(perl6-internals@perl.org)を購読してほしい。また、CVSから最新版をもっとくってのもいいね。もしCVSのコミットのお知らせがほしければ、cvs-parrot mailing list (cvs-parrot@perl.org)に入るといい。CVSのコミット権はある部分への責任者か、いいパッチをよく書いてくれる人に与えられるよ。

We've got a good number of people working away on Parrot, but we could always use a few more. To help out, you'll need a subscription to the perl6-internals mailing list, (perl6-internals@perl.org), where all the development takes place. You should also keep up to date with the CVS version of Parrot; if you want to be alerted to CVS commits, you can subscribe to the cvs-parrot mailing list (cvs-parrot@perl.org). CVS commit access is given to those who taken responsibility for a particular area of Parrot, or who often commit high-quality patches.

便利なウェブサイトは http://cvs.perl.org で、CVSの使い方とか書いてあったり、CVS リポジトリがみれたりする。コードページはこの情報のまとめとか書いてあったり、他の情報とかある。他のいい感じの情報は、http://www.parrotcode.org にあるね。

A useful web page is http://cvs.perl.org, which reminds you how to use CVS, and allows you to browse the CVS repository; the code page is a summary of this information and other resources about Parrot. Another good resource is http://www.parrotcode.org.

遅れないで、さあ Parrot を始めよう！

So don't delay - pick up a Parrot today!

Sasada Koichi / sasada@namikilab.tuat.ac.jp