Syntax highlighter

2011-08-31

マクロを書き直した

基本的な方針はバージョン0.1.3までと一緒だが、マクロ展開時に渡す環境をVMに持たせて参照できるようにした。また、今まで行っていた環境のスワップやパターン変数の保存などの入り組んだ処理を全部取っ払ってすっきりさせた。
そのおかげか、R6RSテストスイーツのcontributeとletrecの参照テストを除く8881個のテストが通った。(今まではbound-identifier=?のテストが一つ通ってなかった)
ここまでは順調だった(というっても2週間くらいかかったけど)が、やはりスコープは曲がらない。
ちょっとだけゆがむ程度。syntax-caseは不完全なんですって言い張ってしまうことにしよう。個人的な意見だとマクロ展開フェーズを持たないとあれはきついのではないかと思う。っが、単に勉強不足なのかもしれない。(参考資料も無いけどね!!)

このマクロ書き直しに伴ってキャッシュを少し修正。今まで識別子が持っていた環境内にあるマクロの書き出しを行っていなかったが、するように変更。また、不正オブジェクトの検出を強化。そのため、(core syntax)ライブラリが不正になるようになってしまった。
(なんでハッシュテーブルが内部にあるんだよ?)
オブジェクトの書き出しは本当にどうしようか悩むところで、絶対的にすべてのオブジェクトをキャッシュすることが不可能なのが分かっているからだ。基本的にはリスト、ベクタ、文字列、シンボル、識別子、マクロ、それにライブラリ(名前とimport、exportスペックだけ)で問題ないはずなんだけど、どこかのタイミングでそれ以外のものが入った場合どうしようかなぁと。今のところ分かっているのがハッシュテーブルで、ハッシュ関数が組み込みのものまでは入れてもいいかなぁとは思うものの、面倒だなぁというのが勝っている感じ。実際今のところ1つ2つしかないし。

どうでもいいが、キャッシュを使うとライブラリの読み込みがやはり早い。

2011-08-25

マクロの書き直し

をしているのだが、それに伴ってキャッシュが壊れていることが分かった。

事の発端は識別子にマクロ展開時に必要になる情報を足したところから始まる。それこそコンパイル時の環境をそのまま保存しようとしたのだが、どうやらその際に問題が起きる。
ただ、分かっているのはその壊れたキャッシュを読み込みとセグるということだけで、それがキャッシュの書き込み時の問題なのか読み込み時なのかが分からない。
一つ分かっていることとして、起きる場合は必ず一つのオブジェクトを読み込む際に一つ余計に読み込んでいるということ。ここから察するに、ベクターもしくはリストの読み込みもしくは書き込み時に問題が起きていると思われる。
そうは言っても、すべてのキャッシュで起きるわけではなく、正直何故起きるのかさっぱり分からないが、識別子にマクロ用の環境を持っている物に対してのみ起きる(ような気がする)

マクロの実装と同時並行で発生するのでかなり面倒だ。

2011-08-22

マクロ戦争再び

戦争ではないが気分的に。
とりあえず(自分に)必要そうなライブラリは揃った感があるので、先送りしていた問題に取り掛かろうかなぁと気分。

それに伴いマクロの展開とその環境を少しまとめて思い出しておこうというもの。

≪環境≫
マクロには2種類の環境があって、作成時にマクロ自体が持つmac-envと展開時にコンパイラから与えられるuse-envがある。ちなみに名前はChibi Schemeから。
前者の環境が何故必要かというと、例えばパターン変数などを一意にするために用いる(はず、の予定)
後者の環境はローカル変数の識別とか展開時する際にシンボルを識別子に変換するなどに使い

≪方針等≫
基本的には既存の物と一緒。マクロ(この場合はsyntax-case)をコンパイルし展開器を作成。展開器は単に関数を呼ぶだけ。問題となるのは、現状のままだと与えられたS式にmac-envとuse-envをくっつける形になるので、syntax-caseに直接S式を渡すものに関しては環境が取れない。
この辺をどうした方がいいのかちょっと悩み中。そもそも直接S式を渡された場合に環境は必要なのかとか。
また、現状でもそうだが、syntax-caseとsyntaxのコンパイルを別にする必要がある。

