また Wiki エンジンを自作してしまった。
こんどのやつは、常用しようと思っていて、にっきも、それ以外も、
全部そっちで書くことにする。
とりあえず、4 月の日記はこちら
]]>http://www.jmilne.org/not/CDGuide.html
amscd は斜めの線が引けないとか。xymatrix がいいのかも。
platex xy.txt
dvipdfmx xy
convert -trim xy.pdf xy.png
http://uhideyuki.sakura.ne.jp/files2015/xy.png
ふつうに数式環境で書けばよい。
MathJax ではなく LaTeX にまかせる数式環境というのをプラグインにすればいいだけかも(studs はなし)
参考: http://www.jmilne.org/not/Mxymatrix.pdf
usepackage に追加するものは、conf に書けた方がよい。
]]>Graphviz では数式書けないし、さくらには Graphviz ちゃんとしたの用意するのしんどげだったので、こっちの方がメインになるかも。
platex web00351
dvipdfmx web00351
convert -trim web00351.pdf web00351.png
jsarticle にして文字大きめ、convert -trim くらいがミソかな。
http://uhideyuki.sakura.ne.jp/files2015/web00351.png
参考:
http://www.biwako.shiga-u.ac.jp/sensei/kumazawa/tex/web0035.html
まず、make install でこけた。↓を参考に回避。
http://scissorhands.jpn.org/2008/04/visitorsgraphviz.html
pangocairo を入れるのは大変そう(根性はない)で、デフォルトのレンダラだとあんまり品質よくない。
http://scissorhands.jpn.org/2008/04/visitorsgraphviz.html
妥協策として、svg を介して、dpi 高めでビットマップを吐くというのでどうかな。
$ ~/bin/dot -T svg -o sample.svg sample.dot
$ convert -resample 300 -units PixelsPerInch sample.svg sample.pdf
いまいちだけど。
]]>「情報学における論理」を主に読み進めている。1章もうすぐ終わって、次は2章の述語論理。どうして学生のころ、ちゃんと勉強しておかなかったかなぁという感じだが。
「プログラム意味論」は、チャーチ・ロッサー定理の証明になっとくがいかなくて、いまは脱線して "The Lambda Calculus" のその部分を読んでる。
圏論の教科書は、最後になるかなぁ。
]]>Date | Problems solved |
---|---|
2015-03-18 | #31, #36 |
気がつくと、細かい時間や、仕事以外でPCに向かえる時間をすべて Project Euler に持っていかれている感じだったので、平均 1 問/日 に制限することにした。
]]>Date | Problems solved |
---|---|
2015-03-17 | #18, #67, #11, #24, #19, #50, #48 |
昨日、おとといは、腰痛で寝込んでいたので、1問/日ペース守るなら3問かなといったところ。
ぱっと見とけそうなのが4つあったので、とりあえず。
あと、#19 も解いた。これは、ずいぶんいい加減にやってしまった感。
その後、#50, #48 も。うむむ。
]]>Haskell で。毎日少しでもコード書くための題材としていいかなと思って始めたのですが、なんか、最初の方の問題はとっとと済ませてしまいたくなって、当初思ってたより時間をつかってしまっているかもしれない。
Date | Problems solved |
---|---|
2015-03-14 | #12, #21, #25, #23, #22,#29,#28,#27,#26 |
2015-03-13 | #40, #20, #30, #35, #15, #10, #13, #16, #14, #17 |
2015-03-12 | #2, #3, #4, #5, #6, #7, #8, #9 |
2015-03-11 | #1 |
はじめ、1から順番にやってたんだけど、9までやったところで、順番にやるのに飽きてしまい。先の方のやつを見てたら、とりあえず #40 簡単そうだったのでやって、間を埋めてる。
書いたコードは一応 GitHub に置いてたりするけど、まぁ、ひとのコード読む気にはならないよなぁ。(解く前にはもちろんひとのコードなんてみないし、解いてしまったらしまったで、読む気なくなる感じ)
]]>とりあえず これ が処理できるようなコンパイラを書きたいなと思ってたのが 2012 年 10 月だったらしいので、2年以上たってる!
ようやく、これを構文解析できるところまではいった。
$ sample/parser_sample < testcases/tqd.hs
Right (Module {modid = Nothing, exports = Nothing, body = ([],[ValDecl (FunAppExp (VarExp (Name {name_base = "qsort", name_qual = "", name_pos = (2,1)})) (VarExp (Name {name_base = "[]", name_qual = "", name_pos = (2,7)}))) (UnguardedRhs (VarExp (Name {name_base = "[]", name_qual = "", name_pos = (2,16)})) []),ValDecl (FunAppExp (VarExp (Name {name_base = "qsort", name_qual = "", name_pos = (3,1)})) (ParExp (InfixExp (VarExp (Name {name_base = "x", name_qual = "", name_pos = (3,8)})) (Name {name_base = ":", name_qual = "", name_pos = (3,9)}) (VarExp (Name {name_base = "xs", name_qual = "", name_pos = (3,10)}))))) (UnguardedRhs (InfixExp (InfixExp (FunAppExp (VarExp (Name {name_base = "qsort", name_qual = "", name_pos = (3,16)})) (VarExp (Name {name_base = "smaller", name_qual = "", name_pos = (3,22)}))) (Name {name_base = "++", name_qual = "", name_pos = (3,30)}) (ListExp [VarExp (Name {name_base = "x", name_qual = "", name_pos = (3,34)})])) (Name {name_base = "++", name_qual = "", name_pos = (3,37)}) (FunAppExp (VarExp (Name {name_base = "qsort", name_qual = "", name_pos = (3,40)})) (VarExp (Name {name_base = "larger", name_qual = "", name_pos = (3,46)})))) [ValDecl (VarExp (Name {name_base = "smaller", name_qual = "", name_pos = (5,18)})) (UnguardedRhs (ListCompExp (VarExp (Name {name_base = "a", name_qual = "", name_pos = (5,29)})) [BindStmt (VarExp (Name {name_base = "a", name_qual = "", name_pos = (5,33)})) (VarExp (Name {name_base = "xs", name_qual = "", name_pos = (5,38)})),ExpStmt (InfixExp (VarExp (Name {name_base = "a", name_qual = "", name_pos = (5,42)})) (Name {name_base = "<=", name_qual = "", name_pos = (5,44)}) (VarExp (Name {name_base = "x", name_qual = "", name_pos = (5,47)})))]) []),ValDecl (VarExp (Name {name_base = "larger", name_qual = "", name_pos = (6,18)})) (UnguardedRhs (ListCompExp (VarExp (Name {name_base = "b", name_qual = "", name_pos = (6,29)})) [BindStmt (VarExp (Name {name_base = "b", name_qual = "", name_pos = (6,33)})) (VarExp (Name {name_base = "xs", name_qual = "", name_pos = (6,38)})),ExpStmt (InfixExp (VarExp (Name {name_base = "b", name_qual = "", name_pos = (6,42)})) (Name {name_base = ">", name_qual = "", name_pos = (6,44)}) (VarExp (Name {name_base = "x", name_qual = "", name_pos = (6,46)})))]) [])]),TypeSigDecl [Name {name_base = "main", name_qual = "", name_pos = (8,1)}] (Nothing,AppTy (Tycon (Name {name_base = "IO", name_qual = "", name_pos = (8,9)})) (Tycon (Name {name_base = "()", name_qual = "", name_pos = (8,12)}))),ValDecl (VarExp (Name {name_base = "main", name_qual = "", name_pos = (9,1)})) (UnguardedRhs (DoExp [LetStmt [ValDecl (VarExp (Name {name_base = "helo", name_qual = "", name_pos = (10,10)})) (UnguardedRhs (LitExp (LitString "Hello, World!" (10,17))) [])],ExpStmt (FunAppExp (VarExp (Name {name_base = "putStrLn", name_qual = "", name_pos = (11,6)})) (VarExp (Name {name_base = "helo", name_qual = "", name_pos = (11,15)}))),ExpStmt (InfixExp (InfixExp (VarExp (Name {name_base = "putStrLn", name_qual = "", name_pos = (12,6)})) (Name {name_base = "", name_qual = ".", name_pos = (12,14)}) (VarExp (Name {name_base = "show", name_qual = "", name_pos = (12,15)}))) (Name {name_base = "$", name_qual = "", name_pos = (12,20)}) (FunAppExp (VarExp (Name {name_base = "qsort", name_qual = "", name_pos = (12,22)})) (ListExp [LitExp (LitInteger 3 (12,29)),LitExp (LitInteger 1 (12,32)),LitExp (LitInteger 4 (12,35)),LitExp (LitInteger 1 (12,38)),LitExp (LitInteger 5 (12,41)),LitExp (LitInteger 9 (12,44)),LitExp (LitInteger 2 (12,47)),LitExp (LitInteger 6 (12,50)),LitExp (LitInteger 5 (12,53))]))),ExpStmt (InfixExp (InfixExp (VarExp (Name {name_base = "putStrLn", name_qual = "", name_pos = (13,6)})) (Name {name_base = "$", name_qual = "", name_pos = (13,15)}) (VarExp (Name {name_base = "show", name_qual = "", name_pos = (13,17)}))) (Name {name_base = "$", name_qual = "", name_pos = (13,22)}) (FunAppExp (VarExp (Name {name_base = "qsort", name_qual = "", name_pos = (13,24)})) (VarExp (Name {name_base = "helo", name_qual = "", name_pos = (13,30)}))))]) [])])})
Typing Haskell in Haskell をみながら書いた型推論器もいちおうもうあるので、構文木を加工して型推論にかけられるように加工する部分(Desugar 的な)を書いてやればよいはず。
ちなみに、今日これを Parse しようとして、layout まわりのバグをみつけた。do の直後の let がうまく処理されていなかったという。
この例には明に型付けされた束縛と、明に型付けされていない束縛が1つづつあって、defaulting も行われるので、型推論の最初の動作確認にはちょうどよさそう。依存解析はまだ省ける。
$ runhaskell -Wall tqd.hs
tqd.hs:2:1: Warning:
Top-level binding with no type signature:
qsort :: forall a. Ord a => [a] -> [a]
tqd.hs:12:29: Warning:
Defaulting the following constraint(s) to type `Integer'
(Num a0) arising from the literal `3' at tqd.hs:12:29
(Ord a0) arising from a use of `qsort' at tqd.hs:12:22-26
(Show a0) arising from a use of `show' at tqd.hs:12:15-18
In the expression: 3
In the first argument of `qsort', namely `[3, 1, 4, 1, ....]'
In the second argument of `($)', namely `qsort [3, 1, 4, 1, ....]'
Hello, World!
[1,1,2,3,4,5,5,6,9]
" !,HWdellloor"
]]>@<m>{}
のなかで {, } を気軽に書きたかったので改造。互換性上、プルリクは無理そうなのがわかったけど、自分はこれが使いたいので勝手に使いつづけよう。
現状の改造版では、次のように書ける。
@<m>{\sigma_{2} = \\{ 5/x \\} \cup \sigma_{1}}
\{
, \}
はカウントされないので、対応とれてない場合に使う。エスケープされて {, } になる。\{
が書きたいときには \\{
と書く必要がある。オプション部分の解析を自前にしたので、一番外側の括弧を選べるようにしてもいいかなとも思ったけど、どっちみち互換性むちゃくちゃなので、ま、凝らなくていいような気がした。
互換性を維持するために、新しいインラインコマンド記法を追加して、その場合には新規の文法が有効になるとかにしないといけないんだな、きっと。
ちなみに、既存の仕様に適応しようかとはおもったのだけど、$ \sigma_{2} = \{ 5/x \} \cup \sigma_{1} $
を得るためにどう書けばいいのか、わかんなかった。
自分でてきとうに書いた文法を LALR(1) に書き直すのは大変っぽかったので、
自分で一度かいたら読めるようになった GHC の Parser.y を有難く参考にさせていただくことにした。
おかげさまで、↓このとおり。ありがたい!
$ happy -i src/Parser.y
shift/reduce conflicts: 12
どうしてこう書くとよいのか、こう書かねばならないのかは、おいおい理解したい。
んでもって、このままではレイアウト規則の最後の1ピースがはまっていないので、構文エラーになる。
$ src/Parser < testcases/test1.hs
Left "parseError: TVCCurly (AlexPn 588 17 1)"
でもって、エラートークンがきたらコンテキストを pop するようにしてやると、
-- Layout ---------------------------------------------------------------------
close: vccurly {}
| error {% popCtx }
…
$ src/Parser < testcases/test1.hs
Right ()
よしよし。スバラシイ。
この調子で、今週中に抽象構文木をつくるところまではいってしまおう。
ふふふ。次はいよいよ型推論(または型再構築)であーる。
]]>shift/reduce conflicts: 128 → 72
reduce/reduce conflicts: 151 → 57
ずいぶん減らしたけど、まだまだあるなぁ。
]]>昨日、Haskell 2010 report みながら、えいっと Parser.y を書いたんだけど、
ずいぶん conflict を出してしまった。
unused rules: 5
shift/reduce conflicts: 144
reduce/reduce conflicts: 212
ひとつひとつ、文法の曖昧なのをなくしていこう。
ひとつの問題で沢山の衝突が引き起される傾向があるようなので、この数ほど修正箇所はないだろう。
レイアウト規則では、そうしないと構文エラーになる箇所には仮想閉じブレースが補われることに
なっている。
そこで、仮想ブレースが閉じていないのを許容する文法にすればいいのかなと思ったんだけど、
こういうのはいかにも衝突の原因になる。
ccurly_opt: vccurly {}
| {- empty -} { {- pop ctx -} }
GHC のパーサーのソースをみると、error トークンが使われていて、Happy のマニュアルにも
そういう利用方法が書かれている。
close : '}' { () }
| error { () }
ついでに、非終端記号の名前も真似して close にしてみよう。
unused rules: 5
shift/reduce conflicts: 96
reduce/reduce conflicts: 176
shift/reduce が 48 個減、reduce/reduce が 36 個へった。
lpat: gcon seq_apat
は
lpat: gcon seq1_apat
の間違いだった。このせいで apat: gcon と衝突。
unused rules: 5
shift/reduce conflicts: 128 (+32)
reduce/reduce conflicts: 127 (-49)
やっぱ空の規則をつくりすぎるのよくないもう一つの例。
topdecl: 'class' sctx_opt tycls tyvar 'where' cdecls
ctx_opt: context '=>'
| {- empty -}
こんななのだが、context の最初にも tycls と同じ文字列が来てもいいので曖昧。
GHC のソースをみると、A -> (context '=>' |) のような非終端記号をつくるので
はなく、
tycl_hdr -> context '=>' tycls | tycls
のようにしてあった。こうすることで、問題となる還元規則がなくなり、
パーサは tycls が context の一部なのかそうでないのか判明するまで複数のポインタを
持てるようになる。(「lex&yacc プログラミング」p.301)
ただ、このあたりは、上のように文法を書き直すだけじゃなくて、もうちょっと整理しないとだめっぽい。
qconid, qtycls などもいっぱい衝突している。(軒並 qconid に還元しようとしたり)
まいったな、まだまだだな。
]]>Haskell x Android プロジェクト(仮)
Tigerbook は基礎編を一通りこなしたので、まえからやりたかった「Haskell で Haskell コンパイラを書いてみる」プロジェクトに移行。
Lexer を一通り書いて、Parser の作成と Absyn (抽象構文)の作成を並行してやる感じかなぁと思いつつとりかかっていた。
んが、「一通りこなした」部分もきちんと勉強しなおそうというのも同時にやっていて、正規言語やら文脈自由言語やらその解析方法やらも復習している。そのために、結局 Dragon book も入手してしまった。で、再帰下降パーサといえば、『プログラミング Haskell』にもそういう章があったなと8章を見直したり。ふむふむ。あそこに述べられているのは、バックトラックのある(予測型ではない)再帰下降パーサーだな。左端のくくり出しもして LL(1) 文法に直すとこまでやっているのに、予測型再帰下降パーサにはせずに終わっている。
そりゃそうと、そんな風に Monadic Parser を復習してたら、これ の書き方がわかったので、Happy による Parser を作らなくても Lexer のデバッグができるようになった。で、案の定、いろいろ間違ってた。
いずれも、直したつもり。Lexer の確認のために今日用意したテストケースは 4つ
test1.hs は、Haskell 2010 の Figure 2.1 にあるもの。
$ sample/lexer_sample < testcases/test1.hs
[TModule (AlexPn 0 1 1),TConid ("AStack",AlexPn 8 1 8),TOParen (AlexPn 15 1 14),TConid ("Stack",AlexPn 18 1 16),TComma (AlexPn 24 1 21),TVarid ("push",AlexPn 27 1 23),TComma (AlexPn 32 1 27),TVarid ("pop",AlexPn 35 1 29),TComma (AlexPn 39 1 32),TVarid ("top",AlexPn 42 1 34),TComma (AlexPn 46 1 37),TVarid ("size",AlexPn 49 1 39),TCParen (AlexPn 55 1 44),TWhere (AlexPn 58 1 46),TVOCurly (AlexPn 66 2 1),TData (AlexPn 66 2 1),TConid ("Stack",AlexPn 72 2 6),TVarid ("a",AlexPn 79 2 12),TEqual (AlexPn 82 2 14),TConid ("Empty",AlexPn 85 2 16),TVBar (AlexPn 107 3 14),TConid ("MkStack",AlexPn 110 3 16),TVarid ("a",AlexPn 119 3 24),TOParen (AlexPn 122 3 26),TConid ("Stack",AlexPn 124 3 27),TVarid ("a",AlexPn 131 3 33),TCParen (AlexPn 133 3 34),TSemi (AlexPn 140 5 1),TVarid ("push",AlexPn 140 5 1),TDColon (AlexPn 147 5 6),TVarid ("a",AlexPn 151 5 9),TRArrow (AlexPn 154 5 11),TConid ("Stack",AlexPn 158 5 14),TVarid ("a",AlexPn 165 5 20),TRArrow (AlexPn 168 5 22),TConid ("Stack",AlexPn 172 5 25),TVarid ("a",AlexPn 179 5 31),TSemi (AlexPn 184 6 1),TVarid ("push",AlexPn 184 6 1),TVarid ("x",AlexPn 191 6 6),TVarid ("s",AlexPn 194 6 8),TEqual (AlexPn 197 6 10),TConid ("MkStack",AlexPn 200 6 12),TVarid ("x",AlexPn 209 6 20),TVarid ("s",AlexPn 212 6 22),TSemi (AlexPn 219 8 1),TVarid ("size",AlexPn 219 8 1),TDColon (AlexPn 226 8 6),TConid ("Stack",AlexPn 230 8 9),TVarid ("a",AlexPn 237 8 15),TRArrow (AlexPn 240 8 17),TConid ("Int",AlexPn 244 8 20),TSemi (AlexPn 251 9 1),TVarid ("size",AlexPn 251 9 1),TVarid ("s",AlexPn 258 9 6),TEqual (AlexPn 261 9 8),TVarid ("length",AlexPn 264 9 10),TOParen (AlexPn 272 9 17),TVarid ("stkToLst",AlexPn 274 9 18),TVarid ("s",AlexPn 284 9 27),TCParen (AlexPn 286 9 28),TWhere (AlexPn 290 9 31),TVOCurly (AlexPn 309 10 12),TVarid ("stkToLst",AlexPn 309 10 12),TConid ("Empty",AlexPn 320 10 22),TEqual (AlexPn 335 10 36),TOBrack (AlexPn 338 10 38),TCBrack (AlexPn 340 10 39),TSemi (AlexPn 356 11 12),TVarid ("stkToLst",AlexPn 356 11 12),TOParen (AlexPn 367 11 21),TConid ("MkStack",AlexPn 369 11 22),TVarid ("x",AlexPn 378 11 30),TVarid ("s",AlexPn 381 11 32),TCParen (AlexPn 383 11 33),TEqual (AlexPn 387 11 36),TVarid ("x",AlexPn 390 11 38),TColon (AlexPn 392 11 39),TVarid ("xs",AlexPn 394 11 40),TWhere (AlexPn 398 11 43),TVOCurly (AlexPn 404 11 49),TVarid ("xs",AlexPn 404 11 49),TEqual (AlexPn 408 11 52),TVarid ("stkToLst",AlexPn 411 11 54),TVarid ("s",AlexPn 421 11 63),TVCCurly (AlexPn 428 13 1),TVCCurly (AlexPn 428 13 1),TSemi (AlexPn 428 13 1),TVarid ("pop",AlexPn 428 13 1),TDColon (AlexPn 436 13 5),TConid ("Stack",AlexPn 440 13 8),TVarid ("a",AlexPn 447 13 14),TRArrow (AlexPn 450 13 16),TOParen (AlexPn 454 13 19),TVarid ("a",AlexPn 456 13 20),TComma (AlexPn 458 13 21),TConid ("Stack",AlexPn 461 13 23),TVarid ("a",AlexPn 468 13 29),TCParen (AlexPn 470 13 30),TSemi (AlexPn 475 14 1),TVarid ("pop",AlexPn 475 14 1),TOParen (AlexPn 481 14 5),TConid ("MkStack",AlexPn 483 14 6),TVarid ("x",AlexPn 492 14 14),TVarid ("s",AlexPn 495 14 16),TCParen (AlexPn 497 14 17),TEqual (AlexPn 504 15 3),TOParen (AlexPn 507 15 5),TVarid ("x",AlexPn 509 15 6),TComma (AlexPn 511 15 7),TCase (AlexPn 514 15 9),TVarid ("s",AlexPn 520 15 14),TOf (AlexPn 523 15 16),TVOCurly (AlexPn 526 15 19),TVarid ("r",AlexPn 526 15 19),TRArrow (AlexPn 529 15 21),TVarid ("i",AlexPn 533 15 24),TVarid ("r",AlexPn 536 15 26),TWhere (AlexPn 539 15 28),TVOCurly (AlexPn 545 15 34),TVarid ("i",AlexPn 545 15 34),TVarid ("x",AlexPn 548 15 36),TEqual (AlexPn 551 15 38),TVarid ("x",AlexPn 554 15 40),TCParen (AlexPn 556 15 41),TVCCurly (AlexPn 588 17 1),TVCCurly (AlexPn 588 17 1),TSemi (AlexPn 588 17 1),TVarid ("top",AlexPn 588 17 1),TDColon (AlexPn 596 17 5),TConid ("Stack",AlexPn 600 17 8),TVarid ("a",AlexPn 607 17 14),TRArrow (AlexPn 610 17 16),TVarid ("a",AlexPn 614 17 19),TSemi (AlexPn 619 18 1),TVarid ("top",AlexPn 619 18 1),TOParen (AlexPn 625 18 5),TConid ("MkStack",AlexPn 627 18 6),TVarid ("x",AlexPn 636 18 14),TVarid ("s",AlexPn 639 18 16),TCParen (AlexPn 641 18 17),TEqual (AlexPn 644 18 19),TVarid ("x",AlexPn 647 18 21)]
うーん、いっぱいだ。あとで見よう。ってことで、小さいやつを用意したのがあとの3つ。
$ sample/lexer_sample < testcases/test2.hs
[TVOCurly (AlexPn 0 1 1),TVarid ("main",AlexPn 0 1 1),TEqual (AlexPn 6 1 6),TVarid ("putStrLn",AlexPn 9 1 8),TString ("Hello",AlexPn 19 1 17)]
$ sample/lexer_sample < testcases/test3.hs
[TModule (AlexPn 0 1 1),TConid ("Main",AlexPn 8 1 8),TWhere (AlexPn 14 1 13),TVOCurly (AlexPn 21 3 1),TVarid ("main",AlexPn 21 3 1),TEqual (AlexPn 27 3 6),TDo (AlexPn 30 3 8),TVOCurly (AlexPn 35 4 3),TVarid ("putStr",AlexPn 35 4 3),TString ("Hello",AlexPn 43 4 10),TSemi (AlexPn 54 5 3),TVarid ("putStrLn",AlexPn 54 5 3),TString (", world!",AlexPn 65 5 12)]
$ sample/lexer_sample < testcases/test4.hs
[TVOCurly (AlexPn 0 1 1),TVarid ("f",AlexPn 0 1 1),TVarid ("s1",AlexPn 3 1 3),TVarid ("s2",AlexPn 7 1 6),TEqual (AlexPn 11 1 9),TVarid ("putStrLn",AlexPn 14 1 11),TVarsym ("$",AlexPn 24 1 20),TVarid ("s1",AlexPn 27 1 22),TVarsym ("++",AlexPn 31 1 25),TVarid ("s2",AlexPn 35 1 28),TSemi (AlexPn 40 3 1),TVarid ("main",AlexPn 40 3 1),TEqual (AlexPn 47 3 6),TDo (AlexPn 50 3 8),TVOCurly (AlexPn 55 4 3),TString ("foo",AlexPn 55 4 3),TBackquote (AlexPn 62 4 9),TVarid ("f",AlexPn 64 4 10),TBackquote (AlexPn 66 4 11),TString ("bar",AlexPn 69 4 13),TSemi (AlexPn 78 5 3),TVarid ("putStrLn",AlexPn 78 5 3),TString ("Hello!",AlexPn 89 5 12)]
最後の test4.hs が今日見つけた問題の確認用で、do 節の最初のトークンが文字列だった場合のやつ。直す前は、文字列の後ろに仮想 ocurly が挿入されてしまっていた。
test1 の結果が正しいかどうかは、明日みましょ。
]]>そろそろ出来てきたので、というか、今年中に動かすのが目標だったので、ちょっと無理やりにでも動かしてみることにする。
Tiger 言語から Dalvik アセンブリ言語へのコンパイラはほぼできていて、Dalvik アセンブリ言語から APK ファイルをつくるあたりもだいたいできているので、ちょっと手を加えてやれば、動かしてみることができるはず、なのだ。
えーと、なにが未だかというと、レジスタ割付けがまだなので(まだ Tiger Book は10章途中なの)、今回は、そこだけ人手で。
Tiger 言語のソースはこちら:
print("Hello, world!")
これを、現状のコンパイラでコンパイルした結果がこちら:
.class public Luhideyuki/daat/DaatProg;
.super Ljava/lang/Object;
.method public constructor <init>()V
.registers 1
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
---- prog ----
:L1
const-string t4, "Hello, world!"
move-object v0, t4
invoke-static {v0}, Luhideyuki/daat/DaatRuntime;->print(Ljava/lang/String;)Ljava/lang/Integer;
move-result-object t5
const t7, 0
new-instance t6, Ljava/lang/Integer;
invoke-direct {t6, t7}, Ljava/lang/Integer;-><init>(I)V
return-object t6
goto :L0
:L0
まだ、関数の prologue (宣言部分とか) が出力されていなかったり、レジスタ番号が仮のまま(t4, t5 とかは一時変数の番号そのまま)です。そこで、今回は人手で少し手を加えてあげます:
.class public Luhideyuki/daat/DaatProg;
.super Ljava/lang/Object;
.method public constructor <init>()V
.registers 1
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public static main([Ljava/lang/Object;Ljava/lang/Integer;)Ljava/lang/Integer;
.locals 5
:L1
const-string v1, "Hello, world!"
move-object v0, v1
invoke-static {v0}, Luhideyuki/daat/DaatRuntime;->print(Ljava/lang/String;)Ljava/lang/Integer;
move-result-object v2
const v4, 0
new-instance v3, Ljava/lang/Integer;
invoke-direct {v3, v4}, Ljava/lang/Integer;-><init>(I)V
return-object v3
#goto :L0
#:L0
.end method
これを、別途用意したランタイム関数といっしょに assembly, apk builder etc. にかけて…
できました!:
Hello, world! だけではナンなので、もうちょっとだけプログラムっぽいのもやってみる。
これ:
for i := 1 to 5 do print("Hello! ")
これを、現状のコンパイラにかけたのがこれで、
.class public Luhideyuki/daat/DaatProg;
.super Ljava/lang/Object;
.method public constructor <init>()V
.registers 1
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
---- prog ----
:L4
const t7, 1
new-instance t6, Ljava/lang/Integer;
invoke-direct {t6, t7}, Ljava/lang/Integer;-><init>(I)V
move-object t4, t6
const t9, 5
new-instance t8, Ljava/lang/Integer;
invoke-direct {t8, t9}, Ljava/lang/Integer;-><init>(I)V
move-object t5, t8
:L1
check-cast t4, L/java/lang/Integer;
invoke-virtual {t4}, Ljava/lang/Integer;->intValue()I
move-result t10
check-cast t5, L/java/lang/Integer;
invoke-virtual {t5}, Ljava/lang/Integer;->intValue()I
move-result t11
if-le t10, t11, :L2
const t13, 0
new-instance t12, Ljava/lang/Integer;
invoke-direct {t12, t13}, Ljava/lang/Integer;-><init>(I)V
return-object t12
goto :L3
:L2
const-string t14, "Hello! "
move-object v0, t14
invoke-static {v0}, Luhideyuki/daat/DaatRuntime;->print(Ljava/lang/String;)Ljava/lang/Integer;
move-result-object t15
const t17, 1
new-instance t16, Ljava/lang/Integer;
invoke-direct {t16, t17}, Ljava/lang/Integer;-><init>(I)V
check-cast t4, Ljava/lang/Integer;
check-cast t16, Ljava/lang/Integer;
invoke-virtual {t4}, Ljava/lang/Integer;->intValue()I
move-result t19
invoke-virtual {t16}, Ljava/lang/Integer;->intValue()I
move-result t20
add-int t19, t19, t20
new-instance t18, Ljava/lang/Integer;
invoke-direct {t18, t19, Ljava/lang/Integer;-><init>(I)V
move-object t4, t18
goto :L1
:L3
手作業でレジスタ割付けなど少し手をくわえたのがこれ:
.class public Luhideyuki/daat/DaatProg;
.super Ljava/lang/Object;
.method public constructor <init>()V
.registers 1
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public static main([Ljava/lang/Object;Ljava/lang/Integer;)Ljava/lang/Integer;
.locals 21
:L4
const v7, 1
new-instance v6, Ljava/lang/Integer;
invoke-direct {v6, v7}, Ljava/lang/Integer;-><init>(I)V
move-object v4, v6
const v9, 5
new-instance v8, Ljava/lang/Integer;
invoke-direct {v8, v9}, Ljava/lang/Integer;-><init>(I)V
move-object v5, v8
:L1
check-cast v4, Ljava/lang/Integer;
invoke-virtual {v4}, Ljava/lang/Integer;->intValue()I
move-result v10
check-cast v5, Ljava/lang/Integer;
invoke-virtual {v5}, Ljava/lang/Integer;->intValue()I
move-result v11
if-le v10, v11, :L2
const v13, 0
new-instance v12, Ljava/lang/Integer;
invoke-direct {v12, v13}, Ljava/lang/Integer;-><init>(I)V
return-object v12
#goto :L3
:L2
const-string v14, "Hello! "
move-object v0, v14
invoke-static {v0}, Luhideyuki/daat/DaatRuntime;->print(Ljava/lang/String;)Ljava/lang/Integer;
move-result-object v15
const v7, 1
new-instance v6, Ljava/lang/Integer;
invoke-direct {v6, v7}, Ljava/lang/Integer;-><init>(I)V
check-cast v4, Ljava/lang/Integer;
check-cast v6, Ljava/lang/Integer;
invoke-virtual {v4}, Ljava/lang/Integer;->intValue()I
move-result v9
invoke-virtual {v6}, Ljava/lang/Integer;->intValue()I
move-result v2
add-int v9, v9, v2
new-instance v8, Ljava/lang/Integer;
invoke-direct {v8, v9}, Ljava/lang/Integer;-><init>(I)V
move-object v4, v8
goto :L1
#:L3
.end method
そして、実行結果がこちら:
もうすこし複雑なプログラムを試すのは、レジスタ割付けを実装してからにしよう。
い、いちおう、今年中に動かした…かな?
]]>