クラなんとか or くらなんとか or cla なんとかの日記

2011-10-24

ギークバーに行ってきた

ということで,pir です.

# parrot hello.pir
.sub main
    say "Hello, World!"
.end

なんだこれ.リッチ


parrot-3.6.0/docs/book/pir/ch03_basic_syntax.pod

=pod

=head1 基本構文

Z<CHP-3>

X<PIR syntax>
PIR は比較的単純な構文を持っている.全ての行はコメント,ラベル,文,ディレクティブのいづれかである.全ての文,ディレクティブは,それ自体の行に依存する.(Cでのセミコロンのような)行末(EOL)のシンボルは無い.

=head2 コメント

X<comments>
コメントはC<#> シンボルで始まり,行末まで続く.コメントは,行にのみ依存し,行やディレクトリが後に続きます.

=begin PIR

    # これは,一般的なコメントです.PIR
    # インタプリタはこれを無視します.

=end PIR

X<Pod documentation>
PIR は,Pod 形式のもインラインドキュメントも取り扱います.行の先頭の文字が等号の場合,Pod ブロックの開始を意味します.C<=cut> マーカは,Pod ブロックの終端を意味します.

  =head2

  これは,Pod ドキュメントであり,1つのコメントとして扱われます.
  comment. PIR インタプリタはこれを無視します.

  =cut

=head2 ラベル

X<labels>
他の文が参照するために,ラベルはコードの行に対して名前を与えます.ラベルは文字,数字,アンダースコアで構成されています.ソースコードの他の部分から目立つよう,ラベルには全て大文字を使うことが多いです.ラベルと同じ行に文やディレクトリを置くことは良いことです:

=begin PIR_FRAGMENT

    GREET: say "'Allo, 'allo, 'allo."

=end PIR_FRAGMENT

単独で行にあるラベルは,逆インデントされている場合に特に可視性を改善します:

=begin PIR_FRAGMENT

  GREET:
    say "'Allo, 'allo, 'allo."

=end PIR_FRAGMENT

=head2 Statements

Z<CHP-3-SECT-1>

X<statements>X<opcodes>
文は,オペコード,1つ以上のオペコードに対するシンタックスシュガーのどちらかです.オペコードは,バーチャルマシンのネイティブな命令です.命令の名前と零個以上の引数が続くもので構成されます.

=begin PIR_FRAGMENT

  say "Norwegian Blue"

=end PIR_FRAGMENT

PIR は,高いレベルの構造(?)を提供し,それにはシンボリックなオペコードも含まれます:

=begin PIR_FRAGMENT

  $I1 = 2 + 5

=end PIR_FRAGMENT

X<operators>
これらの特別な文の形式は,一般のオペコードのシンタックスシュガーでしかありません.C<+> シンボルはC<add> オペコード,C<-> シンボルは,C<sub>オペコードに,などのように対応します.
これは以前の例と等価です:

=begin PIR_FRAGMENT

  add $I1, 2, 5

=end PIR_FRAGMENT

=head2 ディレクティブ

X<directives>
ディレクティブは,オペコードと似ていますが,ピリオド(C<.>)で始まります.コンパイル時に起きるアクションを指定するディレクティブもあります.複数の命令を生成を必要とするような複雑な操作を表現するディレクティブもあります.例えば,C<.local> ディレクティブは,名前のある変数を宣言します.

=begin PIR_FRAGMENT

  .local string hello

=end PIR_FRAGMENT

=head2 リテラル

X<literals>
整数と小数は数字のリテラルです.それらは正と負があります.

=begin PIR_FRAGMENT

  $I0 = 42       # 正の数
  $I1 = -1       # 負の数

=end PIR_FRAGMENT

X<integers>
整数リテラルは,2進,8進,16進もあります.

=begin PIR_FRAGMENT

  $I1 = 0b01010  # 2進
  $I2 = 0o72     # 8進
  $I3 = 0xA5     # 16進

=end PIR_FRAGMENT

X<numbers (floating-point)>
小数点数リテラルは10進であり,科学的記数法も使えます:

=begin PIR_FRAGMENT

  $N0 = 3.14
  $N2 = -1.2e+4

=end PIR_FRAGMENT

X<strings>
文字列リテラルは,クォートとダブルクォートで囲まれています.N<クォートの違いの詳細については4章の L<Strings> 節を参照してください.>

=begin PIR_FRAGMENT

  $S0 = "これは正しいリテラル文字列です"
  $S1 = 'これも正しいリテラル文字列です'

=end PIR_FRAGMENT

=head2 変数

X<variables>
PIR 変数は4つの種類の値を格納できます.それは,整数,小数,文字列,オブジェクトです.Parrot のオブジェクトは,PMC と呼ばれます.これは,"I<P>olyI<M>orphic I<C>ontainer" です.

最も単純な種類の変数がレジスタ変数です.レジスタ変数の名前は,常にドル記号(C<$>)で始まり,変数の型を現わす1文字の,整数(C<I>),小数(C<N>),文字列(C<S>),PMC(C<P>) が続き,個別の数字で終わります.レジスタ変数を事前に宣言しておく必要はありません:

=begin PIR_FRAGMENT

  $S0 = "Who's a pretty boy, then?"
  say $S0

=end PIR_FRAGMENT

X<named variables>
PIR は,名前のある変数もあります.C<.local> ディレクティブがそれらの宣言をしますレジスター変数のように,4つの正しい型があります:
C<int>C<num>C<string>C<pmc> です.名前のある変数は宣言されなければなりません.一度宣言されれば,それらはレジスタ変数と同じように振舞います.

=begin PIR_FRAGMENT

  .local string hello
  hello = "'Allo, 'allo, 'allo."
  say hello

=end PIR_FRAGMENT

=head2 定数

X<constants>
C<.const> ディレクティブは名前のある定数を宣言します.名前のある定数は名前のある変数と似ていますが,宣言時に設定された値が変更できません.C<.local>のように,C<.const> は型と名前を受け取ります.定数の値として設定するために,リテラル引数を必要ともします.

=begin PIR_FRAGMENT

  .const int    frog = 4                       # 整数
  .const string name = "Superintendent Parrot" # 文字列
  .const num    pi   = 3.14159                 # 小数

=end PIR_FRAGMENT

リテラルを使うことのできる場所のどこででも名前のある定数を使うこともできるが,名前のある定数は事前に宣言されていなければならない.これは名前のある文字列定数C<hello>を宣言し,その値をプリントしている例です:

=begin PIR_FRAGMENT

  .const string hello = "Hello, Polly."
  say hello

=end PIR_FRAGMENT

=head2 キィ

X<keys>
キィは(配列のような)複雑な変数の中の要素にアクセスするために使われる特別な種類の定数です.キィは,整数か文字列のどちらかで,常に角括弧(C<[> and C<]>)で囲まれています.リテラルキィを宣言する必要はありません.このコード例では,5の要素として"foo" という文字列を$P0 の中に保持して,それを参照しています.

=begin PIR_FRAGMENT

  $P0[5] = "foo"
  $S1    = $P0[5]

=end PIR_FRAGMENT

PIR 複数の部分を持つキィをサポートします.部分のそれぞれを分けるために,セミコロンを使います.

=begin PIR_FRAGMENT

  $P0['my';'key'] = 472
  $I1             = $P0['my';'key']

=end PIR_FRAGMENT

=head2 制御構造

X<control structures>X<goto instruction>
C<if>C<while>のような用意された制御構造のパッケージを提供するよりも,PIR はブロック自分で構築するためのものを提供します.N<PIR は,多くの先進的な機能を持つが,本質的にはアセンブリ言語なので>ブロックを構築する最も基本的なことは,C<goto> であり,これはそこから名前のあるラベルへジャンプします.N<これは父親のC<goto> ではありません.これは,サブルーチンの中と名前のあるラベルへとジャンプすることができるだけです.> このコード例の場合,C<say> 文はC<goto> 文の後にすぐに実行されます:

=begin PIR_FRAGMENT

    goto GREET
      # ... some skipped code ...
  GREET:
    say "'Allo, 'allo, 'allo."

=end PIR_FRAGMENT

X<conditional branch>
基本的なC<goto> のバリエーションは,ジャンプする前に特定の条件が真か偽かをチェックします.:

=begin PIR_FRAGMENT_INVALID

  if $I0 > 5 goto GREET

=end PIR_FRAGMENT_INVALID

PIR 内蔵の制御構造から伝統的な制御構造を構築することができる.

=head2 サブルーチン

X<subroutines>
PIR のサブルーチンは,C<.sub> ディレクティブで始まり, C<.end> ディレクティブで終わる.パラメータの宣言はC<.param>ディレクティブを使い,それらは名前のある変数の宣言に似ている.この例は,C<greeting>という名前のサブルーチンを宣言しており,C<hello> という1つの文字列型のパラメータを受け取る:

=begin PIR

  .sub 'greeting'
      .param string hello
      say hello
  .end

=end PIR

=head2 That's All Folks

PIR について知るべきことは全て知ることができました.ここでPIR について読んだり習ったことの以外のすべては,これら基本的な言語構造のどれかを使っています.残りはボキャブラリィです.

=begin sidebar Parrot アセンブリ言語

Parrot アセンブリ言語(PASM) は,バーチャルマシンでの別の底レベルな言語ネイティブです.PASM は,PIRをライブラリ開発で親切にしているシンタックスシュガーを持たない純粋なアセンブリ言語ですPASM の主要な目的はバイトコード形式を単純な英語表現として振る舞うことである.これの典型的な使用は,ライブラリを書くためというよりもむしろデバッグの為である.開発タスクに対しては,PIR や高いレベルの言語を使いなさい.