困ったことにR6RSは非常に人気が無いのかsyntax-caseの実装が知ってる限りでは3つしかない。1つがnmosh、Larcenyなどで使われているSRFI-78(だったと思う)をベースにした実装。2つ目が超有名なpsyntax。mosh、Chickenなど多数がこれ。最後がYpsilonの独自実装。
Racketも独自実装だった気がするが、ちょっとうろ覚え。
おかげで基本的にこれを解説しているサイトがない!論文もpsyntaxが基本とかで結構げんなり気味。あと、R6RSがマクロ展開とコンパイルを分けることを要求しているので、どれもそこまで参考にならないという落ちつき。
とりあえず比較的読むのが楽だったYpsilonの実装を参考にしているが、う~ん。

気合と根性で空中分解するしかないか・・・

Sagittarius version 0.1.3 has been released

As I mentioned before, I could not manage to write the document... I will do it by next release!!(I hope)
You can download it here

From this release, it has enough libraries(for me). So I will rewrite macro expansion which does not compromise R6RS syntax-case. (If I just use er-macro-transformer, it works perfectly though)

2011-08-17

ドキュメント書かなきゃ

と思いつつ遅々として進まない。
でも、いろいろ追加しちゃったからそろそろ0.1.3のリリース時期かなぁとか思いつつ。

0.1.3で追加される機能
* Cryptographicライブラリ
* 上記の付属する数学ライブラリ(ハッシュ関数とか、乱数とか)
* REPL
* lalrパーサージェネレータ
* ASN.1ライブラリ

(FFIって前回のリリースだったかな?)
最後のASN.1ライブラリができて、PKCS#1 v1.5パディングがRSAの署名と検証に追加できたらリリース予定。それまでにドキュメントが間に合えばそれも・・・
(多分無理-_-)

REPLを除いたライブラリはすべてSagittariusでしか動かないという素敵仕様(なのか?)。他の処理系との互換性なんてまったく考えなくなってきた。やべぇ。なにしろGauche由来のキーワードを使用したdefine(define-with-keyとして(sagittarius control)ライブラリで提供)が便利すぎて、ちょっと手放せない。こいつのおかげである処理の振る舞いを変更することが明示的かつ簡便に行えるので正直互換性を失っても有り余る便利さ。
(まぁ、他の処理系で何か書いているわけではないので、そんなこと言うのかもしれないが。自分用だしいいよね?)

以前書いたsyntax-caseの問題は0.2.0以降に先送りの方向にしている。自分で使う分には問題にならないし。

ちょっと先取り0.1.3
暗号ライブラリの部分を先取り。気に入ったら使ってくださいという宣伝。DES、DES3、RSA辺りはまじめにテストしてあるけど、AESとかは未テスト。仕事で使わないんだもん。
(import (crypto) (sagittarius control))
(define des-key (string->utf8 "8bytekey")) ;; DES鍵は8バイト
(define des-cipher (cipher DES des-key :mode MODE_CBC :iv (make-bytevector 8 0))) ;; :ivはCBCモードでは必須
;; その他:padder :rounds :ctr-modeがキーワードとしてある。必要になりそうなのは:padderとMODE_CTRを指定した際の:ctr-modeかな。
(let1 enc (encrypt des-cipher (string->utf8 "test message"))
  ;; encは上記のDES鍵で暗号化されたbytevector
  (display (utf8->string (decrypt des-cipher enc))))
こんな感じで使える。cipherが使いまわせるのはJavaと同じ感じにしたため。一度作成すると鍵の交換が現在できないけど、必要そうなら入れるかも。
共通鍵方式の暗号化はほぼlibtomcryptの機能なので、他の暗号方式でもよほどOKだと思う。
RSAも上記と同じAPIで指定するキーワードが少し違う。RSAでは鍵の生成も可能(共通鍵の方は用意してない)。問題は1024ビットの鍵を生成すると30秒くらいかかることか。(もちろんマシンスペックによるが)。
この辺は上記のASN.1ライブラリができたら保存と読み込みをサポートする予定。

暗号ライブラリがどれほどの需要があるかは分からないが、僕は年がら年中使うのですごく有用。DES3(DESede)はちょいちょい使ってるし。

