仕様変更

  • R6RSとの共存を図ることにしたので、@ではなく/をセパレータとして使うように。
  • セパレータ以外のreparsing-symbolを廃止した。
  • bytepackingとendianを分離した

従来、skySchemeではu%dのようなシンボル名を定義することで(u 10)のように展開される、reparsingシンボルを持っていた。しかし、コンパイラを書いてみるとこれがあまり安全で無いことが分かったので(時間的都合もあり)廃止。伝統的な機能が大分廃止されてそれなりにschemeに近くなってきた。
要するに、従来reparsingシンボルとして実装されていたu16とかu32のような型は、特別なプリミティブ/bitsによって個別に宣言されるようになった。
特別なシンボルは/でprefixされる。これらのシンボルはパケット定義中でしか使えず、schemeコード側と干渉することはほぼ無い。
セパレータは特別な解決パスを追加することで残す。

(define-packet-format u10 (/ (/bits 10) /unsigned))

bytepackingを新設し、endianとは別に管理することにした。bytepacking msbfirstがデフォルトであり、エントリの先頭をmsb寄りに配置する。
802.11のような規格は、先頭をlsbから詰めていくので、bytepacking lsbfirstとなる。他にも、規格書が時間的な送信順に書かれ、lsbfirstにビットを送信するプロトコルが該当する。例えばUSBはlsbfirstな物理プロトコルを持つが、規格書はmsbfirstに書かれているので、bytepackingはmsbfirstになる。多くのプロトコルはmsbfirstのbytepacking*1を持ち、これはendianがlittleなプロトコル(Least Significant Byte first)でも多くが該当する。
このpackingは8bit単位で行われるため、いくつかのプロトコルでは対応できないことも有る。リトルエンディアンで、かつword全部をフラグとして利用するようなケースが該当する。0-Fの16bitをこの順に記述したとしても、89ABCDEF01234567の順にビットを配置してしまう(16bitのlittle endian値として解釈すると、0123456789ABCDEFの順になり、これが期待する結果となる)。
今の所一時的にエンディアンを切り替えることでそのようなプロトコルも記述できるが、あまり良くないので明示的な記法を準備する必要が有る。
もっと難しいのは、byte境界をまたぐフィールドとbyte未満のフィールドを組み合わせた場合で、6bit値Aと10bit値Bを持つ構造体testをmsbfirstなlittle endian環境で以下のように宣言した場合、

(define-packet-format test (A u6) (B u10))

Bのフィールドは2bitと8bitに分割されることになる。プロトコルにおいては、全体を16bit wordと解釈して上位6bitをAとするケース(つまり、物理的にはBBBBBBBB_AAAAAAbbのように表現される)と、8bit x2と解釈して、AAAAAAbb_BBBBBBBBのように表現する場合の両方がある。
現在のところ、このようなケースはエラーにしている*2が、かなり不便なので何らかの抽象化を提供したい。
もっとも、最大の変化は、

  • R6RS macroで書くのを諦めた

あたりか。専用のexpanderを持って、一旦R6RSライブラリにコンパイルする方式に戻すことにする。デバッグが困難すぎるため。

*1:bitpackingの方が適切な名前かもしれない。endianこそbytepacking ruleであり、そう考えるとここで使っているものはbitpacking ruleと言えるように思える。

*2:big endianかつmsbfirstやlittle endianかつlsbfirstでは、このようなケースでもあいまいにならないのでこれを許可している。