PASM ファイルは,F<.pasm>ファイル拡張子を使います.

=end sidebar

=cut

# Local variables:
#   c-file-style: "parrot"
# End:
# vim: expandtab shiftwidth=4:

parrot-3.6.0/docs/book/pir/ch04_variables.pod

=pod

=head1 変数

Parrot レジスタベースのバーチャルマシンです.4つの型のレジスタがあります.整数,小数,文字列,オブジェクトです.PIR の全ての変数はそれら4つの型のいづれかです.レジスタ変数や名前のある変数を使う場合,バーチャルマシン上でレジスタを保存する位置に直接働きかけます.

以前にアセンブリ言語を使ったことがあれば,C<$I0> がレジスタのうち零番の整数レジスタであることがすぐに結論として思い付くでしょう.それと Parrot はそれらよりは少しだけスマートです.レジスタ変数の数は必ずしも内部的に使用されるレジスタの数に対応しません.Parrot のコンパイラはレジスタを速度とメモリを考慮して適切に対応付けます.
Parrot が唯一保証することは,同じサブルーチン上でC<$I0>を使った場合,常に同じ格納場所を差すということだけです.

=head2 代入

X<assignment>
X<= operator>
変数に対する最も基本的な操作はC<=> 演算子を使った代入です:

=begin PIR_FRAGMENT

  $I0 = 42        # 値42 に整数変数を設定している
  $N3 = 3.14159   # パイの近似値を小数変数に設定している
  $I1 = $I0       # $I0 の値を $I1 に設定している

=end PIR_FRAGMENT

X<null opcode>
C<null> オペコードは整数,小数変数を零値に設定し,文字列,オブジェクト変数を未定義にします.

=begin PIR_FRAGMENT

  null $I0  # 0
  null $N0  # 0.0
  null $S0  # NULL
  null $P0  # PMCNULL

=end PIR_FRAGMENT

=head2 数を使う

X<integers>X<numbers (floating-point)>
PIR は,整数と小数と数として扱える PMC を一緒に扱うための拡張命令を持っています.それらの命令の多くは,その場で結果を修正するための引数を取ります:

=begin PIR_FRAGMENT

  $I0 = $I1 + $I2
  $I0 += $I1

=end PIR_FRAGMENT

X<+ operator>
1番目の例のC<+> は,2つの引数の合計を結果として変数 C<$I0> に保持します.2番目の式 C<+=> は,1つの引数をC<$I0>に加えて,合計をC<$I0>に保存します.

引数は,Parrot リテラル,変数,定数になりえます.C<$I0> のように結果が整数型であるならば,引数は整数でなければならない.C<$N0>のように結果が小数であれば,小数引数を要求します.小数用の命令は最後の引数として整数も許容します.PMC を結果とする命令は,整数,小数,PMC を最後の引数として受け付けることができます:

=begin PIR_FRAGMENT

  $P0 = $P1 * $P2
  $P0 = $P1 * $I2
  $P0 = $P1 * $N2
  $P0 *= $P1
  $P0 *= $I1
  $P0 *= $N1

=end PIR_FRAGMENT

=head3 単項数値用オペコード

X<unary numeric opcodes>
単項オペコードは,1つの引数を持ちます.結果を返す,又は,その場で引数を変更します.最も一般的な単項小数オペコードとしてC<inc>(インクリメント)X<inc opcode>C<dec>(デクリメント)X<dec
opcode>,C<abs>(絶対値化)X<abs opcode>C<neg>(正負反転)X<neg
opcode>:

=begin PIR_FRAGMENT

  $N0 = abs -5.0  # -5.0 の絶対値は 5.0
  $I0 = 120
  inc $I1         # 120 を 1 インクリメントすると 121

=end PIR_FRAGMENT

=head3 二項数値用オペコード

X<binary numeric opcodes>

二項オペコードは,2つの引数と結果を持ちます.Parrot は,加算 (C<+>X<+ operator>又は,C<add>X<add opcode>),減算(C<->X<- operator> 又は, C<sub>X<sub opcode>),乗算(C<*>X<*
operator> 又は,C<mul>X<mul opcode>),除算(C</>X</ operator> 又は,
C<div>X<div opcode>),剰余(C<%>X<% operator> 又は,C<mod>X<mod
opcode>),指数(C<pow>X<pow opcode>)オペコード と 同様に最大公約数(GCD) (C<gcd>X<gcd opcode>)と 最小公倍数(LCM) (C<lcm>X<lcm opcode>)オペコード を提供します.

=begin PIR_FRAGMENT

  $I0 = 12 / 5
  $I0 = 12 % 5

=end PIR_FRAGMENT

=head3 小数用演算

最も一般的な小数演算は,C<ln>X<ln opcode> (自然対数),
C<log2>X<log2 opcode> (l2を底とするログ), C<log10>X<log10 opcode> (10 を底とするログ),
C<exp>X<exp opcode> (I<e>G<x>) (x を底とする), 三角関数オペコードの全部 C<sin>X<sin opcode> (サイン), C<cos>X<cos opcode> (コサイン), C<tan>X<tan
opcode> (タンジェント), C<sec>X<sec opcode> (secant), C<sinh>X<sinh opcode>
(ハイパボリックサイン), C<cosh>X<cosh opcode> (ハイパボリックコサイン), C<tanh>X<tanh
opcode> (ハイパボリックタンジェント), C<sech>X<sech opcode> (hyperbolic secant),
C<asin>X<asin opcode> (アークサイン), C<acos>X<acos opcode> (アークコサイン),
C<atan>X<atan opcode> (アークタンジェント), C<asec>X<asec opcode> (arc secant),
C<exsec>X<exsec opcode> (exsecant), C<hav>X<hav opcode> (haversine), and
C<vers>X<vers opcode> (versine) です.X<trigonometric
opcodes>三角関数の全ての角度変数は,ラジアンです:

=begin PIR_FRAGMENT_INVALID

  .loadlib 'trans_ops'

  # ...

  $N0 = sin $N1
  $N0 = exp 2

=end PIR_FRAGMENT_INVALID

小数演算の大多数は,1引数で1つの結果を返します.引数は,一般的に整数か小数のどちらかであり,それらのオペコードは結果として小数を要求します.

=head3 論理演算,ビット演算

X<logical opcodes>
論理オペコードは,引数の真偽を評価します.制御フローでの決定をする部分で,最も役に立ちます.整数と数値的なPMC は,0 であれば偽,それ以外ならば真になります.文字列は,それが空文字列であるか,1つの文字"0" である場合は偽,それ以外は真です.PMC は,それ自身のvtable 関数 C<get_bool>X<get_bool vtable
function> が非負の値を返す場合に真です.

C<and>X<and opcode> オペコードは,第一引数が偽である場合と,第二引数がそうでない場合は,第一引数を返します.

=begin PIR_FRAGMENT

  $I0 = and 0, 1  # 0 を返す
  $I0 = and 1, 2  # 2 を返す

=end PIR_FRAGMENT

C<or>X<or opcode> オペコードは,第一引数が真の場合と,第二引数がそうでない場合は,第一引数を返します:

=begin PIR_FRAGMENT_INVALID

  .loadlib 'bit_ops'

  # ...

  $I0 = or 1, 0  # 1 を返す
  $I0 = or 0, 2  # 2 を返す

  $P0 = or $P1, $P2

=end PIR_FRAGMENT_INVALID

C<and>C<or> は,短絡演算子です.第一引数で返す値が決定できる場合,第二引数を評価しません.評価中に副作用があるかもしれないので,これはPMC に対しては重要な意味を持ちます.

C<xor>X<xor opcode> オペコードは,第一引数が真である場合にのみ,第一引数を返し,第二引数が真の場合にのみ第二引数を返します.そして,両方の値が真,又は偽の場合には,偽を返します:

=begin PIR_FRAGMENT

  $I0 = xor 1, 0  # 1 を返す
  $I0 = xor 0, 1  # 1 を返す
  $I0 = xor 1, 1  # 0 を返す
  $I0 = xor 0, 0  # 0 を返す

=end PIR_FRAGMENT

C<not>X<not opcode> オペコードは,引数が偽の場合に真を返し,引数が真の場合に偽を返します:

=begin PIR_FRAGMENT

  $I0 = not $I1
  $P0 = not $P1

=end PIR_FRAGMENT

X<bitwise opcodes>
ビット演算のオペコードは,一度にその値の単一のbit を処理します.C<band>X<band opcode>, C<bor>X<bor opcode>, and C<bxor>X<bxor opcode> は,引数に応じてそれぞれのビットに論理積,和,排他的論理和値した値を返します.それらは全て2つの引数を取ります.

=begin PIR_FRAGMENT_INVALID

  .loadlib 'bit_ops'

  # ...

  $I0 = bor $I1, $I2
  $P0 = bxor $P1, $I2

=end PIR_FRAGMENT_INVALID

C<band>, C<bor>, and C<bxor> も,同じ場所に変更した結果を保存します.

=begin PIR_FRAGMENT_INVALID

  .loadlib 'bit_ops'

  # ...

  $I0 = band $I1
  $P0 = bor $P1

=end PIR_FRAGMENT_INVALID

C<bnot>X<bnot opcode> は,引数の中の全てのビットの論理的否定です.

=begin PIR_FRAGMENT_INVALID

  .loadlib 'bit_ops'

  # ...

  $I0 = bnot $I1

