ふつパイラ

私の住むマンションは、エントランスの所に郵便受けがあり、毎日確認に行くのが私の日課に なっている。

入っているのは、近くで売り出したマンションの広告や建売の広告ばかり。あるマンションなんて 施主が倒産したので、後を引き継いだ工務店が投売りしてた。2100 -> 1800でどうでっしゃろ? とか、モデルルームの家具や設備一式をおまけで付けますとか、、 よっぽど売れてないんだねえ。

でも、そんな広告が毎日入ってるとなると、いいかげんにうざい。郵便受けの所に、ごみ箱を 設置しておいて、そんなスパムは即ごみ箱行きにしたいぞ。

そういうスパムをより分けて、届くのは宅配業者が持ってくる、通販の分厚いカタログ。今は 秋冬モードのオンパレードだ。勿論、届け先は女房名。おいらの所に来るのは、月1の請求書 ばかりだなあ。こういうのは、情報格差と言うんだろうか?

emacsでHaskell入力の補間

Emacs での Haskell プログラミングを幸せにするが 公開された。今まで有りそうで無かったものだ。scheme等では同等なツールが既にあるのに haskellに無かったと言う事は、単純に考えると人口の差だな。

まずは、FreeBSDでやってみる。haskell-src-extsが古いと文句を言われた。こういう時は、 cabal update してから、cabal upgrade haskell-src-exts したよ。

次はWindowsに入れようとしたんだけど、下準備が大変だった。こちらは、 haskell-src-exts が入ってないってば、と言われた。

そなら、cabal update してから、cabal install haskell-src-exts すればいいんだな。 やってみたら、今度は、happy が無いからやだ、と言われた。

ほなら、cabal install happy だなと、やり始めたら、インストールするには perlが要りまっせ と、あるまじき事を言い出したよ。なんたる事だ。

気が進まなかったけど、perl を突っ込んでから、happy -> haskell-src-exts -> ghc-mod と 辿って、やっと入った。もう少し、cabalさんには利口になって貰わねば。こういう面倒さが Haskell人口が増えない原因の一旦になってるのね。

あの方に、haskell少人口対策大臣になって欲しいぞ。

所で、今回の根っ子になった、happy って何物よ? たまたま、読んでいた ふつうのコンパイラをつくろうの、P45に 解説が出ていた。happyはLALR(1)、ParsecはLL(k)を扱えるパーサーだそうです。

ふつパイラで遊ぶ

RHG読書会で ふつパイラの読書会が行われている。もう17章まで進んでしまったと言う事は、残りは第4部の リンクとライブラリー編だけの数章か。ならば、今から出席しても(次回は、10/17)遅いか。

そもそも、この本を手に取って、第3章から終わりまで一気読みし、暫くほってあって、最近 頭から読み始めると言う変則な事をしてたからなあ。少し、自習してみっか。

と、言う事で、久しぶりにlenny/debianをひっぱり出してきた。だって、Linux必須なんだ もん。後は、javac,ant,javaccとか、豪快な環境を要求される。(cbcを*.javaから作る場合)

何事もソースからやってみない事には、気が済まない私ですから、READMEに従って

sakae@debian:~/cbc-1.0$ ls
ChangeLog  README  bin/              build.xml  install.sh*  net/   tools/
Makefile   ToDo    build.properties  import/    lib/         test/  unit/
sakae@debian:~/cbc-1.0$ make
make: `default' に対して行うべき事はありません.

しょうがないので、Makefileを覗いてみた結果

sakae@debian:~/cbc-1.0$ rm lib/cbc.jar lib/libcbc.a
sakae@debian:~/cbc-1.0$ make
ant compile
Buildfile: build.xml

init:

parser:
   [javacc] Java Compiler Compiler Version 4.1d1 (Parser Generator)
   [javacc] (type "javacc" with no arguments for help)
   [javacc] Reading from file /home/sakae/cbc-1.0/net/loveruby/cflat/parser/Parser.jj . . .
   [javacc] Note: UNICODE_INPUT option is specified. Please make sure you create the parser/lexer using a Reader with the correct character encoding.
   [javacc] File "TokenMgrError.java" does not exist.  Will create one.
   [javacc] File "ParseException.java" does not exist.  Will create one.
   [javacc] File "Token.java" does not exist.  Will create one.
   [javacc] File "SimpleCharStream.java" does not exist.  Will create one.
   [javacc] Parser generated successfully.

compile:
    [mkdir] Created dir: /home/sakae/cbc-1.0/build
    [mkdir] Created dir: /home/sakae/cbc-1.0/build/classes
    [javac] Compiling 193 source files to /home/sakae/cbc-1.0/build/classes
      [jar] Building jar: /home/sakae/cbc-1.0/lib/cbc.jar

BUILD SUCCESSFUL
Total time: 27 seconds
cd lib; make libcbc.a
make[1]: ディレクトリ `/home/sakae/cbc-1.0/lib' に入ります
ar crs libcbc.a stdarg.o alloca.o
make[1]: ディレクトリ `/home/sakae/cbc-1.0/lib' から出ます

次は、試験してみっか。

sakae@debian:~/cbc-1.0$ make test
cd test; make test
make[1]: ディレクトリ `/home/sakae/cbc-1.0/test' に入ります
./run.sh

01_exec........
02_print................................................................
  :