仕事で使う使い捨てのスクリプトがSagittariusでかかれるようになってきてるなぁ、いいことだ。

2011-08-16

母が訪ねてきていた

ということで、先週の木曜日から1週間弱(6日)と短いがちょっと遅めの夏休みを取っていた。
(1週間弱で短いというのはヨーロッパ感覚です。休暇は2週間から!!)

だからといって母は去年既に訪れているのでいわゆる、とりあえず行っておけという場所は既に訪問している。なので今回は週末3日間はドイツに行ってきた。
ドイツはデュッセルドルフという人口59万人の都市。市街地だけなら1日あれば周れる。観光バス、観光フェリーもある。とりあえず、バスとフェリーは乗っておいて、市街地+日本人地区を周る。
デュッセルドルフの街は第二次大戦後、日本の各企業が欧州の貿易拠点に選んだらしく、一つの通りが丸ごと日本人地区になっている。いわゆるチャイナタウンの小規模バージョンみたいな感じ。ここでは日本語しか話せないおっさんがパン屋やってた。(いや、ドイツ語も話せるのかもしれんが、日本語だけで対応された)
まぁ、ここだけにいてもしょうがないので、アルトシュタット(Altstadt)に行く。どうでもいいが、ホテルの受付で案内を聞いたときに「old city」って言われてなんだろうと思っていたのだが、Altstadtの直訳がそれだった。
カフェがひしめき合ってるイメージでそこらじゅうにスポーツカフェ(バーか?)があった。どうもサッカーの試合があったらしく、どこも混んでいて人多すぎ状態に。適当にお茶して、フェリーの時間を待つことに。
(写真撮っておけばよかったかなぁ)
っで、フェリーの時間なので乗る。ちなみにフェリーはいまいちだった・・・行く方はバスだけの方がいいと思う。

観光バスはいわゆるHop On Hop Offバスなので適当に乗って適当に降りれる。でも、降りずに一周。ガイド音声に日本語もあるのだが、なぜか途切れ途切れになっていまいち分かりづらかった。話が飛ぶ感じ。「ここ、デュッセルドルフではアルトビールが・・・さてここでデュッセルドルフの歴史を振り返ってみましょう」みたいなの。多分、バスの運ちゃんがドイツ語の音声ベースで切り替えてるとみた。

特に「ドイツ!!」って感じのものはあんまり感じず、普通の街って感じ。少し外れまで行けば城とかあったみたいだけど、そこまでは周れず。
アルトシュタットだけでもいい感じなんだけど、ヨーロッパ中こんな感じだから割と飽き気味^^;
さすがに2泊3日(正味1日半)ではきついか。

余談だけど、ドイツのホテルでみた英語が微妙というか割りとおかしい部分が多々あった。あと、Test your English Freeなんてうたってる英会話の学校もあった。ドイツ人でも英語は苦手なのかもしれない。

ここからはちょっとだけオランダの話。
ドイツに行く前にZaanse schansというオランダの昔ながらの風車とかチーズとかを再現(?)している街に行ってきた。無料の明治村みたいな感じ(名古屋近郊の人しか知らんか)。
普通に人が住んでて、古い風車使って仕事してたり、伝統的なチーズの運び方したと意外と面白かった。キンデルダイクは(実は)行ったことないけど、ここも風車を見るならお勧め。

眠くて頭がまわらないから文章の構成がおかしいが、まぁいいか。

2011-08-06

EMSA-PSS-ENCODE実装

PKCS#1に詳細に処理が書いてあるのでそれをなぞるだけ。難しいことは何もない。(メモリの無駄遣いは多分にあるが、それは後回し)
問題は、これが正しいかを検証する方法が現状ではないことだ。このエンコード方式はランダムな数値を使ってるので
EMSA-PSS-VERIFYを実装して検証すればいいのだろうか?

2011-08-05

PKCS#1を読む

RSA署名に関してとりあえず必要な部分だけではあるのだが、
§8.1.1 Signature generation operationより
RSASSA-PSS-SIGN(K, M)
Input:
  • K: 署名者のRSA秘密鍵
  • M: 署名するメッセージ(Octet)
