どさにっき(アナログ) 〜2010年1月中旬〜

by やまや
<< = >>

2010年1月12日(火)

あたらしいプログラム言語を作った

_ これにいたく感銘を受けたので、モールス淫語ではなく、プログラムを書けるようにしてみた。

% cat hello.an
あああんああんあああっんっあああああんんああんあんっんっあああああんん
あんんああっんっあああああんんあんんああっんっあああああんんあんんんんっんっ
あああああんあんんああっんっあああああんあああああっんっあああああんんん
あんんんっんっあああああんんあんんんんっんっあああああんんんああんあっんっ
あああああんんあんんああっんっあああああんんああんああっんっあああああん
ああああんっんっあああああんあんあっんっああっっっ
% ./aegi hello.an
Hello, world!
……すまん。

_ 中身は、 whitespaceのトークンを変更しただけ。whitespace における空白、タブ、改行がそれぞれ「あ」「ん」「っ」に対応。上では「あんっ」(と改行)以外の文字は使ってないけど、あっても無視されるだけでエラーにはならないので、お好きな字句を挿入して感情を高めてください。手元で動いてるものは ここにある ruby 版 whitespace に以下の修正をした。

--- whitespace  2004-05-02 01:16:24.000000000 +0900
+++ aegi        2010-01-12 22:46:36.000000000 +0900
@@ -53,7 +53,7 @@

   def initialize
     @tokens = []
-    @program = $<.read.tr("^ \t\n", "")
+    @program = $<.read.tr("^\xa2\xf3\xc3", "").tr("\xa2\xf3\xc3", " \t\n")
     while @program != "" do
       @tokens << tokenize
     end
これは EUC 版。\xa2\xf3\xc3 となってる部分を \xa0\xf1\xc1 に変更すると ShiftJIS を受け付けるようになるはず(ためしてないけど)。厳密には、2バイト文字をまじめに解釈せずに「あんっ」の2バイト目を探してるだけなので、「あんっ」以外でもこれにマッチする文字はコードとして解釈される。手抜きですまん。たとえば、EUC 版はカタカナの「アンッ」で喘いでもちゃんと動く。

_ 少ないトークンで記述できる言語としては、 ちょっと草植えときますね型言語 Grassなんてのもあるけど、これはこれで素のままでもネタなのでいじらない。 brainfuck をベースにしなかったのは、同じ文字(とくに +-)がやたら連続して出現しがちでいまいちおもしろくなさそうだったから。 みさくら語言語 Misaという偉大な先達ぐらいに無意味文字を混ぜればそれでもよさそうだけど。というかこのインパクトには勝てねぇwWWwwww (← Grass で w を出力するコードらしい)。


2010年1月13日(水)

awk で brainfuck

_ きのうアホな遊びをやってたらなんだか変態言語をいじりたくなったので( きのうのようなベクトルの変態ではない)、 brainfuckを自前で実装してみる。

_ …1時間もかからず書けた。brainfuck なんて変態言語は読めないし書けないしできるようになろうとも思わないので正しく動作するか確認するのがめんどうだけど、てきとーにぐぐって見つけたコードをつっこんでみると確かに動いてるようだ。読み書きできない言語を実装するというのもおかしな話だが。ちうことで、 awk で書いた bf インタプリタ。mawk or gawk 用。コードを縮めようとしたわけではないんだが(まったくやってないわけでもないが)、それでも500バイトもなかった。

_ ぐぐってみたら、ほかにも awk で書かれた インタプリタ(","(1文字入力)が実装されてないようだ)や C へのトランスレータ(この程度なら sed でいいじゃん)なんてのがあるようだ。


2010年1月14日(木)

lua で brainfuck

_ Lua でも書いてみた。なんも考えずに きのうの awk 版をベタ移植しただけ。かなり丁寧に書いたんだけど、それでも 1KB を下回る。

_ ぐぐったら こんなのが見つかったんだけど、……これ、今の lua では動かないよね。lua をいじりはじめてまだ半年に満たないので歴史的なことはあまり知らないんだけど、バージョンが上がるたびに互換性をばっさり捨てる言語らしいと聞く。組み込み用途では互換性の確保よりも処理系のサイズが小さい方が重要ってことなんだと思うけど。

_ すっかり golf 脳なので、高圧縮版。283バイト。上のとはまったく異なるロジック。

s="(a[p]or 0)"a={}p=0
loadstring(io.open(arg[1]):read"*a":gsub("[^><%+%-%.,%[%]]",""):gsub(".",{[">"]="p=p+1 ",["<"]="p=p-1 ",["+"]="a[p]="..s.."+1 ",["-"]="a[p]="..s.."-1 ",["."]="io.write(s.char"..s..")",[","]="a[p]=io.read(1):byte()",["["]="while "..s.."~=0 do ",["]"]="end "}))()

_ ついでに高圧縮 gawk 版。303バイト。lua より長くなってしまった。getchar() に相当する部分が大きい(全体の 1/3 以上)。がんばればもう少し縮むかもだけど。

{s=s$0}END{$0=s
for(p=++NF>256?NF:256;p--;c[sprintf("%c",p)]=p)(b[p]=$p)~/]/?t[++k]=p:$p~/\[/?r[r[p]=t[k--]]=p:_
for(;$0=b[++i];/>/?++p:/</?--p:/+/?++a[p]:/-/?--a[p]:/\[/&&!a[p]?i=r[i]:/]/?i=r[i]-1:_){if(/,/){if(!j&&1>getline s<"-")break;n=split(s RS,t);a[p]=c[t[++j]];j%=n}if(/\./)printf"%c",a[p]}}FS=_


<< = >>
やまや