36_alloca..................................................
37_setjmp................
PASS (1920 tests) -- debian / Linux 2.6.26-2-686 i686
make[1]: ディレクトリ `/home/sakae/cbc-1.0/test' から出ます

インストールしたら、試運転。

sakae@debian:~/tmp$ cat hoge.cb

import stdio;

int main(int argc, char **argv){
  printf("Hello CBC\n");
}

sakae@debian:~/tmp$ cbc hoge.cb
sakae@debian:~/tmp$ ./hoge
Hello CBC

ああ、青木さんの血と汗を一瞬のうちに堪能しちゃった。と、思ったらおまけが有ったよ。

sakae@debian:~/tmp$ cat hoge.s
.file   "hoge.cb"
        .section        .rodata
.LC0:
        .string "Hello CBC\n"
        .text
.globl main
        .type   main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        movl    $.LC0, %eax
        pushl   %eax
        call    printf
        addl    $4, %esp
.L0:
        movl    %ebp, %esp
        popl    %ebp
        ret
        .size   main,.-main

gas って、opcode src,dest と並んでるんだよね。この並びの方が私の趣味に合うなあ。 また、movlと言う具合に、lだとかw,bと言うのが付くのもm68kアセンブラみたいで好感が 持てる。AT&T風記述万歳。ああ、$が頭に付くと即値というのもいいねぇと、徹底的に intel風味を嫌うのでした。

次は、AST。

sakae@debian:~/tmp$ cbc --dump-ast hoge.cb
<<AST>> (hoge.cb:2)
variables:
functions:
    <<DefinedFunction>> (hoge.cb:4)
    name: "main"
    isPrivate: false
    params:
        parameters:
            <<Parameter>> (hoge.cb:4)
            name: "argc"
            typeNode: int
            <<Parameter>> (hoge.cb:4)
            name: "argv"
            typeNode: char**
    body:
        <<BlockNode>> (hoge.cb:4)
        variables:
        stmts:
            <<ExprStmtNode>> (hoge.cb:5)
            expr:
                <<FuncallNode>> (hoge.cb:5)
                expr:
                    <<VariableNode>> (hoge.cb:5)
                    name: "printf"
                args:
                    <<StringLiteralNode>> (hoge.cb:5)
                    value: "Hello CBC\n"

schemeは、ここまでは人間がやるんだな。

sakae@debian:~/tmp$ cbc --dump-ir hoge.cb
<<IR>> (hoge.cb:2)
variables:
functions:
    <<DefinedFunction>> (hoge.cb:4)
    name: main
    isPrivate: false
    type: int(int, char**)
    body:
        <<ExprStmt>> (hoge.cb:5)
        expr:
            <<Call>>
            type: INT32
            expr:
                <<Addr>>
                type: INT32
                entity: printf
            args:
                <<Str>>
                type: INT32
                entry: net.loveruby.cflat.entity.ConstantEntry@f5da06

そして、ASTを扱いやすいように中間言語に変換したぞ。

sakae@debian:~/tmp$ cbc --print-asm -fverbose-asm hoge.cb
.file   "hoge.cb"
        .section        .rodata
.LC0:
        .string "Hello CBC\n"
        .text
.globl main
        .type   main,@function
main:
        # ---- Stack Frame Layout -----------
        # (%ebp): return address
        # 4(%ebp): saved %ebp
        # 8(%ebp): argc
        # 12(%ebp): argv
        # -----------------------------------
        pushl   %ebp
        movl    %esp, %ebp
        # line 5: printf("Hello CBC\n");
        # Call {
          # Str {
        movl    $.LC0, %eax
          # }
        pushl   %eax
        call    printf
        addl    $4, %esp
        # }
.L0:
        movl    %ebp, %esp
        popl    %ebp
        ret
        .size   main,.-main

そして、これは、高橋会長ご推薦図書「計算機プログラミングの基礎概念」風の、まぜこぜ スタイルによる出力。さりげなく、こういうのを用意してるとは、さすが青木さん! と、cbcは、いろいろな段階の 結果が見られるから、勉強になるなあ。どんな段階があるかは

sakae@debian:~/tmp$ cbc --help
Usage: cbc [options] file...
Global Options:
  --check-syntax   Checks syntax and quit.
  --dump-tokens    Dumps tokens and quit.
  --dump-ast       Dumps AST and quit.
  --dump-semantic  Dumps AST after semantic checks and quit.
  --dump-ir        Dumps IR and quit.
  --dump-asm       Dumps AssemblyCode and quit.
  --print-asm      Prints assembly code and quit.
    :

最後に、javaccがどんな*javaを吐き出したか確認しておく。

sakae@debian:~/cbc-1.0/net/loveruby/cflat/parser$ ls -ltr
合計 220
-rw-r--r-- 1 sakae sakae   2314 2009-05-10 23:52 LibraryLoader.java
-rw-r--r-- 1 sakae sakae  31109 2009-05-24 19:23 Parser.jj
-rw-r--r-- 1 sakae sakae  42175 2009-10-05 13:47 ParserTokenManager.java
-rw-r--r-- 1 sakae sakae 101151 2009-10-05 13:47 Parser.java
-rw-r--r-- 1 sakae sakae   4493 2009-10-05 13:47 TokenMgrError.java
-rw-r--r-- 1 sakae sakae   3833 2009-10-05 13:47 Token.java
-rw-r--r-- 1 sakae sakae  12093 2009-10-05 13:47 SimpleCharStream.java
-rw-r--r-- 1 sakae sakae   3789 2009-10-05 13:47 ParserConstants.java
-rw-r--r-- 1 sakae sakae   6683 2009-10-05 13:47 ParseException.java

ChangeLogによると、このプロジェクトは、"Tue Mar 20 22:09:22 2007 Minero Aoki"から 始められたようです。一人でコンパイラーを作るなんて、とんでもなく大変な事。 そして、そのコード解説を本にしちゃうなんて、常人には出来る事ではありません。 この本の真価は、3,(特に)4部にあると思っています。心してもう一度、読み直そう。