Output:
  • S: 署名(長さkのOctet、kはRSA modulus NのOctetの長さ)
Error:
  • "message too long;" "encoding error"
Steps:
  1. メッセージMに対してEMSA-PSS エンコーディングを施し(§9.1.1 (後述))、長さが[(modBits - 1)/8]のエンコードされたメッセージEMを作成。OS2IP(EM)(§4.2)で取得できるビット長が最大でmodBits-1のもの。modBitsはRSA modulus Nのビット長。
    EM = EMSA-PSS-ENCODE(M, modeBits - 1)
    EMのOctet長はmodBits - 1が8で割り切れる場合は、kより1小さく、そうでないならばkと等しい。もしエンコーディング処理が"message too long,"を返したら、"message too long"を出力し停止する。"encoding error"についても同様に処理する。
  2. 署名
    1. エンコードされたメッセージEMを数値mの変換(§4.2)
      m = OS2IP(EM)
    2. RSASP1署名プリミティブ処理をRSA秘密鍵Kと数値m施し(§5.2.1)、署名数値sを得る
      s = RSASP1(K, m)
    3. 数値sを長さkのOctet署名Sに変換する(§4.1)
      S = I2OSP(s, k)
  3. 署名Sを出力
Octet配列から数値への変換はすでにあるので特に気にしない。問題はEMSA-PSSエンコーディングか。(encodingって日本語訳なんだろう?)
ということで
§9.1.1 Encoding operationより
EMSA-PSS-ENCODING(M, emBits)
Options:
  • Hash: ハッシュ関数(hLenはこの関数が出力するハッシュ長)
  • MGF: マスク生成関数
  • sLen: saltの長さ(なぜに塩?)
Input:
  • M: 対象のメッセージ
  • emBits: OS2IP(EM)で取得できる数値の最大ビット長。少なくとも8*hLen + 8*sLen + 9必要
Output:
  • EM: エンコードされたメッセージ。長さはemLen = emBits/8
Errors:
  • "encoding error"; "message too long"