=end PIR_FRAGMENT_INVALID

X<shl opcode>
X<shr opcode>
X<lsr opcode>
論理的で数学的なシフトは,与えられた数値分のビットを操作します.:

=begin PIR_FRAGMENT_INVALID

  .loadlib 'bit_ops'

  # ...

  $I0 = shl $I1, $I2        # shift $I1 left by count $I2
  $I0 = shr $I1, $I2        # arithmetic shift right
  $P0 = lsr $P1, $P2        # logical shift right

=end PIR_FRAGMENT_INVALID

=head2 文字列を扱う

X<strings>
Parrot 文字列は,可変サイズのデータのバッファです.文字列の最も一般的な使い方は,テキストデータを保持することです.文字列は,バイナリィやテキストでないデータも保持することができますが,そうすることはまれです.N<一般的に言えば,カスタマイズされたPMC の方がより便利です.> Parrot 文字列は,人間が読める(コンピュータで表現可能な)テキストデータの複雑さを取り扱うことができるくらい柔軟で強力です.文字列演算子は,文字列リテラル,変数,定数,文字列扱いできるPMC で動作します.

=head3 エスケープシーケンス

X<string escapes>
X<escape sequences>

ダブルクォートの中の文字列は,バックスラッシュを用いたエスケープシーケンスを書くことができます.シングルクォートの中の文字列は,ネストされたクォートに対してのエスケープのみ許可されています.

  $S0 = "This string is \n on two lines"
  $S0 = 'This is a \n one-line string with a slash in it'

表 4.1 は,ダブルクォート文字列の中でParrot がサポートしているエスケープシーケンスを示しています.

=begin table String Escapes

=headrow

=row

=cell エスケープ

=cell 意味

=bodyrows

=row

=cell C<\a>

=cell アラーム文字 (ASCII)

=row

=cell C<\b>

=cell バックスラッシュ文字 (ASCII)

=row

=cell C<\t>

=cell タブ

=row

=cell C<\n>

=cell 改行

=row

=cell C<\v>

=cell 垂直タブ

=row

=cell C<\f>

=cell A form feed

=row

=cell C<\r>

=cell 復帰

=row

=cell C<\e>

=cell エスケープ

=row

=cell C<\\>

=cell バックスラッシュ

=row

=cell C<\">

=cell クォート

=row

=cell C<\x>R<NN>

=cell 1桁又は2桁の16進数で表現される文字

=row

=cell C<\x{>R<NNNNNNNN>C<}>

=cell 1桁から8桁の16進数で表現される文字

=row

=cell C<\o>R<NNN>

=cell 1桁から3桁の8進数で表現される文字

=row

=cell C<\u>R<NNNN>

=cell 4桁の16進数で表現される文字

=row

=cell C<\U>R<NNNNNNNN>

=cell 8桁の16進数で表現される文字

=row

=cell C<\c>R<X>

=cell コントロール文字R<X>

=end table

=head3 ヒアドキュメント

X<heredocs>
文字列の定義においてより柔軟さを必要とする場合,ヒアドキュメント文字列リテラルを使うこともできる.C<E<lt>E<lt>> 演算子がヒアドキュメントを開始します.文字列終端をすぐに続けます.終端まで全てのテキストが文字列の部分になります.終端は,自身の行に現われなければなりませんし,行の開始に無ければなりませんし,続く空白もあってはいけません.

  $S2 = <<"End_Token"
  This is a multi-line string literal. Notice that
  it doesn't use quotation marks.
  End_Token

=head3 文字列連結

X<. operator>
X<strings;concatenation>

文字列の連結するためには C<.> 演算子を使います.以下の例は,文字列 "ab" に 文字列 "cd" を連結し,結果を C<$S1> に保存しています.

=begin PIR_FRAGMENT

  $S0 = "ab"
  $S1 = $S0 . "cd"  # concatenates $S0 with "cd"
  say $S1           # prints "abcd"

=end PIR_FRAGMENT

X<.= operator>
連結は,その場での結果の上書きを右辺値にするためにC<.=> もあります.次の例では,C<.=> 演算子はC<$S1> の中の文字列"abcd"に "xy" を加えます.

=begin PIR_FRAGMENT

  $S1 .= "xy"       # appends "xy" to $S1
  say $S1           # prints "abcdxy"

=end PIR_FRAGMENT

=head3 文字列の繰り返し

X<repeat opcode>
C<repeat> オペコードは,指定した数の回数だけ文字列を繰り返します:

=begin PIR_FRAGMENT

  $S0 = "a"
  $S1 = repeat $S0, 5
  say $S1              # prints "aaaaa"

=end PIR_FRAGMENT

この例では,C<repeat> は,"a" を5回繰り返した新しい文字列を生成し,それをC<$S1> に格納します.

=head3 文字列の長さ

X<length opcode>
C<length> オペコードは,文字列の文字での長さを返します.これは,多バイトエンコード済み文字列に対しては I<bytes>での長さと同じではありません.

=begin PIR_FRAGMENT

  $S0 = "abcd"
  $I0 = length $S0                # the length is 4
  say $I0

=end PIR_FRAGMENT

C<length> は,PMC 文字列と等価ではありません.

=head3 部分文字列

C<substr>X<substr opcode> オペコードの最も単純なバージョンは,3つの引数,元の文字列,オフセット位置,長さを取ります.それは,オフセット位置(0が最初の文字)から長さを測ったオリジナルの文字列からの部分文字列を返します:

=begin PIR_FRAGMENT

  $S0 = substr "abcde", 1, 2        # $S0 is "bc"

=end PIR_FRAGMENT

この例では,"abcde" から文字列の最初から1文字のオフセット(2番目の文字で開始する)で2文字の文字列を抽出します.これは新しい文字列"bc" を宛先レジスタ C<$S0> の中に生成します.

オフセット位置が負数の場合,文字列の終端から逆方向に数えます.そのため,-1 のオフセットは,文字列の最後の文字から開始します.

その場での文字列操作は削除されましたので,C<substr> は,もう4つの引数の形式を持っていません.置き換えと元の文字列を修正することなしに新しい文字列を返すことを実現する C<replace> 演算子があります.引数は,new_string,old_string,offset,count,replacement_string です.old_string は,offset から count の文字だけ内容を replacement_string に置き換えられ new_string コピーされます.

この例では,C<$S1> の中の部分文字列 "bc" を"XYZ" に置き換え,C<$S0> に"aXYZde" を返します.C<$S1> に変更はありません:

=begin PIR_FRAGMENT

  $S1 = "abcde"
  $S0 = replace $S1, 1, 2, "XYZ"
  say $S0                        # prints "aXYZde"
  say $S1                        # prints "abcde"

=end PIR_FRAGMENT

C<replace> のオフセット位置が元の文字列の長さを1文字超えている場合,C<replace> は,ただの連結演算子のように置き換え文字列を加えます.置き換え文字列が空文字列の場合,オペコードは元の文字列から新しい文字列に文字を削除します.

=begin PIR_FRAGMENT

  $S1 = "abcde"
  $S1 = replace $S1, 1, 2, "XYZ"
  say $S1                        # prints "aXYZde"

=end PIR_FRAGMENT

=head3 文字の変換

C<chr>X<chr opcode> オペコードは,整数値を受け取り,ASCII 文字集合から対応する文字を1文字の文字列として返します.C<ord>X<ord opcode> オペコードは,1つの文字を受け取り,文字列の最初の位置の文字の整数値を返します.文字の整数値は,文字列の現在のエンコードに依存して異なる:

=begin PIR_FRAGMENT

  $S0 = chr 65              # $S0 is "A"
  $I0 = ord $S0             # $I0 is 65, if $S0 is ASCII/UTF-8

=end PIR_FRAGMENT

C<ord> は,複数文字の文字列から1つの文字を選択し,1文字を選択するための文字のオフセットを受け取る 2つの引数を持つ.オフセットは,文字列の長さの範囲内でなければならない:

=begin PIR_FRAGMENT

  $I0 = ord "ABC", 2        # $I0 is 67

=end PIR_FRAGMENT

負のオフセットは,文字列の終端から逆方向に数える.そのため-1 は最後の文字である.

=begin PIR_FRAGMENT

  $I0 = ord "ABC", -1       # $I0 is 67

=end PIR_FRAGMENT

=head3 フォーマット文字列

X<strings;formatting>

The C<sprintf>X<sprintf opcode> opcode generates a formatted string from a
series of values. It takes two arguments: a string specifying the format, and
an array PMC containing the values to be formatted. The format string and the
result can be either strings or PMCs:

=begin PIR_FRAGMENT

  $S0 = sprintf $S1, $P2
  $P0 = sprintf $P1, $P2

=end PIR_FRAGMENT

The format string is similar to C's C<sprintf> function with extensions for
Parrot data types. Each format field in the string starts with a C<%> and ends
with a character specifying the output format. Table 4.2 lists the available
output format characters.

=begin table Format characters

=headrow

=row

=cell Format

=cell 意味

=bodyrows

=row

=cell C<%c>

=cell A single character.

=row

=cell C<%d>

=cell A decimal integer.

=row

=cell C<%i>

=cell A decimal integer.

=row

=cell C<%u>

=cell An unsigned integer.

=row

=cell C<%o>

=cell An octal integer.

=row

=cell C<%x>

