記号でPolyglotプログラミング♪(RejectKaigi2009)

RubyKaigi2009の最終日に同じ場所で開催された別のイベント「RejectKaigi2009」にて
「はじめてのRuby1.9プログラミング」と題して、記号Polyglotプログラミングの話をしてきました。

3分という限られた時間でありましたが、貴重な発表の機会を与えてくださりありがとうございます。

取り急ぎプレゼンで披露した記号Polyglotのプログラムを公開しておきます。

■ hello.pl

(という名前ですが、Perlの他にRubyやJavaScriptでも実行できるプログラムです)

■ 各言語処理系での実行結果

(1) Perl の実行結果

D:\rejectkaigi2009> perl hello.pl
Hello, Perl!

(2) Ruby 1.8.7 での実行結果

D:\rejectkaigi2009> ruby1.8 hello.pl
Hello, Ruby1.8!

(3) Ruby 1.9.1 での実行結果

D:\rejectkaigi2009> ruby1.9 hello.pl
Hello, Ruby1.9!

(4) SpiderMonkey での実行結果

D:\rejectkaigi2009> js hello.pl
Hello, JavaScript!

(5) Firefox での実行結果

ブラウザのURL入力欄にjavascript:を入力してその後にワンライナーをコピペして改行(Enter)を押します。

Demo_firefox

(6) Chrome での実行結果

Firefoxの場合と同様にします。javascript:を入力し忘れないでください。(でないと入力した記号のワンライナーをGoogle検索しにいってしまってBad Requestと怒られてしまいます…)

Demo_chrome

■ Ruby部分のコード解説

PerlとJavaScriptのコードは後日解説するとして、Ruby部分のコードで使われているテクニックを少し解説しようと思います。(最初に言い訳ですが、まだRuby1.9を使い始めて3日目なので、間違ったことを言っていたらすみません…)

Rubyインタプリタの解釈する部分は以下になります。

Polyglot_ruby

それ以外のところはPerlやJavaScriptで実行される領域になっています。

– Ruby 1.8 と 1.9 の非互換部分

Ruby1.8以前では ?a は’a’のASCIIコードの数値97が返されていましたが、Ruby1.9からは長さ1の文字列"a"を返すように仕様変更されました。これはRuby1.9からの多言語対応のためで、文字列をバイト列ではなく文字単位で扱うようになったためです。

ruby1.9> p ?a
"a"

ruby1.8> p ?a
97

したがって、?? は Ruby1.9では文字列"?"のことですが、Ruby1.8以前では’?’のアスキーコードである63の数値を返すことになります。

ruby1.9> p ??
"?"

ruby1.8> p ??
63

次に数値と文字列における%演算子の違いですが、文字列の"?"%"?"はsprintf("?","?")と同じ動きをして結果は"?"となりますが、数値の63%63は63÷63=商1…余り0の余りを返すため0となります。

ruby1.9> p ??%??
"?"

ruby1.8> p ??%??
0

これを利用してRuby1.9の処理系かどうかを記号9バイトだけで判定することができます。RUBY_VERSION を使うよりも圧倒的に短いです。地球に優しくてエコですね。:-)

ruby1.9> p ??%??==??
true

ruby1.8> p ??%??==??
false

– 記号のみで任意の文字列を作成する方法

Rubyで任意の文字列を生成するには""<<数値(ASCIIコード)という文字列の破壊的演算を行なう構文を利用するのが簡単です。

ruby1.9> p ''<<123
"{"

ruby1.8> p ''<<123
"{"

任意の数値を作成するには、Ruby1.8以前では?{-?|などを利用してできたのですが、Ruby1.9からは先の仕様変更があるため使えません。どうするかというと、正規表現を利用します。

ruby1.9> p //=~''
0

ruby1.8> p //=~''
0

正規表現にマッチした場所を文字列の先頭から数えて結果を返します。

ruby1.9> p /_/=~'>_'
1

ruby1.8> p /_/=~'>_'
1

これを利用すると、こちらで用意した文字列から目的の先頭バイト数でマッチする正規表現を書いてあげれば、任意の数値を作成することができます。これは記号だけを使って実現できます。

ruby1.9> p /_/=~'>>>>>>>>>_'
9

ruby1.8> p /_/=~'>>>>>>>>>_'
9

– (”<<数値)で任意のASCIIコードの文字を標準出力 $> に書き込む

以上のテクニックを組み合わせると、$> << "文字列" と書くことを利用して任意の文字列を標準出力に書き込むことができます。

ruby1.9> $><<(''<<88)+(''<<89)+(''<<90)
XYZ

ruby1.8> $><<(''<<88)+(''<<89)+(''<<90)
XYZ

もちろん、88や89の数字の部分は上記で解説したテクニックを応用して、数値返す正規表現(記号のみ)に置き換えています。真面目にゴルフすればもっと短くなることはわかっているのですが、まずは「わかりやすさ優先」ということであえて冗長なコードになっています。

実際のコードではPerlとJavaScriptとRubyのコードを混在させるために、別のテクニックも使っているのですが、詳しい解説はまた後日行ないたいと思います。

それでは、Happy Hacking!

コメントは受け付けていません。