Syntax highlighter

2011-02-28

SHA BU SHA BU

こんな名前のレストランがオランダにはある。
名前の由来はもちろん日本のあの料理だ。実際、レストランのサイトには名前の由来はその料理からとったと書いてある。
さて、ここで問題。あなたは日本人(まぁ、ほぼ100%そうだと思うけど)だと仮定します。あなたはこの料理の詳細を知っています。そしてそのレストランを見ました。このレストランの看板メニューを答えなさい。(30点)


・・・


・・・・・・


・・・・・・・・・


時間切れです。あなたの答えは何だったでしょう。まぁ、こんな聞き方をしているのだから、まさか「しゃぶしゃぶ」なんて安易な答えじゃないですよね。
ちなみに、答えは寿司です!!

おかしいだろ!!!どう考えても!!!
久しぶりにしゃぶしゃぶだぁなんてはしゃいで予約いれて、HP見たら寿司がメインかよ!!即行キャンセルだぜ。
とりあえず、中国人経営日本食レストランの寿司は大抵はずれだからというのと、腹具合がいい感じにしゃぶしゃぶ用にセッティングされてたからな!!
お前それ、「四川料理」って銘打ってるのに「北京ダック」だすようなもんじゃね?

他にもいろいろ「KIMONO」とか「SUMO」とか「SAKURA」とか(まぁ桜はいいか)、突っ込みどころが多い名前のレストランがあるが、今回のは食べる前から壮大に裏切られた。

ちなみに、どうしてもしゃぶしゃぶが食べたかったので、自分で作ったとさ。
(牛肉の薄切りが売ってる日本っていいなぁと思いながらね・・・)

2011-02-24

er-macro-transformerでsyntax-caseを実装

まだ使用としているだけだが、とりあえずChibi Schemeのsyntax-rulesが動いた。
以前書いた問題は意外と簡単で(といっても、実装の核にかかわる部分の違いだったので判明するのに少し時間がかかったが)、identifier?の判別の差だった。
Chibi Schemeではidentifier?はsymbolもしくはsyntactic-closureのどちらかも満たすものなのだが、僕の実装系にsyntactic-closureはない。またidentifier自体が一つのScheme型として存在してるので、渡された生S式から取り出したものと、renameされてidentifierに変換されたものとの比較が上手くいってなかった。
とりあえず、compare関数に渡す際にすべてrenameすることにしたが、多分これはcompare関数自体を変更した方がよさそう。現状だと単にeq?で比較なので、symbolとidentifierの比較は確実に偽になる、でもそれだと不便すぎる気がするので、わたってきた値がsymbolとidentifierの混在だったらrenameしてから比較した方がいい気がする。

この実装のいいところ(?)は(おそらく、まだ全部試してないので)srfi 46をデフォルトで実装しているところだと思う。でも、組み込んであるGauche由来のsyntax-rulesに比べるとすごく遅い。おそらく、希望的観測だが、コンパイルが遅いのだと思う。展開は速いと信じたい。(明日試す)
何とか高速化できたら、組み込みのsyntax-rulesをやめてこっちを採用したい。特に意味はないが、組み込みのマクロはer-macro-transformerだけで、残りはライブラリという位置づけにしたい。
問題は、今のところマクロはCに書き出すことができないところか。多分できなくもないんだろけど、やるなら、ちょっと(大分)考えないと。

これを足がかりにsyntax-caseが実装できたら、後は必要なライブラリをそろえるだけ。バージョン0.0.1のリリースも近いか。

2011-02-23

招待状

大学の後輩(とってももう直接のかかわりは無いが)から定演の招待状が届いた。
海外にも送ってくれるのはとても律儀で好感がもてる。
っが、今週末に開かれる演奏会に、今日届いていては招待する気がないとしか思えない。
届くまでに一週間かかったとしても、送ったのが2月14日の週では遅すぎないかね?