=cell A hex integer, preceded by 0x (when # is specified).

=row

=cell C<%X>

=cell A hex integer with a capital X (when # is specified).

=row

=cell C<%b>

=cell A binary integer, preceded by 0b (when # is specified).

=row

=cell C<%B>

=cell A binary integer with a capital B (when # is specified).

=row

=cell C<%p>

=cell A pointer address in hex.

=row

=cell C<%f>

=cell A floating-point number.

=row

=cell C<%e>

=cell A floating-point number in scientific notation (displayed with a
lowercase "e").

=row

=cell C<%E>

=cell The same as C<%e>, but displayed with an uppercase E.

=row

=cell C<%g>

=cell The same as C<%e> or C<%f>, whichever fits best.

=row

=cell C<%G>

=cell The same as C<%g>, but displayed with an uppercase E.

=row

=cell C<%s>

=cell A string.

=end table

Each format field supports several specifier options: R<flags>, R<width>,
R<precision>, and R<size>.  Table 4.3 lists the format flags.

=begin table Format flags

=headrow

=row

=cell Flag

=cell 意味

=bodyrows

=row

=cell 0

=cell Pad with zeros.

=row

=cell E<lt>spaceE<gt>

=cell Pad with spaces.

=row

=cell C<+>

=cell Prefix numbers with a sign.

=row

=cell C<->

=cell Align left.

=row

=cell C<#>

=cell Prefix a leading 0 for octal, 0x for hex, or force a decimal point.

=end table

The R<width> is a number defining the minimum width of the output from
a field. The R<precision> is the maximum width for strings or
integers, and the number of decimal places for floating-point fields.
If either R<width> or R<precision> is an asterisk (C<*>), it takes its
value from the next argument in the PMC.

The R<size> modifier defines the type of the argument the field takes.
Table 4.4 lists the size flags. The values in the aggregate PMC must
have a type compatible with the specified R<size>.

=begin table Size flags

=headrow

=row

=cell Character

=cell 意味

=bodyrows

=row

=cell C<h>

=cell short integer or single-precision float

=row

=cell C<l>

=cell long

=row

=cell C<H>

=cell huge value (long long or long double)

=row

=cell C<v>

=cell Parrot INTVAL or FLOATVAL

=row

=cell C<O>

=cell opcode_t pointer

=row

=cell C<P>

=cell C<PMC>

=row

=cell C<S>

=cell String

=end table


=begin PIR_FRAGMENT

  $S0 = sprintf "int %#Px num %+2.3Pf\n", $P2
  say $S0       # prints "int 0x2a num +10.000"

=end PIR_FRAGMENT

The format string of this C<sprintf> example has two format fields. The first,
C<%#Px>, extracts a PMC argument (C<P>) from the aggregate C<$P2> and formats
it as a hexadecimal integer (C<x>) with a leading 0x (C<#>). The second format
field, C<%+2.3Pf>, takes a PMC argument (C<P>) and formats it as a
floating-point number (C<f>) with a minimum of two whole digits and a maximum
of three decimal places (C<2.3>) and a leading sign (C<+>).


The test files F<t/op/string.t> and F<t/op/sprintf.t> have many more
examples of format strings.

=head3 文字列の連結

C<join>X<join opcode> オペコードは,配列 PMC の要素を1つの文字列に結合します.第一引数は,最後の結果の文字列中でPMC の各要素を区切ります.

=begin PIR_FRAGMENT

  $P0 = new "ResizablePMCArray"
  push $P0, "hi"
  push $P0, 0
  push $P0, 1
  push $P0, 0
  push $P0, "parrot"
  $S0 = join "__", $P0
  say $S0                # prints "hi__0__1__0__parrot"

=end PIR_FRAGMENT

この例は,C<$P0>C<"hi">C<0>C<1>C<0>C<"parrot">の入った C<Array> を作ます.それらの値を(C<"_"> 文字列で区切って) 1つの文字列にして連結して C<$S0> に格納します.

=head3 文字列の分割

文字列を分割することで,元の文字列の部分文字列を含む新しい配列ができます.

この例では,"abc" 文字列を個別の文字に分割し,それらを C<$P0> の中に配列の中に格納します.配列の1番目と3番目の要素を印字します.

=begin PIR_FRAGMENT

  $P0 = split "", "abc"
  $P1 = $P0[0]
  say $P1                # 'a'
  $P1 = $P0[2]
  say $P1                # 'c'

=end PIR_FRAGMENT

=head3 部分文字列の比較

C<index>X<index opcode> オペコードは文字列の中で部分文字列を探します.部分文字列が見付かれば,部分文字列が見付かった場所を文字列の開始からの文字オフセットとして返します.文字列を探すのに失敗すれば,-1 を返します.

=begin PIR_FRAGMENT

  $I0 = index "Beeblebrox", "eb"
  say $I0                           # prints 2
  $I0 = index "Beeblebrox", "Ford"
  say $I0                           # prints -1

=end PIR_FRAGMENT

C<index> は,3つの引数を取るバージョンもあります.最後の引数は検索の開始位置を定義します.

=begin PIR_FRAGMENT

  $I0 = index "Beeblebrox", "eb", 3
  say $I0                           # prints 5

=end PIR_FRAGMENT

この例では,検索が文字列の最初の3つの文字をスキップしているので "Beeblebrox" の中の1番目ではなくて2番目の"eb" を探します.

=head3 ビット演算

The numeric bitwise opcodes also have string variants for AND, OR, and XOR:
C<bors>X<bors opcode>, C<bands>X<bands opcode>, and C<bxors>X<bxors opcode>.
These take string or string-like PMC arguments and perform the logical
operation on each byte of the strings to produce the result string.
Remember that in-place string operations are no longer available.

=begin PIR_FRAGMENT_INVALID

  .loadlib 'bit_ops'

  # ...

  $P0 = bors $P1
  $P0 = bands $P1
  $S0 = bors $S1, $S2
  $P0 = bxors $P1, $S2

=end PIR_FRAGMENT_INVALID

The bitwise string opcodes produce meaningful results only when used with
simple ASCII strings, because Parrot performs bitwise operations per byte.

=head3 Copy-On-Write

文字列は,コピーオンライト(COW)X<copy-on-write>X<COW (copy-on-write)>最適化を使います.C<$S1 = $S0> の呼び出しは,すぐにC<$S0> のコピーをする訳ではありません.これは両方の変数の位置を同じ文字列にします.Parrot は,2つの文字列のうち1つが変更されるまで文字列のコピーをしません.

=begin PIR_FRAGMENT

  $S0 = "Ford"
  $S1 = $S0
  $S1 = "Zaphod"
  say $S0                # prints "Ford"
  say $S1                # prints "Zaphod"

=end PIR_FRAGMENT

2つの変数のうち一方が変更によって,Parrot は新しい文字列を生成します.この例では,C<$S0> の中の既存の値を保存し,C<$S1> の中に新しい文字列に新しい値を割り当てます.コピーオンライトの利点は,コピーが必要になるまで文字列のコピーのコストを避けられることです.

=head3 エンコードと文字

X<charset>
X<ASCII character set>
X<encoding>
何年も前は,文字列としてシンボルと英語の文字の128 のビットパターンの対応のASCII 文字セット(キャラセット)のサポートのみ必要だった.コンピュータを使う全ての人が英語を読み書きし,少しだけ句読点シンボルを使うだけである限りは,これはうまく働いていた.言い換えれば,これだけじゃ全然不十分だ.今の文字列のシステムは,世界中の文字列データの全てを扱えるために文字セットも使う必要がある.A modern string system must also handle different encodings --
ways to represent various charsets in memory and on disk.

Every string in Parrot has an associated encoding and character set. The default
format is 8-bit ASCII, which is almost universally supported.  Double-quoted
string constants can have an optional prefix specifying the string's
format.N<As you might suspect, single-quoted strings do not support this.>
Parrot tracks information about encoding and charset internally, and
automatically converts strings when necessary to preserve these
characteristics. Strings constants may have prefixes of the form C<format:>.

=begin PIR_FRAGMENT

  $S0 = utf8:"Hello UTF-8 Unicode World!"
  $S1 = utf16:"Hello UTF-16 Unicode World!"
  $S2 = ascii:"This is 8-bit ASCII"
  $S3 = binary:"This is raw, unformatted binary data"

=end PIR_FRAGMENT

X<ISO 8859-1 character set>
X<Latin 1 character set>
X<UCS-2 encoding>
X<UTF-8 encoding>
X<UTF-16 encoding>
Parrot supports the formats C<ascii>, C<binary>, C<iso-8859-1>
(Latin 1), C<utf8>, C<utf16>, C<ucs2>, and C<ucs4>.

The C<binary> format treats the string as a buffer of raw unformatted
binary data. It isn't really a string per se, because binary data
contains no readable characters. This exists to support libraries which
manipulate binary data that doesn't easily fit into any other primitive
data type.

Parrot が2つの文字列に対する演算(連結や比較のような) をする場合,それらの両方が同じ文字セットとエンコーディングを使っていなければならない.Parrot は,必要であれば最も高い互換性を持った形式へ自動的に一方又は両方の文字列を昇格させます.ASCII strings will automatically upgrade to UTF-8 strings if needed,
and UTF-8 will upgrade to UTF-16.  それらの変換は,全てParrot の中で起こり,プログラマはその詳細について意識する必要はありません.

=head2 PMC を使う

X<Polymorphic Containers (PMCs)>
X<PMCs (Polymorphic Containers)>
多態コンテナ(PMC) は,Parrot での複雑なデータ型とオブジェクト指向的な振舞いの基礎です.PIR では,低レベルの整数,小数,文字列でない全ての変数がPMC です.PMC 変数は,低レベル変数と同じように動作しますが,それを使う前に 新しい PMC オブジェクトのインスタンス化が必要です.C<new> オペコードは,指定された型の新しいPMC オブジェクトを生成します.

=begin PIR_FRAGMENT

  $P0 = new 'String'
  $P0 = "That's a bollard and not a parrot"
  say $P0

=end PIR_FRAGMENT

この例では,C<String> オブジェクトを生成し,PMC レジスタ変数C<$P0> に格納し,それに 値 "That's bollard and not a parrot" を代入し,それをプリントしています.

全ての PMC は,どんなデータを保持できるかとそれがどんな振舞いをサポートするか示す型を持っています.C<typeof>X<typeof opcode> オペコードは,PMC の型について教えてくれます.結果は文字列変数である場合,C<typeof> は型の名前を返します:

=begin PIR_FRAGMENT

  $P0 = new "String"
  $S0 = typeof $P0               # $S0 is "String"
  say $S0                        # prints "String"

=end PIR_FRAGMENT

結果がPMC 変数の場合,オブジェクト型に対して C<typeof>C<Class> PMC を返します.

=head3 スカラ

X<scalar PMCs>
X<PMCs (Polymorphic Containers);scalar>
今までに示してきた最も一般的な例では,PMC は整数,小数,文字列の振舞いの再現していました.Parrot は,PMC に対して正確な目的を提供します.C<Integer>, C<Float>, C<String> は,Parrot の低レベルな整数,小数,文字列の薄いラッパーです.

以前の例では,型C<String> のPMC 変数に代入された文字列リテラルを示しました.PMC へのリテラルの直接代入は,全て低レベル型とそれらのPMC の等価なものに対して動作します:

=begin PIR_FRAGMENT

  $P0 = new 'Integer'
  $P0 = 5

  $P1 = new 'String'
  $P1 = "5 birds"

  $P2 = new 'Float'
  $P2 = 3.14

=end PIR_FRAGMENT

X<boxing>

定数でない低レベルな整数,小数,文字列のレジスタをPMC へと直接代入するかもしれません.PMC は,低レベルタイプからそれ自身の内部ストレージへの変換を扱います.N<単純な型から複雑な型へのこの変換は"boxing" です.>

=begin PIR_FRAGMENT

  $I0 = 5
  $P0 = new 'Integer'
  $P0 = $I0

  $S1 = "5 birds"
  $P1 = new 'String'
  $P1 = $S1

  $N2 = 3.14
  $P2 = new 'Float'
  $P2 = $N2

=end PIR_FRAGMENT

C<box> オペコードは,整数,小数,文字列リテラルや変数から適切なPMC オブジェクトを生成するための使い易いショートカットです.

=begin PIR_FRAGMENT

  $P0 = box 3    # $P0 is an "Integer"

  $P1 = box $S1  # $P1 is a "String"

  $P2 = box 3.14 # $P2 is a "Float"

=end PIR_FRAGMENT

X<unboxing>
逆の状況では,つまり整数,小数,文字列変数へPMC を代入する場合では,PMC にもその値を低レベル型へ変換する能力があります.N<"boxing" の反対は"unboxing" です.>

=begin PIR_FRAGMENT

  $P0 = box 5
  $S0 = $P0           # the string "5"
  $N0 = $P0           # the number 5.0
  $I0 = $P0           # the integer 5

  $P1 = box "5 birds"
  $S1 = $P1           # the string "5 birds"
  $I1 = $P1           # the integer 5
  $N1 = $P1           # the number 5.0

  $P2 = box 3.14
  $S2 = $P2           # the string "3.14"
  $I2 = $P2           # the integer 3
  $N2 = $P2           # the number 3.14

=end PIR_FRAGMENT

This example creates C<Integer>X<Integer PMC>, C<Float>X<Float PMC>,
and C<String>X<String PMC> PMCs, and shows the effect of assigning each
one back to a low-level type.

Converting a string to an integer or number only makes sense when the contents
of the string are a number. The C<String> PMC will attempt to extract a number
from the beginning of the string, but otherwise will return a false value.

=begin sidebar Type Conversions

X<type conversions>
Parrot also handles conversions between the low-level types where
possible, converting integers to strings (C<$S0 = $I1>),
numbers to strings (C<$S0 = $N1>), numbers to integers (C<$I0 = $N1>),
integers to numbers (C<$N0 = $I1>), and even strings to integers or
numbers (C<$I0 = $S1> and C<$N0 = $S1>).

=end sidebar

=head3 集約

X<aggregate PMCs>
X<PMCs (Polymorphic Containers);aggregate>
PMC で,複数の値を保持する複雑な型を定義できます.一般的には集約と呼びます.2つの基本の集約型は順序付き配列と連想配列です.The primary difference between these is that ordered arrays use integer
keys for indexes and associative arrays use string keys.

Aggregate PMCs support the use of numeric or string keys.  PIR also offers a
extensive set of operations for manipulating aggregate data types.

=head4 順序付き配列

X<arrays>
X<ordered arrays>
Parrot provides several ordered array PMCs, differentiated by whether
the array should store booleans, integers, numbers, strings, or other
PMCs, and whether the array should maintain a fixed size or dynamically
resize for the number of elements it stores.

The core array types are C<FixedPMCArray>, C<ResizablePMCArray>,
C<FixedIntegerArray>, C<ResizableIntegerArray>, C<FixedFloatArray>,
C<ResizableFloatArray>, C<FixedStringArray>, C<ResizableStringArray>,
C<FixedBooleanArray>, and C<ResizableBooleanArray>. The array
types that start with "Fixed" have a fixed size and do not allow
elements to be added outside their allocated size. The "Resizable"
variants automatically extend themselves as more elements are
added.N<With some additional overhead for checking array bounds and
reallocating array memory.> The array types that include "String",
"Integer", or "Boolean" in the name use alternate packing methods for
greater memory efficiency.

Parrot's core ordered array PMCs all have zero-based integer keys. Extracting
or inserting an element into the array uses PIR's standard key syntax, with the
key in square brackets after the variable name. An lvalue key sets the value
for that key.  An rvalue key extracts the value for that key in the aggregate
to use as the argument value:

=begin PIR_FRAGMENT

  $P0    = new "ResizablePMCArray" # create a new array object
  $P0[0] = 10                      # set first element to 10
  $P0[1] = $I31                    # set second element to $I31
  $I0    = $P0[0]                  # get the first element

=end PIR_FRAGMENT

Setting the array to an integer value directly (without a key) sets the number
of elements of the array.  Assigning an array directly to an integer retrieves
the number of elements of the array.

=begin PIR_FRAGMENT

  $P0 = 2    # set array size
  $I1 = $P0  # get array size

=end PIR_FRAGMENT

This is equivalent to using the C<elements> opcode to retrieve the number of
items currently in an array:

=begin PIR_FRAGMENT

  elements $I0, $P0 # get element count

=end PIR_FRAGMENT

Some other useful instructions for working with ordered arrays are
C<push>, C<pop>, C<shift>, and C<unshift>, to add or remove elements.
C<push> and C<pop> work on the end of the array, the highest numbered
index. C<shift> and C<unshift> work on the start of the array, adding or
removing the zeroth element, and renumbering all the following elements.

=begin PIR_FRAGMENT

  push $P0, 'banana' # add to end
  $S0 = pop $P0      # fetch from end

  unshift $P0, 74    # add to start
  $I0 = shift $P0    # fetch from start

=end PIR_FRAGMENT

=head4 連想配列

X<associative arrays>
X<hashes>
X<dictionaries>
An associative array is an unordered aggregate that uses string keys to
identify elements.  You may know them as "hash tables", "hashes", "maps", or
"dictionaries". Parrot provides one core associative array PMC, called C<Hash>.
String keys work very much like integer keys.  An lvalue key sets the value of
an element, and an rvalue key extracts the value of an element. The string in
the key must always be in single or double quotes.

=begin PIR_FRAGMENT

  new $P1, "Hash"          # create a new associative array
  $P1["key"] = 10          # set key and value
  $I0        = $P1["key"]  # get value for key

=end PIR_FRAGMENT

Assigning a C<Hash>X<Hash PMC> PMC (without a key) to an integer result
fetches the number of elements in the hash.N<You may not set a C<Hash>
PMC directly to an integer value.>

=begin PIR_FRAGMENT

  $I1 = $P1         # number of entries

=end PIR_FRAGMENT

The C<exists>X<exists opcode> opcode tests whether a keyed value exists in an
aggregate. It returns 1 if it finds the key in the aggregate and 0 otherwise.
It doesn't care if the value itself is true or false, only that an entry exists
for that key:

=begin PIR_FRAGMENT

  new $P0, "Hash"
  $P0["key"] = 0
  exists $I0, $P0["key"] # does a value exist at "key"?
  say $I0                # prints 1

=end PIR_FRAGMENT

The C<delete>X<delete opcode> opcode removes an element from an associative
array:

=begin PIR_FRAGMENT

  delete $P0["key"]

=end PIR_FRAGMENT

=head4 イテレータ

X<iterators>
X<PMCs (Polymorphic Containers); iterators>
イテレータは,1つづつ集約されたPMC から値を取り出します.Iterators are
most useful in loops which perform an action on every element in an aggregate.
The C<iter> opcode creates a new iterator from an aggregate PMC. It takes one
argument, the PMC over which to iterate:

=begin PIR_FRAGMENT

  $P1 = iter $P2

=end PIR_FRAGMENT

The C<shift>X<shift opcode> opcode extracts the next value from the iterator.

=begin PIR_FRAGMENT

      $P5 = shift $P1

=end PIR_FRAGMENT

Evaluating the iterator PMC as a boolean returns whether the iterator has
reached the end of the aggregate:

=begin PIR_FRAGMENT_INVALID

      if $P1 goto iter_repeat

=end PIR_FRAGMENT_INVALID

Parrot provides predefined constants for working with iterators.
C<.ITERATE_FROM_START> and C<.ITERATE_FROM_END> constants select whether an
ordered array iterator starts from the beginning or end of the array.  These
two constants have no effect on associative array iterators, as their elements
are unordered.

Load the iterator constants with the C<.include>X<.include directive>
directive to include the file F<iterator.pasm>. To use them, set the
iterator PMC to the value of the constant:

=begin PIR_FRAGMENT

      .include "iterator.pasm"

      # ...

      $P1 = .ITERATE_FROM_START

=end PIR_FRAGMENT

With all of those separate pieces in one place, this example loads the iterator
constants, creates an ordered array of "a", "b", "c", creates an iterator from
that array, and then loops over the iterator using a conditional C<goto> to
checks the boolean value of the iterator and another unconditional C<goto>:

=begin PIR_FRAGMENT

      .include "iterator.pasm"
      $P2 = new "ResizablePMCArray"
      push $P2, "a"
      push $P2, "b"
      push $P2, "c"

      $P1 = iter $P2
      $P1 = .ITERATE_FROM_START

  iter_loop:
      unless $P1 goto iter_end
      $P5 = shift $P1
      say $P5                        # prints "a", "b", "c"
      goto iter_loop
  iter_end:

=end PIR_FRAGMENT

Associative array iterators work similarly to ordered array iterators.  When
iterating over associative arrays, the C<shift> opcode extracts keys instead of
values. The key looks up the value in the original hash PMC.

=begin PIR_FRAGMENT

      $P2      = new "Hash"
      $P2["a"] = 10
      $P2["b"] = 20
      $P2["c"] = 30

      $P1      = iter $P2

  iter_loop:
      unless $P1 goto iter_end
      $S5 = shift $P1          # the key "a", "b", or "c"
      $I9 = $P2[$S5]           # the value 10, 20, or 30
      say $I9
      goto iter_loop
  iter_end:

=end PIR_FRAGMENT

This example creates an associative array C<$P2> that contains three
keys "a", "b", and "c", assigning them the values 10, 20, and 30. It
creates an iterator (C<$P1>) from the associative array using the
C<iter> opcode, and then starts a loop over the iterator. At the start
of each loop, the C<unless> instruction checks whether the iterator has
any more elements. If there are no more elements, C<goto> jumps to the
end of the loop, marked by the label C<iter_end>. If there are more
elements, the C<shift> opcode extracts the next key. Keyed assignment
stores the integer value of the element indexed by the key in C<$I9>.
After printing the integer value, C<goto> jumps back to the start of the
loop, marked by C<iter_loop>.

=head4 多次元キィ

X<keys>
X<multi-level keys>
集約では,全てのデータ型を保持できます.それには他の集約も含みます.Accessing elements deep within nested data structures is a common
operation, so PIR provides a way to do it in a single instruction.
Complex keys specify a series of nested data structures, with each
individual key separated by a semicolon.

=begin PIR_FRAGMENT

  $P0           = new "Hash"
  $P1           = new "ResizablePMCArray"
  $P1[2]        = 42
  $P0["answer"] = $P1

  $I1 = 2
  $I0 = $P0["answer";$I1]
  say $I0

=end PIR_FRAGMENT

This example builds up a data structure of an associative array
containing an ordered array. The complex key C<["answer"; $I1]>
retrieves an element of the array within the hash. You can also set a
value using a complex key:

=begin PIR_FRAGMENT

  $P0["answer";0] = 5

=end PIR_FRAGMENT

The individual keys are integer or string literals, or variables with
integer or string values.

=head3 コピーとクローン

X<PMCs (Polymorphic Containers); copying vs. cloning>
PMC レジスタは直接PMC のデータを保持している訳ではありません,それらはデータを保持する構造へのポインタのみを保持しています.そのため,C<=> 演算子は,PMC 全体をコピーしません.それはPMC データのポインタのみをコピーします.If you later modify the copy of the variable, it will also
modify the original.

=begin PIR_FRAGMENT

  $P0 = new "String"
  $P0 = "Ford"
  $P1 = $P0
  $P1 = "Zaphod"
  say $P0                # prints "Zaphod"
  say $P1                # prints "Zaphod"

=end PIR_FRAGMENT

In this example, C<$P0> and C<$P1> are both pointers to the same
internal data structure.  Setting C<$P1> to the string literal
"Zaphod", it overwrites the previous value "Ford". Both C<$P0> and
C<$P1> refer to the C<String> PMC "Zaphod".

The C<clone> X<clone opcode> opcode makes a deep copy of a PMC, instead
of copying the pointer like C<=>X<= operator> does.

=begin PIR_FRAGMENT

  $P0 = new "String"
  $P0 = "Ford"
  $P1 = clone $P0
  $P0 = "Zaphod"
  say $P0        # prints "Zaphod"
  say $P1        # prints "Ford"

=end PIR_FRAGMENT

This example creates an identical, independent clone of the PMC in
C<$P0> and puts it in C<$P1>. Later changes to C<$P0> have no effect on
the PMC in C<$P1>.N<With low-level strings, the copies created by
C<clone> are copy-on-writeX<copy-on-write> exactly the same as the copy
created by C<=>.>

To assign the I<value> of one PMC to another PMC that already exists, use the
C<assign>X<assign opcode> opcode:

=begin PIR_FRAGMENT

  $P0 = new "Integer"
  $P1 = new "Integer"
  $P0 = 42
  assign $P1, $P0    # note: $P1 must exist already
  inc $P0
  say $P0            # prints 43
  say $P1            # prints 42

=end PIR_FRAGMENT

This example creates two C<Integer> PMCs, C<$P1> and C<$P2>, and gives the
first one the value 42. It then uses C<assign> to pass the same integer value
on to C<$P1>. Though C<$P0> increments, C<$P1> doesn't change. The result for
C<assign> must have an existing object of the right type in it, because
C<assign> neither creates a new duplicate object (as does C<clone>) or reuses
the source object (as does C<=>).

=head3 プロパティ

X<properties>
X<PMCs (Polymorphic Containers); properties>

PMC は,PMC の"properties" としてそれらに付随した追加の値を持つことができます.Most properties hold extra metadata about the PMC.

The C<setprop>X<setprop opcode> opcode sets the value of a named property on a
PMC. It takes three arguments: the PMC on which to set a property, the name of
the property, and a PMC containing the value of the property.

=begin PIR_FRAGMENT

  setprop $P0, "name", $P1

=end PIR_FRAGMENT

The C<getprop>X<getprop opcode> opcode returns the value of a property.  It
takes two arguments: the name of the property and the PMC from which to
retrieve the property value.

=begin PIR_FRAGMENT

  $P2 = getprop "name", $P0

=end PIR_FRAGMENT

This example creates a C<String> object in C<$P0> and an C<Integer> object with
the value 1 in C<$P1>. C<setprop> sets a property named "eric" on the object in
C<$P0> and gives the property the value of C<$P1>. C<getprop> retrieves the
value of the property "eric" on C<$P0> and stores it in C<$P2>.

=begin PIR_FRAGMENT

  $P0 = new "String"
  $P0 = "Half-a-Bee"
  $P1 = new "Integer"
  $P1 = 1

  setprop $P0, "eric", $P1  # set a property on $P0
  $P2 = getprop "eric", $P0 # retrieve a property from $P0

  say $P2                   # prints 1

=end PIR_FRAGMENT

Parrot stores PMC properties in an associative array where the name of the
property is the key.

C<delprop>X<delprop opcode> deletes a property from a PMC.

=begin PIR_FRAGMENT

  delprop $P1, "constant" # delete property

=end PIR_FRAGMENT

You can fetch a complete hash of all properties on a PMC with
C<prophash>X<prophash opcode>:

=begin PIR_FRAGMENT

  $P0 = prophash $P1 # set $P0 to the property hash of $P1

=end PIR_FRAGMENT

Fetching the value of a non-existent property returns an C<Undef> PMC.

=head3 vtable 関数

X<vtable functions>
単純な操作が別のPMC で別の影響を与えるような場合があることに気付くかもしれません.低レベルな整数値をC<Integer> PMC に代入することで,そのPMC の整数値が設定されますが,同じ整数を順序付けされた配列に代入することで,配列のサイズが設定されます.

全ての PMC は,vtable 関数と呼ばれる標準な一連の低レベル操作を定義しています.以下のような代入をしようとすると:

   $P0 = 5

... Parrot は,レジスタ C<$P0> によって参照されるPMC の持つ C<set_integer_native> vtable 関数を呼び出します.

X<polymorphic substitution>
Parrot は,固定のvtable 関数を持っていますので,全てのPMC は,他のPMC の代役を務めることができます.これは,ポリモルフィックです.N<"Polymorphic Container" という名前で呼ばれる由来です>
全ての PMC は,全てのvtable 関数の振舞いを定義しています.The default behavior
is to throw an exception reporting that the PMC doesn't implement that vtable
function. The full set of vtable functions for a PMC defines the PMC's basic
interface, but PMCs may also define methods to extend their behavior beyond the
vtable set.

=head2 名前空間

X<namespaces>
X<global variables>
Parrot は,小さレジスタ集合へ保存した変数をそれぞれのサブルーチンでローカルにする操作を実現しています.より複雑なタスクとしては,N<…Parrot がサポートしている最も高級言語に対して> 1つのサブルーチンのスコープがまたがるような変数を持つことに対しても有効です.それらの変数は,プログラム全体でグローバルであるかもしれないし,特別なライブラリに制限されているかもしれない.Parrot は,名前空間の階層の中に長命な変数を保持します.

オペコード C<set_global>X<set_global opcode>C<get_global>X<get_global opcode> は,名前空間の中に変数を保持したり,取り出したりします:

=begin PIR_FRAGMENT

  $P0 = new "String"
  $P0 = "buzz, buzz"
  set_global "bee", $P0
  # ...
  $P1 = get_global "bee"
  say $P1                        # prints "buzz, buzz"

=end PIR_FRAGMENT

この例の最初の2つの文は,C<$P0>の中にC<String> PMC を生成し,値を代入しています.三番目の文で,C<set_global> は,そのPMC を名前付きグローバル変数 C<bee> に保持します.プログラムの少し後で, C<get_global> は,名前からグローバル変数を取り出して,それをC<$P1> に保持し,出力しています.

名前空間は,PMC 変数にしか保持できません.Parrot は,全てのプリミティブ,整数,小数,文字列の値をそれらを名前空間に保持する前に対応するPMC にボックス化します.

特定の名前空間の中に保持された全ての変数の名前は,ユニークでなければなりません.C<Integer> PMC と配列の PMC の両方を 同じ名前空間の中に保持された "bee" という名前に保持することはできません.N<誰がそれをしようと思うのか不思議に思うかもしれない.わたしたちも同じように不思議に思っているが,Perl5 はそれをいつでも行っている.Parrot 上の Perl 6 の実装では,変数の名前の中にそれぞれの名前をユニークに保存するような型シジルを含んでいる.例えば C<$bee>, C<@bee>....>

=head3 階層的な名前空間

X<hierarchical namespaces>
X<namespaces; hierarchy>

単一のグローバルな名前空間は,大半の言語やアプリケーションにおいて制限されすぎている.A single global namespace would be far too limiting for most languages or
applications. とても大きなコードベースの場合には,2つのライブラリで同じ名前で違う変数を使おうとしてしまう場合などの偶然の衝突の危険がとても高い.Parrot maintains a collection of namespaces arranged as a tree, with the
C<parrot> namespace as the root.  Every namespace you declare is a child of the
C<parrot> namespace (or a child of a child....).

The C<set_global> and C<get_global> opcodes both have alternate forms that take
a key name to access a variable in a particular namespace within the tree. This
code example stores a variable as C<bill> in the Duck namespace and retrieves
it again:

=begin PIR_FRAGMENT

  set_global ["Duck"], "bill", $P0
  $P1 = get_global ["Duck"], "bill"

=end PIR_FRAGMENT

The key name for the namespace can have multiple levels, which correspond to
levels in the namespace hierarchy. This example stores a variable as C<bill> in
the Electric namespace under the General namespace in the hierarchy.

=begin PIR_FRAGMENT

  set_global ["General";"Electric"], "bill", $P0
  $P1 = get_global ["General";"Electric"], "bill"

=end PIR_FRAGMENT

X<root namespace>
X<namespaces; root>

The C<set_global> and C<get_global> opcode operate on the currently selected
namespace. The default top-level namespace is the "root" namespace. The
C<.namespace>X<.namespace directive> directive allows you to declare any
namespace for subsequent code.  If you select the General Electric
namespace, then store or retrieve the C<bill> variable without
specifying a namespace, you will work with the General Electric bill,
not the Duck bill.

  .namespace ["General";"Electric"]
  #...
  set_global "bill", $P0
  $P1 = get_global "bill"

Passing an empty key to the C<.namespace> directive resets the selected
namespace to the root namespace. The brackets are required even when the
key is empty.

  .namespace [ ]

When you need to be absolutely sure you're working with the root namespace
regardless of what namespace is currently active, use the
C<set_root_global>X<set_root_global opcode> and
C<get_root_global>X<get_root_global opcode> opcodes instead of
C<set_global> and C<get_global>. This example sets and retrieves the
variable C<bill> in the Dollar namespace, which is directly under the
root namespace:

=begin PIR_FRAGMENT

  set_root_global ["Dollar"], "bill", $P0
  $P1 = get_root_global ["Dollar"], "bill"

=end PIR_FRAGMENT

X<HLL namespaces>
X<namespaces; hll>
To prevent further collisions, each high-level language running on
Parrot operates within its own virtual namespace root. The default
virtual root is C<parrot>, and the C<.HLL>X<.HLL directive> directive
(for I<H>igh-I<L>evel I<L>anguage) selects an alternate virtual root for
a particular high-level language:

  .HLL 'ruby'

The C<set_hll_global>X<set_hll_global opcode> and
C<get_hll_global>X<get_hll_global opcode> opcodes are like
C<set_root_global> and C<get_root_global>, except they always operate on
the virtual root for the currently selected HLL. This example stores and
retrieves a C<bill> variable in the Euro namespace, under the Dutch HLL
namespace root:

  .HLL 'Dutch'
  #...
  set_hll_global ["Euro"], "bill", $P0
  $P1 = get_hll_global ["Euro"], "bill"

=head3 名前空間 PMC

X<NameSpace PMC>
名前空間は,ただのPMC です.それらは標準的なvtable 関数と少しの追加のメソッドを実装しています.The C<get_namespace>X<get_namespace opcode>
opcode retrieves the currently selected namespace as a PMC object:

  $P0 = get_namespace

The C<get_root_namespace>X<get_root_namespace opcode> opcode retrieves
the namespace object for the root namespace.  The
C<get_hll_namespace>X<get_hll_namespace opcode> opcode retrieves the
virtual root for the currently selected HLL.

  $P0 = get_root_namespace
  $P0 = get_hll_namespace

Each of these three opcodes can take a key argument to retrieve a namespace
under the currently selected namespace, root namespace, or HLL root namespace:

  $P0 = get_namespace ["Duck"]
  $P0 = get_root_namespace ["General";"Electric"]
  $P0 = get_hll_namespace ["Euro"]

Once you have a namespace object you can use it to retrieve variables from the
namespace instead of using a keyed lookup. This example first looks up the Euro
namespace in the currently selected HLL, then retrieves the C<bill> variable
from that namespace:

  $P0 = get_hll_namespace ["Euro"]
  $P1 = get_global $P0, "bill"

Namespaces also provide a set of methods to provide more complex
behavior than the standard vtable functions allow. The
C<get_name>X<get_name method> method returns the name of the namespace
as a C<ResizableStringArray>:

  $P3 = $P0.'get_name'()

The C<get_parent>X<get_parent method> method retrieves a namespace
object for the parent namespace that contains this one:

  $P5 = $P0.'get_parent'()

The C<get_class>X<get_class method> method retrieves any Class PMC
associated with the namespace:

  $P6 = $P0.'get_class'()

The C<add_var>X<add_var method> and C<find_var>X<find_var method>
methods store and retrieve variables in a namespace in a
language-neutral way:

  $P0.'add_var'("bee", $P3)
  $P1 = $P0.'find_var'("bee")

The C<find_namespace>X<find_namespace method> method looks up a
namespace, just like the C<get_namespace> opcode:

  $P1 = $P0.'find_namespace'("Duck")

The C<add_namespace>X<add_namespace method> method adds a new namespace
as a child of the namespace object:

  $P0.'add_namespace'($P1)

The C<make_namespace>X<make_namespace method> method looks up a
namespace as a child of the namespace object and returns it. If the
requested namespace doesn't exist, C<make_namespace> creates a new one
and adds it under that name:

  $P1 = $P0.'make_namespace'("Duck")

=head3 エイリアス

X<aliasing>
普通の代入に似ていますが,ネームスペースの中で変数に保持するような様々な操作がPMC へのポインタを保持します.If you modify the local PMC after
storing in a namespace, those changes will also appear in the stored global. To
store a true copy of the PMC, C<clone> it before you store it.

Leaving the global variable as an alias for a local variable has its advantages.
If you retrieve a stored global into a register and modify it:

=begin PIR_FRAGMENT

  $P1 = get_global "feather"
  inc $P1

=end PIR_FRAGMENT

... you modify the value of the stored global, so you don't need to call
C<set_global> again.

=cut

# Local variables:
#   c-file-style: "parrot"
# End:
# vim: expandtab shiftwidth=4:

2011-10-17

名古屋ギークバーに行ってきた

麻雀回でした

とりあえず,Perl6 のNagoya.pm でやってた続きをする.

必要な機能は,テストから調べる.ことはわかったので

普通のプログラミングで必要なことを考える.

今は遅いのをなんとかしたいので,プロファイラかな.ぐぐる.

docs/dev/profiling.pod - Profiling Parrot

# Copyright (C) 2001-2005, Parrot Foundation.

=head1 NAME

docs/dev/profiling.pod - Profiling Parrot

=head1 DESCRIPTION

このファイルは,Parrot のプロファイリング実行部分の使用方法について記述している.

=head2 Summary

プロファイル実行環境は,Parrot の一部として作られており,PIRコードのボトルネックを発見できるように設計されています.HLL(?)プロファイルをサポートするために実装されていますが,現在では制限があります.C<parrot>バイナリィに C<-Rprofiling> や C<--runcore profiling>を渡すことで,コードはプロファイリング実行環境下で実行されます.出力ファイルの位置とフォーマットは,次に記述されるように環境変数によって決定されます.プロファイリング実行環境が関連する環境変数を発見できない場合は,次で書かれるようなデフォルト値を使います.

=head2 環境変数

=over 4

=item C<PARROT_PROFILING_FILENAME>

もしあれば,出力が書かれるファイルの完全な名前を決定します.Parrot は,書くために開く前にファイル名が存在するかどうかをチェックをせず,以前のプロファイルが含む既存のファイルを偶然にも上書きしてしまうでしょう.

値が設定されていなければ,Parrot はファイルをC<parrot.pprof.X> に書き出します.ここで,X はParrot プロセスのPID です.プロファイリング実行部分が存在する場合,プロファイルが書かれるときにアナウンスするメッセージを出力します.

この変数は,C<stdout> や C<stderr> という特殊な値を持つこともできます.それらの値のどちらかが(大文字小文字に関係無く) 見つかった場合,Parrot はプロファイリングの結果をstdout か stderr に出力します.

=item C<PARROT_PROFILING_OUTPUT>

これは,プロファイルを含む出力のタイプを決定します.現在のオプションは,C<pprof> と C<none>です.C<pprof> は,デフォルトであり,ASCII 文字であるため,人間が読めるような形式です.これは,tools/dev/pprof2cg.pl によって後処理して,Callgrind 互換のフォーマットに変換できます.C<none> は,結果ファイルを書き出しません.これは,主にプロファイリングの実行部分自身のテストや最適化にとって有用です.これは,PIR とHLL コードをプロファイルしたいユーザにとってあまり意味がないことを期待されています.

=item C<PARROT_PROFILING_ANNOTATIONS>

これは,PIR アノテーションがプロファイルの一部として記録されるように設定します.アノテーションは,HLL コードをプロファイリングするのに必要ですが,プロファイリングの実行部分をより遅くします.デフォルトでは,それらは無効です.それらを有効にするために,この値を設定します.

=item C<PARROT_PROFILING_CANONICAL_OUPUT>

これが設定されている場合,プロファイリングの実行部分は,全てのアドレスを1つの定数値として,全ての時刻を1として記録します.このオプションは,与えられたコードの部分が常に同じプロファイルを正確に生成することを保証する方法があると便利な場所,主にテスト用に便利です.この機能を有効にしたい場合,多分ランダムなハッシュシードに起因する非決定的な振舞いを避けるために C<--hash-seed 1324> を使ってParrot に特定のハッシュシードも渡したいと思うでしょう.

この変数はテストやプロファイリングの実行部分から離れては有用ではありません.そしてユーザのコードのホットスポットを見つけるために殆ど確実に助けにもなりません.

=back

=cut

つまり,C<parrot>バイナリィに C<-Rprofiling> や C<--runcore profiling> を渡すということですね.

で,よく見ると <workdir>/rakudo-star-2011.07/parrot-3.6.0/tools/dev/pprof2cg.pl に,pod もあった.

$ parrot -Rprofiling <workdir>/rakudo-star-2011.07/install/lib/parrot/3.6.0/languages/perl6/perl6.pbc <scriptname>
$ perl <workdir>/rakudo-star-2011.07/install/lib/parrot/3.6.0/tools/dev/pprof2cg.pl parrot.pprof.XX

pprof2cg.pl は,Callgrind-compatible 互換ファイルを出力するらしいので

valgrind をインストールしたけど,そもそもcallgrind のファイル見るのは,

kcachegrind だった…

$ sudo brew install --HEAD valgrind     # Lion だとhead しか対応してなかった
$ sudo brew install qt --with-qt3support
$ rehash
$ wget http://kcachegrind.sourceforge.net/kcachegrind-0.7.0.tar.gz
$ tar xf kcachegrind-0.7.0.tar.gz
$ cd kcachegrind-0.7.0/qcachegrind
$ qmake
$ make
$ ./qcachegrind.app/Contents/MacOS/qcachegrind

これで parrot.out.$PID ファイルが読めます.

ご参考

で見てみたんだけど,

f:id:clairvy:20111024220148p:image

これは,Perl6;Perl6Role;ACCEPTS(Role.pir) に時間がかかってるんですよね?

次はpir を読む流れ?

PEG を見よというおつげを頂いた

  • 10/22 valgrand の辺を追記

2011-09-18

Nagoya.pm #01 をやりました

ニューキャストさんとこで,

Nagoya.pm#01 を開催しました.

なるべく質問しやすいようにしたいと思ってやってみたけど

どうだったかな?

開催してみれば,2人でしか居ないかもと思いきや,

意外にも遠方から来てくださる方もいたし,

時間も余っちゃうんじゃないかと思ってたのですけど,

飛び入りもあったりして,参加者のみなさまに感謝です.


で,今後なんですけど,11月に第2回を開催したい感じです.

あと発表者も募集中なので,何かあれば連絡してください.


次回は,Apache の設定の話がいいとか,Git の話がいいとか言われてます.

Nagoya.pm の明日はどっちだ?

2011-08-07

ゆるPerl #14 にいってきた

Cafe どえりゃあ 復活です

Paas 的なものでなんかやりたいと思って,

とりあえずdotcloud を試そうと思って,

フレームワークどうしようかなと思って,

とりあえず Amon2 を試そうと思って,

cpanm Amon2 したら,make がないって言われて,

そういえば,今日Lion にしたから,/usr/bin の下が綺麗になってて,

Xcode 入れなきゃって思ったけど,

どうせならXcode4 にしようと思って,

ダウンロードしてインストールしてたらなんか時間が過ぎてた感じ.

id:bleis-tift の人がGit-Hooks を修正してたので,

自分のplatform で試してたら前に書いたところで普通にエンバグしてたので

一件修正しときました.bleis さんすんませんした.

今回は,Perl をちょっとだけ書いたので偉いと思いました.まる

あと日付が変ったけどこの日記を更新するスクリプトが動かなかったので

ライブラリを更新しました.

2011-01-16

メタプログラミングRuby を読み始めた

Ruby の知識は全然足りない状態で読み始めた.

とりあえず,色々調べながらで最初全然進めない感じですよ.

調べたこと - Ruby

  • Rakefile - test target を簡単に刺す
  • Rakefile - default ターゲットの指定方法

gist にしようかと思ったけど,とりあえずそのまま貼る

構成としては,

Rakefile
lib/object_model/alphanumeric.rb
test/test_object_model_alphanumeric.rb

Rakefile

require 'rake/testtask'

Rake::TestTask.new

task :default => "test"

こんな感じ.

で,Perl で書き直してみた.

Makefile.PL
lib/ObjectModel/Alphanumeric.pm
t/ObjectModel_Alphanumeric.t

Makefile.PL

use inc::Module::Install;

name 'ObjectModel-Alphanumeric';
all_from 'lib/ObjectModel/Alphanumeric.pm';

WriteAll;

lib/ObjectModel/Alphanumeric.pm

package ObjectModel::Alphanumeric;

use strict;
use warnings;

# Perl5 は,そもそもネイティブなオブジェクト指向言語ではないので
# autobox を使って,スカラにメソッドを刺せるようにする
sub to_alphanumeric {
    ($_ = shift) =~ s/[^\w\s]//g;
    $_;
}

1;

t/ObjectModel_Alphanumeric.t

#!/usr/bin/env perl

use strict;
use warnings;

use Test::More;
use FindBin;
use lib qq|$FindBin::Bin/../lib|;

use ObjectModel::Alphanumeric;
use autobox SCALAR => 'ObjectModel::Alphanumeric';

is(ObjectModel::Alphanumeric::to_alphanumeric('#3, the *Magic, Number*?'), '3 the Magic Number');
is('#3, the *Magic, Number*?'->to_alphanumeric(), '3 the Magic Number');

done_testing;

ということで,とりあえず Rakefile, Makefile.PL を書く辺で止まっているけど,

順番にやっていこうと思う.

参考

メタプログラミングRuby
Paolo Perrotta
アスキー・メディアワークス
売り上げランキング: 24616

rakudo コンパイルする

MacPorts をアップデートした所為か,昔コンパイルしたバイナリが動かなくなってたので,

clean したかったけど,よくわからんかったので全消ししてもっかいコンパイルしてみたメモ.

$ git clone http://github.com/rakudo/star.git rakudo-star
$ cd rakudo-star
$ make VERSION=2010.12 2> m.err | tee m.log
$ cd rakudo-star-2010.12
$ perl Configure.pl --gen-parrot 2> c.err | tee c.log
$ make 2> m.err | tee m.log
$ make rakudo-test 2> mt.err | tee mt.log
$ make install
$ ./perl6 -v

This is Rakudo Perl 6, version 2010.12 built on parrot 2.11.0Null PMC access in get_bool()
current instr.: 'perl6;Perl6;Compiler;version' pc 326881 (src/gen/perl6-grammar.pir:0)
called from Sub 'perl6;PCT;HLLCompiler;command_line' pc 1855 (compilers/pct/src/PCT/HLLCompiler.pir:917)
called from Sub 'perl6;Perl6;Compiler;main' pc 326820 (src/gen/perl6-grammar.pir:16982)
[1]    33934 exit 1     ./perl6 -v

ということで,やりながら気付いたけど,

make VERSION= すれば全部消さなくても良かったかもな.と思った.

(2011/02/16追記)

で,後で気付いたんだけど,parrot の tar を消さないと更新されないので注意.

*1

*1:しばらく parrot-2.1 とか使ってたよ…