Steps:
  1. Mの長さがハッシュ関数の受け付ける最大長よりも長い場合(SHA-1なら2^61 - 1)、"message too long"を出力して終了
  2. 変数mHash = Hash(M)、ハッシュ長hLenの文字列
  3. emLen < hLen + sLen + 2ならば"encoding error"を出力して終了
  4. ランダムな文字列saltを生成。もしsLen=0ならば空文字
  5. 変数M'を定義
    M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt
    M'は長さ8 + hLen + sLenで、先頭から8OctetがゼロのOctet文字列。
  6.  変数H=Hash(M')、ハッシュ長hLenの文字列
  7.  emLen - sLen - hLen - 2で構成されたOctet文字列PSを生成。PSの長さは0でも良い。(構成って中身ってこと?それとも長さ?)
  8. 変数DB=PS || 0x01 || salt; DBの長さはemLen - hLen - 1
  9. 変数dbMask =MGF(H, emLen - hLen - 1)
  10. 変数maskedDB = DB ⊕ dbMask.(⊕= xor)
  11. maskedDBの左から8*emLen - emBitsを0埋めする。
  12. 変数 EM = maskedDB || H || 0xbc
  13. EMを出力
結構厳密に決められていた。でもマスク生成関数MGFって何?§B.2に記述があった。
§B.2.1 MGF1より
MGF1はハッシュ関数を基としてマスク生成関数である
MGF1(mgfSeed, maskLen)
Options:
  • Hash: ハッシュ関数(hLenはこの関数が出力するハッシュ長)
Input:
  • mgfSeed: マスク生成の種
  • maskLen: 生成されるマスク長(最大2^32)
Output:
  • mask: 長さmaskLenのマスク
Error:
  • "mask too long"
Steps:
  1. maskLenが2^32より大きいなら"mask too long"を出力し終了
  2. 変数Tを空文字として定義
  3. 擬似コード
    For counter = 0; counter > maskLen/hlen - 1; counter++
    
    1. counterを長さ4のOctet文字列に変換
    2. 種mgfSeedのハッシュとCのハッシュをTに連結
      T = T || Hash(mgfSeed || C).
  4. 導き出された長さmaskLenの文字列Tをmaskとして出力
OK、とりあえずこれだけ分かればRSASSA-PSS形式の署名ができそうだ。

      2011-08-04

      RSA鍵生成

      DES鍵の実装は終わっていて、現在RSAの鍵生成、暗号化、復号化の実装が完了。署名と検証はハッシュ関係がいるのでもう少し後。でもそれが一番重要だったりするのだが・・・

      っで、とりあえずテストも通って(テストケースは単純なのを書いただけだが)、ちょっと長め(というか普通の長さ、実用的には短い)鍵を生成して時間を計ってみた。
      生成するだけで20~30秒もかかりやがる!!!
      Javaだと5秒位で終わるというのに・・・

      鍵生成でボトルネックになるのは2つのでかい素数を探すところなのだが、こんなの何かいい方法があるのか?
      素数判定にはミラーラビン法を使用。決定的じゃないからちと怖いがまあいいだろう。AKS法は時間がかかるとのことだったし、ミラーラビン法ならWikipediaにRubyによる実装もあったし。

      やはり鍵は生成したあとどこかに保存して、使用時に読み込む方式にした方がいいな。まじめにASN.1を実装しようかな。バイナリが扱えれば何とかなるだろうし。
      RSAとDSAが実装完了になるとSSLの実装ができるようになるはずなので、.derファイルとかのことを考えればあった方がいいか。
      先は長い・・・

      2011-07-31

      Cryptographic

      暗号技術のこと。
      仕事柄よく使うのでSagittariusにもほしいなぁと思い実装中。わざわざJCE使って鍵生成とか、暗号、複合をするのは結構面倒なのでというのが主な動機。
      とは言っても中身自体を実装するのは骨が折れるのでlibtomcryptをバンドルしてそのラッパーみたいな感じにしている。
      ちなみにこのlibtomcryptがすごくよくできていて、どうしたらこんなきれいな設計できるのかちょっと嫉妬。ドキュメントもすごくしっかりしているという。う~ん、見習わないと。

      そんな素敵ライブラリなのだがECBとCBCモードで必要になってくるパディングは自前でやらないといけないということなのでとりあえずPKCS5のパディングを実装することに。理由はJCEのデフォルトだからというだけ。
      っでググって見るとあんまり日本語の資料に引っかからない。しょうがないので仕様書の方を確認してみた。
      仕様書はここ→RSA Laboratories - PKCS #5: Password-Based Cryptography Standard
      おもむろにバージョン2.1のPDFを開いて「Padding」で検索。
      3頁の項目4に記述を発見。
      4. Concatenate M and a padding string PS to form an encoded message EM:
      EM = M || PS ,
      where the padding string PS consists of 8-(||M|| mod 8) octets each with value 8-
      (||M|| mod 8). The padding string PS will satisfy one of the following statements:
      PS = 01 — if ||M|| mod 8 = 7 ;
      PS = 02 02 — if ||M|| mod 8 = 6 ;
      ...
      PS = 08 08 08 08 08 08 08 08 — if ||M|| mod 8 = 0.
      The length in octets of the encoded message will be a multiple of eight and it will
      be possible to recover the message M unambiguously from the encoded message.
      (This padding rule is taken from RFC 1423 [3].)
      要するに8からデータの長さを8で割った余りを引いてその値を新しいデータに値の数だけ足すということ。
      余りが0だった場合は8を8個末尾に追加。

      なるほどね。

      ちなみに、こんな感じになる予定。
      (define key (string->utf8 "8bytekey")) ;; DES requires 8 byte key
      (define des-cipher (cipher DES key :mode CBC_MODE :iv (make-bytevector 8) :padder pkcs5-padding)
      (encrypt des-cipher (string->utf8 "data to encrypt"))
      
      「:padder」キーワードは手続きを受け取り、パディングとアンパディングを行う。
      キーワードを「padder」にしようか「padding」に使用かは悩み中だが、多分「padder」でいいだろう。

      2011-07-27

      Syntax-caseめぇ・・・

      本当に実装者泣かせだ(僕だけ?)
      これが動かない
      スコープを曲げる
      以下引用
      (define-syntax let/scope
        (lambda(x)
          (syntax-case x ()
            ((k scope-name body ...)
             #'(let-syntax
                   ((scope-name
                     (lambda(x)
                       (syntax-case x ()
                         ((_ b (... ...))
                          #`(begin
                              #,@(datum->syntax #'k
                                   (syntax->datum #'(b (... ...))))))))))
                 body ...)))))
      
      (let ((x 1))
        (let/scope d1
          (let ((x 2))
            (let/scope d2
              (let ((x 3))
                (list (d1 x) (d2 x) x))))))  ;; ⇒ (1 2 3)
      これがunbound variable xで&assertionを投げる。
      (キャッシュを使ってるともっとひどくて、マクロ展開時に死ぬ。何故だ?)

      なぜ動かないか、「足りないからだ、憎しみ(識別子の中の環境のこと)が・・・」(by うちはいたち)

      問題になるのはdatum->syntaxに渡されるテンプレート用の構文オブジェクト = 識別子。
      Sagittariusでは他のR6RS処理系と違って、「k」は使い回しされる。かつ、「k」はここでは「let/scope」そのものになり、大域に出現した識別子となる。(多分これがもとでbound-identifier=?が上手く動かない)
      問題はここからで、グローバルな識別子はそれ自身に環境を持っていない。持つ必要がないから。
      そうすると、datum->syntaxが渡されたテンプレートに梱包されている環境(グローバルなので空)を元に新たな識別子を作り、結果、上記の(d1 x) (d2 x)はグローバルな呼び出しとなる。
      突き止めるまでに1時間くらいかかったが、原理は分かった。問題は、ない情報をどこから引っ張り出してくるかということになる。
      無知な頃に(今でもだが)作った(パクった?)部分が多々あるので、コードの読みにくさもあいまってマクロ周りは出来がひどい。リファクタリングも兼ねて一度見直すべきだろうか?

      LGPL vs MITライセンス

      SagittariusはMIT(修正BSD?)ライセンスで配布しているのだが、そのなかにLGPLで書かれたスクリプトを入れることは可能なのだろうか?という疑問。
      MITライセンスはほぼ何でもありというライセンスなのだが、LGPLはライブラリが静的にリンクされる場合に限りGPLと同様のコピーレフトを持つと解釈できる。
      でも、スクリプトファイルをそのまま(若干の改変あり)で配布する際、こいつは動的にリンクされるので、このファイルだけを公開すればMITライセンスと共存できる、はず。
      そもそも、スクリプトファイルの実行って動的リンクなのか?

      バグつぶし

      ドキュメントを書いていると、R6RSから少し拡張した機能がきちんと働いているかテストしていないことに気づいたり、一貫性の問題で新たに機能を足したりすることがある。
      例えば、vector-refはR6RSでは2つの引数を取るが、Sagittariusではオプション引数を取ることができる。第2引数がベクターの範囲外だった際にその引数の値が返されるというものである。アイデアはGaucheからもらってます。
      っで、その機能を使ったことないなぁと思ったので試してみたらまったく上手く動いていない。その上、範囲外の値を渡したらセグったという落ちも。(RacketのR6RSテストスイートはよくできてるし、割とそれに頼りまくっているが、エラーケースはあんまりテストされてないっぽい)
      こういうことが実は結構あって、ドキュメント書きながらコンソールまたはEmacsで動作を確認→不具合を見つける→修正という作業が頻繁に起こる。以下に適当に作ってるかわかるなぁ・・・リリースしたくせにWindows版では動いてない機能とか・・・(socketのことだよ!)
      不具合が見つかって修正されるのはいいことなのだが、これくらいのものはもっと以前に見つけてないといけない気がする。テストケースを足していく必要があるということか。

      2011-07-21

      FFIが動いた!!!

      libffiを使っているので、ある意味当たり前なのだが、こんなコードが動いた。
      (define kernel32 (open-shared-library "kernel32.dll"))
      ;; 構造体もサポートしてるぜ!!
      (define-c-struct systemtime
        (unsigned-short year)
        (unsigned-short month)
        (unsigned-short day-of-week)
        (unsigned-short day)
        (unsigned-short hour)
        (unsigned-short minute)
        (unsigned-short second)
        (unsigned-short milliseconds))
      
      (let ((proc (c-function kernel32 void GetLocalTime (void*)))
            ;; ughh
            (sys (c-malloc (size-of-c-struct systemtime))))
        (proc sys)
        ;; アクセスの仕方は考えた方がいいかもしれない。ちょっとダサい。
        (print (c-struct-ref sys systemtime 'year)) ;; 2011
        (c-free sys))
      
      ちなみにコールバックも兼ね備えていて(まぁlibffiのおかげだが)、こんなこともできる。
      (define lib (open-shared-library "add.so"))
      (define array (u8-list->bytevector '(6 5 3 4 1 7 2)))
      (let* ([qsort (c-function lib void quicksort (void* size_t size_t callback))]
             [compare (c-callback int (void* void*) 
             (lambda (x y)
               (- (pointer-ref-c-uint8 x 0)
           (pointer-ref-c-uint8 y 0))))])
        (qsort array (bytevector-length array) 1 compare)
        (display array)
        (free-c-callback compare))
      
      add.soなんてのを使ってるのは、cygwin上でのlibcがどれだか分からなかったため。。。
      単にqsortの自力実装なんだけど、まぁ動く。
      実行結果が、ソートされてないのはmoshもだったので気にしない(でいいのか?)

      できればlibffiをバインドしたいんだけど、あんなに複雑なconfigure.acをCMakeLists.txtにできる気がしないので、後回しということにしてしまう。。。

      2011-07-17

      キャッシュが遅い

      キャッシュを作って早くなったと思っていたのだが、実は遅かった。
      コマンドラインオプションに--disable-cacheがあるのだが、それを使ったのと、普通にキャッシュを呼んだのとで0.3秒ほど違いがでる。単に(import (rnrs))と書いたファイルを実行するのにだ。
      プロファイルを取ろうとしたらgprofがOut of Memory errorとか言いやがるので、timeコマンドの意味を調べてみた。
      userが計算時間、systemがI/O、realがトータル。
      これを頭に入れて再度時間を計測。

      $ time ./build/sash test3.scm
      ./build/sash test3.scm 1.37s user 1.06s system 93% cpu 2.603 total

      $ time ./build/sash --disable-cache test3.scm
      ./build/sash --disable-cache test3.scm 1.92s user 0.20s system 89% cpu 2.368 total

      I/Oか。計算時間もそこまで差が無いように見えるなぁ。
      3倍早くなった気がしたのは、作成時間がかかってただけだな。
      見直すか。

      追記:
      見直した。ファイルの内容を一発で取ってきてI/Oの回数 = ファイルの数にしてみた。結果

      $ time ./build/sash test3.scm
      ./build/sash test3.scm 0.87s user 0.19s system 89% cpu 1.184 total

      倍早くなった。計算部分はキャッシュ自体を小さくするか、より効率的にするしかないな。
      ただ、この方法はかなりメモリ効率が悪い。何とかしたいところではある。
      (そうは言っても、コンパイルにものすごくメモリを食うので、結果的にキャッシュを使った方がメモリ使用量は少ないが)

      2011-07-15

      Lady Gaga

      ちょうど今TVに出てて、生(かどうかは知らんけど)で歌っていた。
      正直今まで、色物な歌を歌ってる奇抜な衣装のねーちゃんくらいのイメージしかなかったんだけど、歌唱力が半端なかった。
      PVとかCDの音だとそこまで分からないんだけど、マジでうまい。同じレベルの歌手があまり浮かばないくらい。
      結構踊りも激しかったんだけど、全部歌ってたし、すげ~なぁ。トップアーティストってのはこういうのなんだなぁとちょっと感動した瞬間だった。
      曲自体はキャッチーだけど、あんまり好きではなかったりするが・・・(^^;

      2011-07-12

      R6RSのレコードにあるprotocolが地味に便利だった件

      あまりに複雑すぎる(とどっかで見た)と不評なR6RSのレコードだが、単に使うだけなら結構便利な件。
      特に今までつかってなかったけど、protocolが結構便利。
      例えばこんな例:
      (define-record-type something
        (fields (mutable f1)
                (mutable f2)
                (mutable f3)))
      
      上記のレコードsomethingはfieldsとしてf1~f3まで持つけど、初期化時にコンストラクタに値を渡さないかもしれない。上記の例では必ず
      (make-something #f #f #f)
      
      なんて書かないといけないが、protocolを定義すると事情が変わってくる。
      (define-record-type something
        (fields (mutable f1)
                (mutable f2)
                (mutable f3))
        (protocol (lambda (p)
                    (lambda args
                      (let-optionals* args ((f1 #f)
                                            (f2 #f)
                                            (f3 #f))
                        (p f1 f2 f3))))))
      
      let-optionals*は探せばいろいろあると思うけど、Sagittariusでは(sagittarius control)ライブラリで提供。こうすると上記のmake-somethingがこんな風に書ける
      (make-something 'value)
      
      ここまでは、まぁ割と当たり前なんだけど、Sagittariusの一つの特徴としてキーワードを認識する。っで、キーワードを使ってこんな風に書ける。
      #!compatible ;; キーワードはr6rsモードでは動かない
      (import (rnrs)
              (sagittarius control)) ;; let-keywords let-keywords*もこの中
      (define-record-type something
        (fields (mutable f1)
                (mutable f2)
                (mutable f3))
        (protocol (lambda (p)
                    (lambda args
                      (let-keywords args ((f1 #f)
                                          (f2 #f)
                                          (f3 #f))
                        (p f1 f2 f3))))))
      
      (make-something :f3 'value)
      
      let-keywordsはGaucheからもらってます。これが地味に便利。フィールドが少ないうちはそんなに感じないけど、10個くらいあって、7番目だけ値を入れたいなんて場合にこれが活躍してくる。難点は、全部に値を設定したい場合に一々キーワードを書かないといけないところか。ま、トレードオフだろう。

      2011-07-11

      Harry Potter

      最初の映画を見てたりするのだが、今更ながらに気づいたこと。
      ずっとハーマイオニーだと思ってたのだが、彼女の名前はHermioneでよく聞くと、ハーミオニに近いこと。
      っで、オランダ語の字幕にはHermiolineと何故かLがくっついてること。

      どうでもいい話。

      ところで、ハリーポッターって何がハリーを特別にしてるの?家系?映画見ててもその辺全然説明無くて、いきなりセレブだって言われるからさっぱり分からん、

      2011-07-10

      ドキュメントを書き始めた

      いろいろ何を使おうか悩んでいたが、別にtexinfoとか自前で何か作るとかは馬鹿らしいなぁと思ったので、結局OpenOffice.orgのWriterにした。
      それでいいのか?という疑問は未だに付きまとうけど、単なるAPIドキュメントという側面だけではないようにしたいと思うと割としっかりしたドキュメント作成用のソフトが要るようになる。わざわざテキストファイルで書いてくTexとかはあまりに面倒だし、今から覚えるのも億劫だったという理由から。
      最終的にはOOoフォーマットからLaTexか何かに変換してHTMLを出力という形に持っていこうとは思っている。OOoフォーマットだとソフト持ってないと読めないし。

      ドキュメントと書いてて思ったのが、かなりの分量が必要になるということ。R6RSで規定されている関数とかも全部書いているからなのだが、かなり凹みそうになる。なぜそんな部分まで必要になるかというと、R6RSで規定されている関数を拡張しているものがあって、単純に仕様書にポインタを指すということができないから。
      割とコピペで済ませる部分が多いが、これをやってて仕様を満たしていない部分を発見したりするから割と有用かな(今まで必要な部分しか読んでなかったというのもあるが)。時間かかるけど。

      2011-07-09

      とりあえず一旦完了

      Compiled Cacheの実装が一旦完了した。キャッシュから読み込むと3倍くらい早いのでまずまずだろう。
      いくつか問題点があって、
      ・依存関係にあるキャッシュが変更された際に上手く動かない
      ・キャッシュ自体が壊れていた場合に上手いことエラーハンドリングしない
      などというところがとりあえず分かっている。
      が、問題だなぁと感じてから直すことにする。

      ほしいと思って投稿してからほぼ1週間これの実装にかかったわけだ。結構かかったな。
      まぁでも、それなりに待てる時間まで実行時間が短縮されたので無駄ではなかっただろう。