Skip to content

Translation Phases との対応

Yokota Yuki edited this page Aug 7, 2021 · 9 revisions

https://en.cppreference.com/w/c/language/translation_phases とどれを対応させるか?

現在 (2021-5-26) は下記のようになっていないが、こうなるように修正したい。

physical-source-input-stream

このcommit で導入した。 以下の二つを read-char で透過的に行う。 なぜ gray stream にしたかは以下に書く。

Phase 1 : Trigraph の除去

???= のような文字列が問題で、これは最初の ? を残して ?# に変換されないといけない。 2文字の先読みが必要と思うが、 unread-char を2回呼ぶのも、 peek-char 後に unread-char するのも unspecified になってしまう。 このバッファリングを行うために gray stream を使いたくなった。

Phase 2 : Backslash による行連結

\ をリーダマクロで発見して次の文字を見て、というのでは全然だめ。 \\\n の前のトークンと結合しなければならず、 リーダマクロで文字を引っ掛けても「直前に読んだトークン」に触れる手段はない。

当初、ソースにあらかじめ phase1, phase2 だけを適用し、 phase 3 は Lisp リーダを使おうと考えたが、 backquote で Lisp 文法に戻せるようにしてたのが問題に。 Lisp 文法の中ではこれらの変換を抑制したい、 どちらかの文法のコメント中は }# や backquote を抑制したい、と考えてしまう。(実際 test はそれを前提にしていた。) すると、各時点での文法を追跡してコメントの文法を把握しなければならない。つまり結局 phase1,2,3 を同時に処理しないといけなかった。

Lisp リーダをできる限り使い回すためには、 gray stream で phase1, phase2 を read-char に押し込めることが必要だった。

リーダーマクロ #{ }#

Phase 3 : Preprocessor token への分割

現状は reader macro で行っている。 一部の数値 (0x 表記と、 Reader Level 2 の数値) は pp-number で留められる。

preprocessor 関数

Phase 4 : Preprocessor 処理

preprocess ブランチで実装中。

memo

#include するファイルの発見を asdf:system-relative-pathname でやろうとすると、なぜか Github Actions ではコケる。 asdf:find-component なら大丈夫。

この commit で対応

Phase 5 : 文字セットの変換

やる必要があるのかな?

Phase 6 : string literal の結合

プリプロセスの一部として行っている。

追加処理

  • C keyword の intern. readtable-case 関連処理のためにここで行なっている。
  • (Libc の intern) 削除済。 これは #include で代替されるべき

既知の問題 (2021/7/18 時点)

  • backslash による escape を保存できない。 Lisp リーダは特に escape されるべきではない文字に backslash がついていてもよく、単純に backslash が無くなってしまう。この仕様が、 C99仕様 「6.10.3.5 Scope of macro definitions」の Example 4 の str(: @\n) の箇所と競合する。
  • #include 元と先とで readtable-case が違う場合の処理が整理されてない。この無理矢理な commit に問題が現れている。 → その後、 #pragma で readtable-case を指定できるようにして整理。何もしないと current readtable に従い、 pragma で任意に切り替えられる。 この例 を参照。
  • mcpp の 「u.1.23. # 演算子によって不正な pp-token が生成された」 の形式が受け取れない。この例 (puts( str( \""));)、文字列リテラルとは一体なんなのかわからなくなる・・。

cl-yacc での展開

Phase 7 : compilation

lexer

pp-number の Lisp 数値への変換と、 typedef hack も行う。

compiler

がんばる。

やらない

Phase 8 : Linking

macroexpand して展開することこそが Link である、と定義しよう。