っと、こんなところ彼らが見ているわけもないだろうので、あまり意味は無いが。
ま、ちょっとした愚痴です。
(しかし、マジで行く気で3月にチケットとってたら張った押したくなるくらいの仕打ちだわ)

2011-02-21

与太話

変換したらこれだったけどいいのか?

皆さんはヨーロッパにどんなイメージをお持ちだろうか?例えばこんなのは僕が昔持っていたイメージ。
  • お洒落
  • 金髪美男美女ばかり
  • スーツ着てビジネス
  • モダンな建物
  • 歴史のある風景
  • 陸続きなんだから、2,3ヶ国語は当たり前
もし皆さんがそのような幻想をお持ちなら
                ヘ(^o^)ヘ ok.
                  |∧  
               /  /
           (^o^)/ If you are confident in
          /(  )    what you can, do everything you wish,
    (^o^) 三 / / >
\    (\\ 三
(/o^) < \ 三 
( /
/ く  I would destroy
      your fuck'n fantasy. 
(単にこれを言いたかっただけ)

さて、順番に幻想を壊していきましょう。と言っても、オランダとベルギー、あとフランスの少しくらいしか知らないので、イギリスは違うとか、ドイツはもっとこうだといわれても反論はできません。突っ込みは大歓迎です。

【お洒落】
待ち行く人々を指すなら、日本人の気合にかなう国はそう多くないでしょう。こっちなんて化粧すらあんまりしてない気がします。男も女も基本ジーンズです。

【金髪美男美女ばかり】
そもそも、移民の歴史があったり、アフリカから奴隷をつれてきた歴史があるので、金髪だけではありません。(ラテン系の人は黒髪だし)。美男美女ばかりでもありません。容姿の偏差値というのは変な感じですが、日本が45~60くらいの間だとしたら、30~70とか幅がある感じです。男は基本掘りが深くて毛深いです。でも、頭髪は意外と少ないので禿がマジで多いです。女性へのコメントは控えます。

【スーツ着てビジネス】
これが意外と北米とかでも勘違いされてると思われる事項です。とりあえずオランダだとスーツ着る人いません。一応商談があるとか会社の偉い人は着てますが、普通の社員はジーンズでOK。楽なもんです。昔カナダにワーホリで行った時のホストマザーが、北米の東の方(モントリオールとか、ニューヨークとか)はヨーロッパ色が強く、ビジネスではスーツが基本、時間に厳しい、なんて行ってましたが、完全に妄想です。少なくともオランダでは。

【モダンな建物】
ニュータウンとか、ビジネス色の強い地域じゃないとそんなもんありません。アムステルダムなんて歴史を感じる建物ぐらいしかないです。まぁ、南駅まで出ればビジネス色のほうが強いので、ワールドトレードセンターとかありますが。僕の働いているロッテルダムはどちらかといえばモダン色が強いですが、やっぱりそうでもないです。

【歴史のある風景】
これは本当。ちょっと有名な都市(ライデンとか)だと歩けばそこに歴史があります。まぁ京都みたいな感じです。ま、そうは言っても古めかしい建物の隣にマクドナルドがあったりとか普通なので、あんまり歴史を感じないかも。

【陸続きなんだから、2,3ヶ国語は当たり前】
人によります。まぁ、そうは言っても英語は大抵の人が喋れると思います、がそれを期待すると裏切られることが多々あります。ヨーロッパの中では一番きれいな英語を喋るという風評があったのですが、1年前くらいにイギリスだかどこかが調査した結果、そうでもないということが実証されたそうです。まぁ、アクセントというか訛はありますね。人の事言えませんが・・・

この中に当てはまる幻想があって、見事に砕かれたならもうヨーロッパなんて怖くありません。(何かを恐れてたのか?)

2011-02-18

syntax-caseをexplicit renaming macroで実装するには

どうしたらいいのだろう?

自前の処理系にはer-macro-transformerがある。というか、R6RSに準拠することをとりあえずの目標にしているのだが、syntax-caseを実装するのが(個人的に)無理だったので、(まぁ、psyntaxとか他のexpanderに頼ってもよかったのだが)、とりあえず、explicit renaming macroを実装して、それを使ってsyntax-caseを実装するという手をとろうと考えたわけだ。
正直、ここまでは悪くない手だと自分では思っている。Gaucheの川合史朗さんのBlogのエントリーにsyntax-case、explicit renaming macro、それ以外の衛生的マクロ(Syntactic Closureとか)のどれか一つがあれば他のマクロはポータルに実装できるとあるので、後はその実装だけかなぁとは思ってたりするのだが、いかんせん頭が足りない。
Chibi schemeにer-macro-transformerを使ったsyntax-rulesの実装があってそれをとりあえず走らせて見たのだが、どうも動きがおかしい。
例えば、以下のコード
(define-syntax test
  (syntax-rules ()
    ((_ o)
     (display o)
     (test)
    ((_)
     (newline))))
(test 'a)
(今ちょっと思い出して書いただけなので、間違いがあるかも)、通常のsyntax-rulesなら実行結果は単に「a」と改行をプリントするのだが、Chibi scheme由来のsyntax-rulesを自前の処理系で走らせると、「unbound variable o」となる。
実際、VMのインストラクションを吐かせてみたら、
;; 略
GREF_PUSH o          ;; グローバル変数oに束縛された値をスタックに積む 
GREF_CALL(1) display ;; displayをコール
;; 略
なんてことになってて、そりゃ「o」なんてどこにも定義してないからなぁと納得はするのだが、どうしてそうなるのかさっぱり分からない。
マクロを展開を試してみて、途中でこける。途中のどこかがおかしいので空のリストがcarに与えられてこける。
Chibi shcemeのsyntax-ruleの基本的な感じとしては、(まじめに追ってないので本当に感じ「feeling」だけだが)、er-macro-transformerでer-macro-transformerを作るといった処理に見える。
あれ、ちょっとまてよ、もしそうだとした、こんな感じのマクロが
;; something-macroは別のとこで定義
(define-syntax a
  (something-macro ()
    ((_) (do-something))))
こんな感じに
(define-syntax a
  (er-macro-transformer
    (lambda (form rename compare)
      ;; パターンマッチングの処理とかがあって、最終的に
      ;; これ↓を呼ぶ
      (do-something))))
展開されるということか?
でも、自前の処理系だと、マクロの展開は、マクロのコンパイル → コンパイルされたコードの適用 → 展開されたコードのコンパイル、という実行順序なので、2段階コンパイルされるということになる。1段階目でコンパイルされた時は参照(というか変数?)だったシンボルが、2段階目では変数として扱われてるということかな。
なんかちょっと見えてきたかも。試してみよう。

2011-02-10

とりあえず竹内関数を動かしてみた

まだ足りないところが多いが、たらい回してみた。
ソース:
(define (tarai x y z)
  (if (<= x y) y
      (tarai (tarai (- x 1) y z)
      (tarai (- y 1) z x)
      (tarai (- z 1) x y))))
(display (tarai 12 6 0))
Cygwinのtimeコマンドで一応ほかの処理系とも比較してみた。
(この段階で速度的に勝てるとは思わん!!)

結果:
自分の
→ 2.62s user 0.00s system 100% cpu 2.607 total

Gauche
→ 0.01s user 0.00s system 1% cpu 0.814 total

Ypsilon
→ 0.01s user 0.00s system 1% cpu 0.755 total

mosh
→ 0.80s user 0.03s system 101% cpu 0.812 total

見方が間違ってなければこの段階で3倍程度遅いか。ダイレクトスレッドコードとか、インストラクションのマージとかまだやれそうなことが山ほどあるので、とりあえずは気にしない。

先にバイトベクターを実装しようか、コアにかかわる部分をこなしてしまおうか。
ちと考えないと。

R6RSのシンボル

読み込みの部分でシンボルの解決をどうするか。

R6RSだと以下のシンボルは不正。
「.aa」「|a|」多分ほかにも。
こんな感じのシンボルがほしい場合は、string->symbolで作ってやる必要がある。しかし、ここで個人的には無視できない問題が起きる。
たとえば、ベクターを何らかの型のように使おうとしたとき、最初の要素は型の目印(タグ)にし、残りの要素をプロパティにするといった手法は良くとられるものだと思う。
例えばこんなコード。
(define (make-entity name desc) (vector (string->symbol ".entity") name desc))
(define (entity? e) 
  (and (vector? e) 
       (eq? (vector-ref e 0) (string->symbol ".entity"))))
これに、nameとdescのアクセサと識別用の関数を用意すれば簡易構造体である。

ここからが問題で、ではここでこのentityはシリアライズ可能だとしよう。schemeならwriteで書き出してやれば、entityは読み込み可能なS式として書き出される。こんな風に:
#(.entity name desc) ; mosh
#(\x2E;entity name desc) ; Ypsilon
#(|.entity| name desc) ; r5rs
でも、書き出されたこのタグはR6RSでは不正なシンボルなんだ。
せっかくオブジェクトをS式で簡単にシリアライズできるのに、こんなくだらない罠にはまりたくはない。writeで書き出すのはr5rs方式にして、readはYpsilon方式の「#!xxx」でスイッチできるようにした方がいいかもしれない。

そもそも、こんな使い方が間違ってる?

R6RSのライブラリ その5

まさか5つもこのメモが貼り付けられるとは・・・

ライブラリのバージョンに関する話。
R6RSのライブラリは識別子にバージョンリファレンスをつけることができる。そうこんな感じで。
(library (identifier (1)) ...)
バージョンは数字のリストである必要があり、import時には比較もできる。なかなかすごい機能だ。
import時に比較ができる、たとえばバージョン1以上とか、ということは、複数の同一識別子、別バージョンのライブラリを持つことも可能なのだろうか?
R6RSのSection 7.1に、
When more than one library is identified by a library reference, the choice of libraries is determined in some implementation-dependent manner.

訳:
もし、2つ以上のライブラリリファレンスが識別された場合、その(ライブラリの)選択は処理系依存によって決定される。
とある。
ということは、処理系が許せばライブラリをバージョン違いで複数定義することが可能なのだろうか?
調べてみた。
例によって使用した処理系は、Petite chez scheme(7.9.4), Ypsilon(0.9.6-update3), nmosh(0.2.6)。そのうちikarusとかも試してみたいがそれは後回し。

使用したプログラム:
(library (lib)
    (export test)
    (import (rnrs))
  (define test 'test))

(library (lib (1))
    (export test)
    (import (rnrs))
  (define test 'test-1))

(library (lib (2))
    (export test)
    (import (rnrs))
  (define test 'test-2))

(import (lib (1))(rnrs)) ;; (1)を取ったり、つけたり
(display test)(newline)
結果は見事自分の予想とは違っていて、petite, Ypsilonはライブラリの現在のバージョンと要求バージョンが違うといってエラー。nmoshはtest-2を返してきた、つまりバージョンリファレンス無視。

バージョンの違う同一ライブラリを同時に読み込むということが実際ありえるかというと、こんなテストでもない限りありえないとは思う。そういう意味では、nmosh(おそらくSRFI-72を拡張したexpanderを使用しているscheme処理系)は現実解としてバージョンを無視。petite、およびYpsilonは同時に読み込める同一名ライブラリを1つとし、リファレンスの比較を行うといったところか。
ちなみに、nmoshで(import (rnrs (5))なんてのを試したところ普通に動いたので、おそらく上記の推測はある程度的を射ていると思う。
(これが動くのをよしとするかは、また別の問題だとは思うが)
nmoshのバージョン無視はさすがにどうかと思うので、改修の少ないpetite、Ypsilon方式で読み込める同一名ライブラリは1つとしよう。これなら現在のLibraryクラスにバージョンを追加してやるだけで済む。

しかし、R6RSには微妙な言い回しが多い気がする。expand時の(for (rnrs) expand)とか。

2011-02-01

BoehmGCで気になること

BoehmGCを使っていていろいろ気になることが起きてきた。
正直起きてほしくはない、が現実を受け入れる。使い方が悪いのか?

現象としては、おそらく回収されてはいけないメモリが回収されてるっぽい。保守的なGCにもかかわらず!!
正確には静的に置いてあるハッシュテーブルの中身がある回数参照されたあと変な値になるというもの。
詳しく調べてないし、GDBで確認するのと普通の流すので結果が変わるので調べ難い(ひどい話である)ので、断言はできないが。
DLL内でGC_INIT()を呼んで、exeメインのファイルでもGC_INIT()を呼んでいるが、これがまずいのか、それともCygwinでは静的に置いた値に対して特別な処置がいるのか、どっちかは分からない。
涙が出そうになったのでデバッグを適当に切り上げてしまった。続きはまた明日。

どうでもいい話だが、どうやってポインタが指すポインタを判別してるんだろう?
例えば
typedef struct a
{
  int tag;
  void *addr;
} A;

int main()
{
  A *ap = GC_MALLOC(sizeof(A)); /* (1) */
  char *strp = GC_MALLOC(10);
  ap->tag = 1;
  ap->addr = strp; /* (2) */
  return 0;
}
プログラムに意味は無いが、こんなのがあった場合、(1)はいいだろう、スタックから辿れる。(2)はもしapがどこかで作られたものなら、strpのスタック上のアドレスは完全に消える。この場合、struct Aの中身を1byteもしくはalignのサイズ(例えば2byte)ずつ見ていき、GCが抱えるヒープ上のアドレスを保持しているかどうかというのを見るのだろうか?
こんな感じ?
void follow(void *obj, size_t size)
{
  uintptr_t addr = (uintptr_t)obj;
  int i;
  for (i = 0; i < size; i++) {
    void *p = (void*)(addr + i);
    /* p が指すアドレスの先がヒープを指しているか? */
    if (in_heap(*p)) {
      /* ヒープは割り付けたメモリのサイズを管理する */
      follow((void*)*p, get_size_from_heap_header(*p));
    }
  }
}
これなら一応アドレスを辿れそうに見える、試してないけど。

仮に、BoehmGCがこんな感じのことをしてたとして、誤回収が起きるのはどうしてだろう?もしくは、メモリを中身を書き換えてるのかも?
ソース読めば早いのだろうが、あれを読んで理解するのはかなり大変だよなぁ・・・そこまで時間をかけたくないし、なんかいい解決方法ないだろうか?

2011-01-30

エレヴェン

まずはこの動画を見てほしい。


いや、最先端だね。音声認識エレベーターとは。
でもスコティッシュアクセントには対応していなかったようだ。

これを同僚に見せられたときは思わず大爆笑してしまった。
うちの会社のCEOとマネージャーの一人はスコットランド人だけどね!!

2011-01-15

LinuxをUSBからインストール

をするための準備の話。
ちょっと古めのデスクトップが転がってて、OSが入ってない。Windowsはもちろんない。ということで、Linuxを入れようと思ったのだが、現在使ってるノートPCにはCDROMがない。

っでちょっと調べてみたらUSBからインストールできるらしい。ということでブータブルUSBを作成する。
手順。
  1. syslinuxを落としてくる。
  2. DAEMON Tool Liteを落としてインストール。
  3. Linuxのisoイメージを落とす。
  4. 3.を2.のツールでマウントして、中身をUSBドライブにコピー。
  5. USBドライブにisolinuxってフォルダがあるので、それをsyslinuxに変更。
  6. 5.のフォルダの中にisolinux.cfgというファイルがあるので、syslinux.cfgに変更
  7. syslinux.exeを叩く。(syslinux.zipで落としたなら、中のwin32フォルダにある)
    C:\> syslinux.exe -maf F:
    (F: はUSBドライブ名。これをC:とか自分のHDDにすると多分えらいことになる)
    本当は-maでいいんだと思うけど、僕のUSBはリムーバブルと認識されてなくて、強制書き換えの-fが必要だった。
たった(結構あるな)これだけ。

他にも、UNetbootinってツールも試したけど、こいつにはひどい目に合わされた。バージョンが悪いのか(最新版だけど)、そもそもCDイメージをUSBにコピーするだけのツールなのか知らないけど、ブータブルなUSBならない。

これで上手くいったらSSDを買って自分のノートにLinuxを入れよう。
(その前に死んだバッテリーを換えないと。ACアダプタ抜いたら即死ぬノートPCってノートの魅力0なんですけど)

2011-01-12

ワイド文字列

いろいろやってて壁にぶち当たった・・・
C言語で文字列を扱うことがこんなに面倒だとは、知ってたけど改めて痛感。
char = 1 byteはいいとして、
wchat_t != 4 byte ってか処理系依存って結構厳しい。
UCS4を内部エンコードに使いたかった(すでに過去形)のだが、WindowsのVCとCygwin GCCだとwchat_tは2byte。(Linuxだと4byteらしいけど、試してない)
マクロで
typedef wchar_t ucs4char;
#define UC(str) L##str
なんてことしたかったんだけど、無理になった・・・orz
そもそも
typedef int32_t ucs4char; /* 符号付 4byte(EOFは大抵-1だし) */
static const ucs4char msg[4] = {0x3042, 0x3044, 0x3046 0x0}; /* あいう */
static const char* cmsg = "abcde";
ってのがアセンブラ上だとなんかあんまり美味しくないようになってる。こんな感じで。
L0  .long 0x3042
    .long 0x3044
      :
_msg .long L0
     .def __somewhere
L1  .ascii "abcde\0"
    .text
_cmsg .long L1
なんか、静的に配列確保してて(そういう宣言だから当たり前だが)、あんまり静的な文字列な感じがしない。

あと、C内部で文字列を扱う際に、C文字列からUCS4変換する必要が出てくるので、文字列のコピーがどうしても必要になり、アロケーションが走る。使い捨ての文字列とかにアロケーションは走ってほしくない。

Ypsilon方式にするか。ファイルのエンコーディング -> UCS4(中間表現) -> UTF8(内部文字列)とするとCで使ってる文字列はそのまま流用できそう。
改修がすごく広範囲にわたるが今のうちにやったほうがいいだろうなぁ。

2011-01-08

Boehm GCを読む

正直涙が出そうになっているが、現在の所分かった(つもりでいる)部分のメモ。

    基本的な部分
  1. ヒープとして渡されるポインタはヘッダー情報を保持していない(ある意味当たり前)
  2. ファイナライザはオブジェクト(ここではポインタ)に持たせず別に管理している(finalizable_objectを格納するハッシュテーブル)
  3. ヒープ内部はOSのページブロック(基本4KB)ごとに分けられている(ちと不安)

    曖昧な理解の部分
  1. GCのヒープはGC_arraysという構造体で一括管理してるっぽい。
  2. top_indexとかbottom_indexとか2KBくらいの配列を確保してるけど、この中に実際のヒープのヘッダーが入ってるっぽい。

あ、でも
struct hblkhdr
{
  struct hblk *hb_next;
  struct hblk *hb_prev;
  struct hblk *hb_block;
  /* 以下略 */
};
struct hblk
{
  char hb_body[HBLKSIZE];
};
/* HBLKSIZEは基本4KB */
なんてなってるから、ヘッダーにメタ情報を持たせて(使える領域とか、どんなオブジェクト用かとか、残りブロックサイズとか)、ページブロック以下のサイズのオブジェクトに対してはhb_blockからみ使用部分を割り当てるなんて方法なのかも。
可変構造体にしないのは、最大限にヒープを使うためなのか、可搬性のためなのかどっちなんだろう?

2011-01-04

これってOK?

C言語でこんなのって合法?
static int s_value[5] = {1, 2, 3, 4, 5};
struct rec_t {
  int v[1];
};
static struct s_rec_t
{
  rec_t v[1];
} myth = {
  { s_value }
};
用は構造体の初期化だと思うんだけど、rec_tがint*なら合法なのはいいとして、この場合だとどうなるんだろう?
そのまま見ると1個しかない配列に対して5個入れてるから違法臭いけど、ポインタ自体を書き換えるのであれば合法っぽくもある。
実際、
struct string_t
{
   int size;
   char value[1];
};
---
string_t *s = (string_t*)malloc(sizeof(string_t) + sizeof(char)*10);
strcpy(s->value, "abcdefghi");
s->value[10] = '\0';
なんてのは合法なんだよね。
(いや、仕様書を確認したわけじゃないけど、よく見るテクニックだからそう思ってる。実際char[1]をchar*にするとセグるし、当たり前だが)
ただ、この場合だとポインタを書き換えるのではなく、連続したメモリという扱いになるのかな?
最初のケースだと純粋に書き換えてるから、うっかり鼻から悪魔が出てきても文句が言えなさそうな気はするが。
う~ん。

2011-01-01

謹賀新年

あけましておめでとうございます。

旧年はお世話になりました。本年もよろしくお願いいたします。

去年(一昨年からか?)やってる個人プロジェクト、まだあんまり形になってないけど、今年中にはなんらかの形にしたいなぁ。
個人的にもう少しな感じがしてる。(気が変わって作り直しをしなければ。何度やったか・・・)

今年はいい年になりそうな気がする。

2010-12-29

続 C言語でオブジェクト指向

バスに揺られた帰り道に思いついた。
忘れないうちにメモしておこう。

unionを使えばいいのかもしれない。
よくよく考えてみれば、設計の段階で回避できる問題なのだからこんな感じにしたらいけそうな気がする。
(対象はSchemeのポート周り)
struct Port
{
  int type;
  int direction;
  int (*close)(Port*);
  union {
    struct BinaryPort *bport;
    struct TextualPort *tport;
    struct CustomPort *cport;
  } impl;
};
typeでバイナリ、テキスト、またはカスタムポートか判別。directionでIN/OUTの判別。実際のポートの実装はimplで行って、closeとかすべてに共通しそうなのは上位に入れる。
(どうせ、そうは行ってもそれぞれのcloseを呼ぶことになりそうな気はするので、もう少し練る必要がありそうだ)

メタクラスも考えたが、一朝一夕ではいい案が出ないのと、Scheme内で使うところまで考えないとオーバースペック(苦労に見合わないとも言う)になりそうなのでとりあえず却下。
(Glib、Gaucheのソースを見たけど結構大変そうだったので。いろいろ魅力的ではあるが、自分の手に余りそうだし、recordを使えば一応クラスっぽいのも定義できるのでという理由)

明日この方向で実装を再開しよう。
ポート周りが終わらないと始まらない辛さ・・・

C言語でオブジェクト指向

ただいま絶賛挫折中・・・orz

その昔(といっても2ヶ月くらい前か?)途中で開発方針変えたため放棄したC++のソースをCに移植してる最中でぶつかった壁。
まだぶつかってるので躓いてる壁か?

単一クラス、振る舞いは変わるが継承、多態はないのなら、こんなのでいける。
typedef struct ObjectRec Object;
struct ObjectRec
{
  int x;
  int y;
  int (*squre)(Object*);
};
こんなことして、適当に関数ポインタに関数を突っ込んでやればいい。
たとえばこんなの。
static int realSqure(Object* o)
{
  return o->x * o->y;
}

static int fakeSqure(Object* o)
{
  return o->x * o->x * o->y * o->y;
}

Object* makeObject(int x, int y)
{
  Object* o = (Object*)malloc(sizeof(Object));
  o->squre = realSqure;
  o->x = x;
  o->y = y;
  return o;
}

Object* makeFakeObject(int x, int y)
{
  Object* o = (Object*)malloc(sizeof(Object));
  o->squre = fakeSqure;
  o->x = x;
  o->y = y;
  return o;
}
これで、同じo->squreなのに違う関数にアクセスできる。
この辺まではいいんだよ。昔から使ってたから。問題は継承が絡んでくると意味が分からん。
vtable使うか、メタクラスを別に作って気合でアクセスするか。
(多分、メタクラスを使った方が後々いい気がする。GObjectとかを参考にするか)

くそ、C++でかければこんなことで悩まないのに・・・
みんなDLLが悪いんだ!

2010-12-25

クロワロタwwwww

性の6時間を正すために6時間正拳突きをしようと思う。某巨大掲示板に立ったスレをまとめたもの。

クソ笑った。あほすぎる。でも、これ日本にいてリアルタイムで発見したら大阪までスネークに行ってたかもw
いや、どちらかといえばリア充寄りだと思うけどね、僕。
これだけ行動力があるのなら、もう少し建設的なことに使えばいいのに、とも思ったが。
(別に彼女を作るとかじゃなくて、勉強でもいいと思うし、昨今の政治家に対してのデモとか)

でも、個人的には愛するべきあほだと思う。

そうそう、Merry Christmas!

2010-12-22

C++/Cで書き始めたい

だいぶ自前Schemeがまとまってきたので、そろそろC++かCで書き始めようと思う。
コンパイラ(+その周りのライブラリ)はコンパイルされたコードをC(多分CよりなC++)にコンバートすればいいとして、
(それでも、ライブラリのインポートとか識別子どうしようとか問題はあるけど)
どこまでをCで書いて、どこからをC++で書こうか迷い中。

迷う理由としてはこんな感じ。
  1. C++だとバイナリ互換がない、つまりアプリケーション組み込みに向かない
  2. C++にはtemplate、class、関数オーバーロードなどCにはない機能がある
1.はアプリケーション組み込みをするのかという話にもなる。でも、たとえばDLLでモジュール(ライブラリか?)を作成したいと思ったときに、CまたはC++で書くなら必要になる気がする。
(同じコンパイラ使えばいいんだけどね、実際)
2.は要らないといえば要らないが、あるとすっきりかける気がする。慣れの問題だとは思うが。

おそらく問題になりそうな部分としては、オブジェクトの扱いかなと。
結局こいつらをC++で書くと先に書いた、DLLでモジュール作成に支障が出る気がする。
Gaucheは完全にCだが、Ypsilonは一部Cで主にC++で書いてる。
見ればオブジェクトは単なるポインタで、それぞれのオブジェクト、Pairを除く、にヘッダ(単なるunsigned int)を持たせてる。
Moshは全部C++で、オブジェクトはクラスなんだけど、タグと値を保持するだけ。
(まぁ、その他便利関数が入ってるけど)

MoshとYpsilonを混ぜるのが答えになる気がする。
こんな感じで
typedef struct ObjectRec
{
  uint32_t tag;
  void*    value; //多分こいつはintptr_tとかにしないとまずい
} Object;
っで、シリアライズ可能なオブジェクトはCで書いて、PortとかシリアライズできそうにないのはC++で書けばいいかな。

そもそも、C++のABIがもっとポータルならいいのに。問題の一つは名前マングルにあると思うんだ、うん。
(try-catchの実装とかもそうか・・・)

2010-12-16

続 R6RSのライブラリ その4

理由が全然違うことが発覚した・・・orz

原因はletrec-syntaxでsyntax-rulesにキーワードを入れたら正しく動作しないのが原因だった。
マクロ展開難しすぎる・・・
(ほぼ、Gaucheのを流用してるのになぜ?)