-
Notifications
You must be signed in to change notification settings - Fork 3
progress
- テンプレートの特殊化を行ったコードを出力できるようになった。
- 特殊化されたコードは、shouldVisitTemplateInstantiations()を値trueを返すようにすることでトラバースされるようになった。
- 特殊化されたコードのXML出力はその元になったコードのすぐ後ろにCXXRecordなしで出てくるので、テンプレート宣言ノードの下をパースする必要がある。
- メンバポインタの出力が正しくなかったので直した。
- XcodeMLtoCXXのXcodeMl::Typeの中にlibxmlのコードのポインタを入れる方法がわかった。これはスマートポインタを使っているので、ポインタとして生のポインタを型メンバに入れうることができず、スマートポインタをいれることになるが、libxmlのポインタはすべてlibxmlの中で管理されているため、ポインタは一種のハンドルとして扱えば良く、かってに破棄とかしてほしくない。そのため、intptr tなどの型にキャストすることで、単なる数値として扱われ、スマートポインタからは触られずにすむようになる。これは、現状は結局使わなかったが、decltype型の実装で利用ができると思われる。
- 現状、vectorをインクルードしたプログラムからCXXtoXcodeMLからXMLが出力される。
- 出力されたXMLからXcodeMLtoCXXでC++のコードがとりあえず出てくる。
- 出力されたC++のコードをコンパイルするとエラーが出てくる。現状、3425個のエラーが出る。
- なお、カレントディレクトリにある簡略化されたstdio.hではなく、本物のstdio.hを使うとva listや、pthreadまわりのために現状のテストプログラムは通らない。
- vectorのテストプログラムの出力を検討し、テンプレートで展開された関数やメソッドの実体が存在するかどうかを調べた。
- どちらも現状存在せず、実体化されたものをダンプする必要がある。
- std::vectorのメンバ関数push_backの実体化されたものはMemberExprに出てくる。
- クラスに属していない関数の実体化されたものはDeclRefExprに出てくる。
- いずれもそれが実体化された場所(関数内の呼び出し)で展開しても動作しないので、関数外のどこかで展開する必要がある。
- 納品までの見通しとしては、これをサポートするところまでできるかどうかというところ。
- テンプレート関連を完全に再現できるようにするとなると、C++の文法すべてをサポートするに近い作業が必要となり、多分間に合わない。
- とりあえず、algorithm, vectorを全部処理できるようになった。(ただし、テンプレートまわりの出力は正しくない)
- DependentScopeDeclrefに対応した。
- templateにtemplate関数渡す場合の処理を追加し、型名を処理するようにした。
- メンバ関数ポインタ演算子に対応した。
- ここまでの作業は作業ツリーにcommitしてある。
- 現在、まだコンパイルできないコードが出力されるものの、type_traitsは全部処理できるようになった。
- メンバの存在確認メタ関数は処理できるようになった。
- 可変長引数の出力で、可変長引数以外の引数が無い関数が正しく出力できるようにした。(Cではありえないが、C++のテンプレート関数では存在する)
- テンプレート内のテンプレートメンバー関数に対応した。
template<typename T> class A{ template <typename T> foo(T int); }
- decltypeを認識できるようにした。しかしながら、decltypeは定義の中にステートメントが入るため実装に手間取っている。
- constexprの対応がなかったので対応した。
- 可変長引数の定義は扱えるが、Cでの可変長引数の処理に使われるstdarg周りのマクロは正しく処理できなかった。中身を見るとXMLには必要なデータ構造が埋め込まれているが、C++の実体化されたテンプレート構造体などと同様に出力するトリガーがなかった。
- initializer_listはincludeしただけのものでは通る。
- algorithmはそもそもincludeしただけでは大量にコンパイルエラーが出る。そもそもcstdioなどのようなC言語の関数のC++関数版が、いまのテストプログラムで使われている、コンパイラフラグをつけると通らない。(つけなければ通る)
- つけずに出力したalgorithmはコンパイルエラーは出ず、xmlが出力される。このxmlに対し、XcodemltoCXXで戻すと、utilityのところで失敗する。
- algorithmは、type_traitsをincludeしていたため、それが処理できないとそもそも先に話が進まなかった。
- 現在、STLのtype_traitsで止まっている。
- テンプレート型から継承した方を継承したテンプレート型宣言もうごかした。
- テンプレートパラメータの型パラメータのメンバ関数呼び出しもうごかした。
- テンプレートパラメータの型パラメータの中にある型を参照する型宣言がもう少しで動く。作業中。メンバ名および、参照するパラメータ型がXMLに埋め込まれていなかったので、それを埋め込むところまでは行った。
- ラムダ関数宣言のテストプログラムを作り、実装方針の検討をした。ラムダ関数はローカルに定義される無名のファンクタークラス(つまり関数呼び出しオペレータのオーバーライドが定義されているクラス)のような振る舞いをするが、関数ポインタ型へのキャストがサポートされているため、単純にクラス宣言として書くのは難しい。
- 今具体的に止まっているメンバの存在確認メタ関数を切り出したプログラムを作った。動作しないことだけしかまだ確認できていない。
- 現状インスタンス化されたテンプレート関数はXMLに出力されていないが、llvmの作ったASTでインスタンス化されたノードからアクセスできることは確認できた。これは何らかの方法で出力したほうが良さそう。
- テンプレート型から継承した型を継承したテンプレート型宣言が正しく動かないというのが実際のところであった。
template <typename T, int x> struct A{};
template struct B:public A<T, 3>{};
` - テンプレートインスタンス化の実装を行っている。現状CXXtoXcodeMLが十分な情報を出力していなかったので、ちょっと手こずっている。
- 実際にインスタンス化されたオブジェクトに含まれるコードは再現できるだけの情報がもともと入っていた。
- テンプレート宣言はコード生成に全く影響を及ぼさないのであまり力をかけてもしょうがないと思うが、特殊化されたテンプレート型だけ宣言することができるのかどうかがわかっていない。(特殊化されたテンプレートならばテンプレートメタ関数などが解消されているはずなので、これだけ処理できるのなら、そうしたほうが処理が楽)
- バグだし用のテストプログラムをstd::vectorベースのものに変えた。
- 可変長配列宣言に対応できるようにした。
- テンプレート数値引数の値をXMLに出力するようにした
- 複数のテンプレート引数の扱いがおかしかったので直した
- テンプレート数値引数に対法するようにした
- テンプレート型エイリアス宣言をとりあえずvoidを出すようにした。
- 現在テンプレート型エイリアスのインスタンス化されたものから継承したクラス宣言が正しく動かない。
- iostreamのテストプログラムからの出力をXcodeMLtoCXXに入力したところ出力が出なかった。
- 引っかかったところの抜き出すようなテストプログラムを作成した。
- OtherTypeに対するハンドラがなかったのが原因で、それらを一応登録するようにした。 **これは、CXXtoXcodeML側で詳細な実装が必要
- usingの型エイリアスに対応していなかったので、一応通すようにした。
- これにより、抜き出したものでは一応XcodeMLtoCXXの出力が出るようになった。
- テンプレートの非型引数に対応していない。
- 可変長配列宣言が正しく扱えない。
- CXXtoXML側で作業したiostreamが通るようにしたコードをCXXtoXcodeML側に移植してみたが、そのままではうまく行かなかった。
- 調査すると、宣言文でVisitDeclを通らないケースがあった。
- 結局VisitDeclをPreVisitDeclにリネームし、明示的に呼び出すようにしたところ、CXXtoXcodeMLでも通るようになった。
- まだXcodeMLtoCXXで戻せるかどうかは確認していない。
- llvm36ベースで構築し直し、動作を確認し。すべてのテストプログラムが正しく動いていることを確認した。
- llvm90ベースのものの出力と比較したところ、TemplateTypeParam宣言が出力される場所が変わっていて、テンプレート関数宣言内になっていた。
- XcodeMLtoCXX側を調べたところ、テンプレート関数宣言の中が、関数本体のみ定義されていることを想定していたので、関数本体定義を抜き出して展開するように変更した。
- こうすると、新しい方のツールではまだテンプレート周りでの動きがおかしいことが確認された。
- これは、VisitTemplateArgumentが呼ばれていないことが問題だった。
- 結局TraverseTemplateArgumentLoc, TraverseTemplateArgument,TraverseDeclarationNameInfoを実装し直し、Visit〜を呼び出してから、基底のものを呼ぶようにした。
- これで、テンプレート周りのコードも動くようになった。
- hello_world_cは未だに動いていない。
- clangxcodemlを自分のgithubのアカウントのリポジトリにforkして、そこに手元の作業をcommitしていくことにした。 https://github.com/takawata/ClangXcodeML/tree/takawata-wip
- pointer_to_memberをみたところ、問題はNestedNameSpecifierが消えてしまっていることだった。
- TraverseDeclをオーバーライドしてるのが間違いかと思ったが、TraverseDeclは呼ばれていなかったようだ。(引数がサブクラスの物になっていてマッチしない)
- そもそも、本来のトラバーサではVisitNestedNameSpecifier,VisitDeclarationNameInfo,VisitConstructorInitializerとかはない。
- なので、なるべく本来の動きを変えない範囲でTraverseNestedNameSpecifierLocを変更しなければならない。
- TraverseConstructorInitializerからは、VisitConstructorInitializerを呼んでから元の実装を呼ぶようにした。
- TraverseNestedNameSpecifierなどをVisitNestedNameSpecifierなどをもとに実装した。
- 現在、手元のCXXtoXMLと同じことが出来るところまでは来た。
- テンプレート周りとC言語のコンパイルがうまく行っていないが、Clang9.0への移植の時に入ったバグのためかもしれない
- 現状の問題は
- func_templ_expl_spec_and_nontempl テンプレート関数の中身の記述が無い。
- func_templ_partial_spec.dst.txt テンプレート関数の中身の記述が無い。
- hello_world_c.dst.txt: main関数の定義に余計な属性がついている。
- これは手元のClang9.0に移植したCXXtoXML側でも同じ
- 先週の時点でうまく動いていなかったのは子ステートメントではなく子要素すべてををダンプする必要があるためであった、
- llvm90ではshouldUseDataRecursionForが呼ばれない。トラバース周りは大幅に3.7から最近のもので変わっている。
- そもそも、ドキュメントによると最初っからの仕様としてVisitからTraverseを呼ぶのは間違い。(逆は良い)
- 元々の仕様ではTraverseの最上位クラスで、ステートメントの種類ごとのTraverse(TraverseStmtからTraverseForStmt等) が呼ばれ、Traverseでは同じ命令クラスのWalkUpが呼ばれ、WalkUpFromから上位のWalkUpFrom(例えばWalkUpFromForStmtだったらWalkupFromStmt)と同じ命令クラスのVisitが呼ばれる。
- 現状のVisitStmt内でのfor文の処理内容をTraverseForStmtに移すことによって、For文の中身だけを処理でき、元々のコードと同等の出力をif_else.src.cppで出すことが出来た。VisitStmt内でfalseを返している文の処理で同様にすれば動作するのではないかと考えている。
- そもそも、RecursiveASTVisitorではなくASTDumpを元にするという手はある。AST jsonダンプを元にすることができそう。
% clang -Xclang -ast-dump=json ${SRC}
- とりあえず、JSONダンプを単体で動かす方法はわかった.
- getLocStart()が代わっている。
- getBeginLoc();へリネーム
- BeginSourceFileActionの引数からファイル引数が消えている。
- getCurrentFile()を呼ぶ
- PrintStackTraceOnErrorSignalの引数が代わってる。
- Argv[0]を渡した
- Type::型がllvm::とclang::の両方があり曖昧だった。
- 関数の最初でusing節で指定する。
- child_range型の実装が違ってる。 LLVM3.0のときから大きく変わっている。
- range based forに実装を変えた。
- ケースを尽くしていない。
- default:節の追加
- clang::NamespaceDeclへのllvm::castの呼び出しの際、参照にしないと、デフォルトのコピーコンストラクタがdeleteされているため動かない。
- OptionParserの呼び出しでNULLポインタを踏む。
- OptionsParserの定義と同じコンパイル単位にカテゴリ定義が無いとだめ。
- CXXtoXMLではPreと、Postの2つのトラバースコードがある。Post側ではほとんど何もしていないが、最後にDeclだけは名前空間処理を行っている。
- 戻り値により再帰下降パースの降り方が変わるので、そこを見る必要がある。
- CXXtoXML側ではトラバース処理を自分で行っているのでfor節の戻り方でfalseを返すこのとき、CXXtoXMLではTraverseStmtは自分の子供のパースを行わずにtrueを返して、処理が続行されるがCXXtoXcodeMLではfor節の処理でfalseを返すと以降の後続処理が行われない。
- CXXtoXMLでのXMLVisitorBaseでのothersideはXMLRAVで、内包されておりそこからみたXMLRAVはXMLVisitorBaseである。
- とりあえず、何が起きてるかはわかり、TraverseStmtで元のCXXtoXMLのXMLVisitorBaseのコメントにある通り、VisitStmtがfalseを返したら、TraverseStmtはその場でtrueを返し、そうでなければ子ステートメントを処理するようにしてみたところ、 Return文などが出力できているが、出力できていない項目があり、もどそうとするとうまく行かない。
- nnsTableを正変換・逆変換で扱うようにした
- 同名関数の定義に対応した
- 非スカラー型のcv-qualifierが正変換で扱えていなかったので修正した
- テスト環境を整えた(/tests/CCTest/)
- 以下の文法に正変換・逆変換で対応した
- コンストラクター・デストラクターの宣言
- 前置・後置インクリメント・デクリメント
- メンバー関数のアクセス指定
- コンストラクター宣言中の初期化リスト
- 演算子オーバーロード
- nested-name-specifier
- 可変長引数
- friend宣言
- 言語リンケージ指定 (
extern "C"
など) - 単一宣言文内での複数変数の宣言
- クラス宣言中の基本クラス指定子
- メンバーアクセス演算子、アロー演算子
- 正変換の際に 必要に応じて 型情報を登録するようにした
- localTypeTableの出力に対応できるよう型情報テーブルの構造を変えた(スタックにした)
- -dump-typemapオプションが実装不可能になったため削除した。 ただし型情報の登録漏れに起因するエラーが出ることはもうないのでいまやこのオプションは不要である。
- 逆変換
- 従来XMLを読みながら文字列を吐いていたが、一度ASTに近い木を構築してから出力するようにしている
- クラス型を表現するオブジェクトの構造を変え、friend宣言などメンバー変数宣言以外の要素にも対応できるようにしている
- 正変換
- globalSymbols/symbols要素にもっと多くの名前を出力するようにしている
- friend宣言中で定義された関数名
- (普通の、およびネストされた)クラスの名前
-
extern "C"
ブロック中で宣言された名前
- globalSymbols要素に不適切な要素が出ていたので修正
- globalSymbols/symbols要素にもっと多くの名前を出力するようにしている
-
#55 NNS定義要素の追加
-
#60 class要素をclassType要素に名称変更
-
#54 pointerType要素を使ってリファレンスを表現する
- 先週から引き続きopen。conversationsにコメントを追加
- #61 class要素で派生と継承を表現する方法について明記
- リファレンス型の元になる型を登録していなかったので登録するようにした
- XMLを吐く際にリンケージや言語リンケージについての情報を出すようにした
- XSLTを追加した
- member要素
- intConstant要素(文字リテラル)
- Var要素
- varDecl要素
- CXXtoXML用のテスト環境を整備した
C++プログラムを出力するときの仕組みを改善した(#47, #53)。従来はアドホックにインデントの調整を行っていたが、これにより自動的に調整されるようになった。
- #50 演算子オーバーロードに関するいくつかの記述を削除
-
#51 標準(型)変換を表現する
<implicitCastExpr>
要素を追加 -
#54
<pointerType>
などの要素を使ってリファレンスを表現する
作業ブランチはhnagamin-20170208-clangastwalker。 逆変換(XcodeML -> C++,XcodeMLtoCXX)を行うには名前と型の対応関係を知っている必要があるが、一部の型について対応関係がCXXtoXMLの出力するXMLに含まれていなかったためこれを修正した。
CXXtoXMLの出力するXML文書をXSLTでXcodeML文書に変換している(/CXXtoXML/src/XSLTs/)。このXSLTに処理を追加した。
型とデータ型識別名の対応関係を出力するオプションを追加した(#45)。
$ ./CXXtoXML -dump-typeTable sample.cpp --
Pointer0: int *
Function0: int (int)
int: int
先週議論した文字列リテラルの問題
また、これらをとりあえず回避した状態で、現状の CXXtoXML で処理させると、文字列リテラルを扱っている部分で segmentation fault になる。 これはどうやら「文字列リテラルの型は、 const char * ではなく、 const char [文字数+1] になるので、その型がどこにも宣言されていないから」らしく、...
について、これを修正し文字列リテラルの型を正しく扱うようにした(#43)。 また、文字列リテラルを出力する処理がCXXtoXMLに含まれていなかったので出力するようにした(同PR)。
いただいたソースは全体的に C++ として正しくない部分が多い。 g++ ではいちおう全部コンパイルできるようだが、 clang++ ではエラーでコンパイルできない部分が多い。
- main() 関数の返り値が宣言されていない (int main() に修正しないとだめ)
- 名前空間内の名前を参照する using を使わない古い記法(クラスフィールドで単に A::x; などと書く記法)が用いられている。 これは -std=c++03 にすることでエラーは回避できるが Warning は出る (-Wno-deprecated でそれも抑制できるが…)。
- リテラル文字列を non const のポインタ変数に代入している。これも -std=c++03 にすることで一応回避できるが…。
- デフォルト値を持つ引数の使い方が正しくなくて、デフォルトコンストラクタと宣言がかぶっていたり、 friend 宣言が間違っている。 member046.cc, member059.cc, member060.cc はこのためにコンパイルできない。
- 可視属性に違反した関数呼び出しなどがある。上記の3つに加え、 access045.cc, access046.cc はこのためにコンパイルできない。
これ以外に、 -std=c++03 にしても大量の警告が出る。
- 未使用変数、未使用パラメータ、未使用privateフィールド、などの警告が出るが、これはまあ問題はない。
- c++03 だとすると long long 型がないことになるのだが、使用されている。これもまあ問題はない。
- printf の %x でポインタ値を表示しようとしている(正しくは %p を使うべきなところ)。これもまあ無視できるレベル。
- signed の値と unsigned の値を直接比較している。とりあえず無視してもよいレベル。
- コンストラクタの初期化指定の並びの順が正しくなく、基底クラスの初期化指定がフィールドの初期化指定よりも後ろに並んでいる。 (access003.cc, access005.cc, member048.cc, member049.cc, member050.cc, member051.cc, member058.cc, overload005.cc, overload007.cc)
- 関数引数部に何も書いていない関数宣言( f() など ) があり、オーバーロードやプロトタイプ宣言が正しく行われていないフシがある。 (derive029.cc, derice049.cc, member045.cc)
- ビットフィールドに char 値をキャストなしで代入している。 (class051.cc)
- 未初期化変数を使っている。 (derive061.cc)
また、これらをとりあえず回避した状態で、現状の CXXtoXML で処理させると、文字列リテラルを扱っている部分で segmentation fault になる。 これはどうやら「文字列リテラルの型は、 const char * ではなく、 const char [文字数+1] になるので、その型がどこにも宣言されていないから」らしく、とりあえず typedef const char char1[1]; typedef const char char2[2]; …と書き並べていくことで回避できたが要修正。 (また、 CXXtoXML に --ignore-unknown-type というオプションをつけても回避できる。ただしこの場合 typeTable は不完全)
ヌルポインタ参照することがあったので修正した。#42
また、commitはしていないが、現在pragmaを扱う処理を実装中である。 参照: Issue #10
cd CXXtoXML
make
ある種のコメントに対してcomment要素を出力するようにした。入出力例は#40を参照せよ。
もっと多くの情報を出力するようにした。(#40)
- access属性 アクセス指定を表現する。(bf851b7)
- clangCastKind属性 キャスト式の種類を表現する。(2d3b530)
- clangNestedNameSpecifier要素 nested-name-specifier(
A::B::x
のA::B::
)を表現する。(d550e98) - class属性 文法要素の種類を表現する。(388a4ce)
- decimalNotation属性 整数リテラル式について、その十進表現を文字列としてもつ。(9bdf273)
- has_init属性 変数宣言が初期化子をもっているかどうかを表現する。(94f79d6)
- is_const属性 メンバー関数のconst性を表現する。(e246ef2)
- is_static属性 メンバー関数のstatic性を表現する。(e246ef2)
- is_virtual属性 メンバー関数のvirtual性を表現する。(e246ef2)
- token属性 整数リテラル式について、そのソースコードにおける表現を文字列としてもつ。(2ec73c0)
- valueCategory属性 式のvalue categoryを表現する。(e36268e)
- xcodemlType属性 式がもつ型のXcodeMLにおける名前(データ型識別名)を表現する。(8d96db6)
CXXtoXMLの出力するXML文書をXcodeML/C++の形式に近付けるためにXSLTを書いていた。(#40)
Pull Request #32、#34、および開発ブランチから。
- array_size属性に対応。multi_dim_array.src.cppに対して以下のように出力する。
int b[1][2][3][4][5];
- 配列型のconst, volatile属性に対応。array_cv.src.cに対して以下のように出力する。
void f(int const a[const 10], double b[const volatile 20]){
{
}
}
- (Cの)構造体に対応。struct_type.src.cppに対して以下のように出力する。
struct A{
int i;
};
struct B{
double d;
int i;
};
struct C{
char * pc;
double d;
int i;
};
- ビットフィールドに対応。bitfield.src.cに対して
struct A{
unsigned int a : 3;
unsigned int b : 10;
unsigned int : 5;
unsigned int c : 10;
unsigned int : 0;
double g;
int d : 15;
int e : 17;
int f : 20;
int h : 4;
};
- CtoXcodeMLの
unsigned_int
データ型識別名に対応。出力例略。 - C_Frontでのテストに対応(08eb2f2d)。以下のコマンドで実行できる。
cd XcodeMLtoCXX/
make check CTOXCODEML=C_Front CTOXCODEMLFLAGS=
- 基本型のデータ型識別名(
long_long
など)をそのままC++ソースコードとして出力するのを修正 (#32) - arrayType要素がelemTypeよりも先に定義されていた場合に異常終了するのを修正(#33)
- 関数宣言で引数の順番が変わるのを修正(e0468cc4)
- 無名引数を使ったコードに対してC_Frontが出力したXcodeML文書をXcodeMLtoCXXに入力すると異常終了するのを修正(991ecd8c)
- C_Frontの関数宣言を扱うとき、関数本体が
{}
で囲まれていなかったのを修正(c2bc9a10) - 関数ポインターを返す関数宣言の修正。コミットメッセージ参照。(4c575d96)
- XcodeML/Cのname要素との整合性を保ったままXcodeML/C++で名前解決の仕組みを扱う方法について議論した。nnsTableのページに記載。
- template のページに「typeTable と nnsTable の入れ子構造」の節を追記。
- 仕様書を google docs に配置し、2章を修正中。 https://docs.google.com/document/d/11GnZwwGS72cLGinPaBgV0YFS_QHG2ByC4RFtra_wI-k
- template および nnsTable の仕様検討のたたき台のため、正変換ツールをいったん「Clang AST になるべくそのまま沿う形」で実装しなおし、 Clang AST からどのような情報を引き出せばよいのかについて試している。 CXXtoXML サブディレクトリ内で作業中。
C++ の参照をどう表現するか、および template をどう表現するかについて、それぞれ reference と template のページに記載。
CV修飾子を出力するようにした(#28)。
例えば次のコードは、
const int f(int * const p) {
const int i = 0;
const int * q = p;
const int * const r = q;
return i;
}
void g() {
volatile int vi;
const volatile double cvd = 0;
int * const volatile cvpi = 0;
}
CtoXcodeMLとXcodeMLtoCXXにより次のように変形される。
int const f(int * const p)
{
int const i = 0;
int const * q = p;
int const * const r = q;
return i;
}
void g()
{
int volatile vi;
double const volatile cvd = 0;
int * const volatile cvpi = 0;
}
型を表すクラス(XcodeMl::Type
)の設計に難があったので修正を行った。
- C++の型は階層構造をもつが、これをポインターによる参照で表現するのをやめデータ型識別名による参照で表現するようにした(#25)。これにより関数へのポインターを正しく扱えない問題(#14)が解消された。
ただし、データ型識別名が現行仕様で厳密に定義されていない型がある(unnnamed namespace中で定義されたクラスなど)ので、将来仕様を定めるなど対応をとる必要がある。 - 関数定義における名前の有効範囲の取り扱い方にバグがあったため修正した(#26)。
現在は、CV修飾子を出力する機能の追加に取り組んでいる。この作業ブランチはまだpushしていない。
https://github.com/omni-compiler/ClangXcodeML/tree/hnagamin-20160808-bugfix/type のブランチで下記作業中。
- XcodeML の typeTable の情報を XcodeMLtoCXX の内部データ構造(C++ のクラス)として保持している部分について、 XcodeML での名前(type=属性に指定される名前)を用いずにデータ構造を構築しようとしていた(ポインタを張り巡らす構造にしようとしていた)のを根本的に見直し、素直に type 名を文字列のキーとして検索できる構造に修正中。
- ただし、 basicType においては、 type 名は違うけれど実態としては同じ型(たとえば const int が複数の basicType になる)ということことがありえて、これを単純に上記の戦略で扱うと同じものに複数の名前がついている(が内部的には別々のものだとされてしまう)ので、逆変換時までそのような認識のままで大丈夫なのかどうか、少々不安は残る(おそらく大丈夫だが…)。
- struct については XcodeML での type=属性 の名前ではなく、ソースコード上の tag 名があればその名前で復元できるように調整中。(tag 名の無い struct については XcodeML での名前をもとにして適当に発行した名前をつける。)
https://github.com/omni-compiler/ClangXcodeML/commits/hnagamin-20160702-XMLSchema のブランチで下記作業中。
- exprStatement, compoundStatement, ifStatement について追記。
- ifStatement については、 C_Front 実装を確認する限りにおいては then 部と else 部を必ず compoundStatement で囲う実装になっているが、 forStatement や whileStatement はむしろ必ず囲わない実装になっているので、統一感がない。仕様では統一性を考えてどちらかにまとめたほうがいいのではないか。(もちろん compoundStatement で余分に囲うのは構わないとする)
C の構造体をパースする部分について、
- XcodeML での名前を用いて前方宣言として生成しておく部分を実装。これにより、ポインタのみの利用であれば順番が問題になることはない。
- ただし、 placeholder が真に必要となるような状況(関数内の局所クラス定義や、ネストされたクラス定義など)においては、前方宣言も「前方宣言がソースコード上に置かれていた場所」に適切に配置する必要があり、定義本体とは別に前方宣言用の placeholder が必要になると思われるので、これは XcodeML 自体の仕様の問題として考える必要がある。
- 中身のパース (typeTable の中にある セクションを適切に処理する部分) を実装中。
C++11 のコア言語 ( http://ezoeryou.github.io/cpp-book/C++11-Syntax-and-Feature.xhtml ) の各部についての対応状況をチェックするためのシートを作成した。
これは https://github.com/omni-compiler/ClangXcodeML/milestone/3 のマイルストーンの作業に対応する。 このマイルストーンに対応する Issue を 5 つ登録した。
https://docs.google.com/spreadsheets/d/1kb-X9b-w5b4kvUL59yb7H5PS-NY-RmEpfZBx5ukvOEw で閲覧可能(google アカウントを持っている人には個別に編集権限を付与することもできる)。
現状では
- 縦軸と横軸を作成(Issue#15 に対応、すでに closed)
- 列のうち、「XcodeML_CXX_1.1.docx (Mar 30, 2016) での状況」の列をひととおり記入(Issue#16 に対応、すでに closed)
- 残りの列は思いついた範囲で書き込んだのみなので未完成 (Issue#17, #18, #19 に対応) というところまで。
- for文
- while文
- do-while文
- return文
を扱う処理を実装した。
また出力されるソースコードのインデントを整えるようにした。
例えば次のようなコードは、
void f() {
int i = 0;
for (i = 0; i - 10; i = i + 1) {
int num = 1;
}
while (1 == 2) {
return;
}
do {
i = i - 1;
} while (i);
}
int square(int x) {
return x * x;
}
CtoXcodeMLとXcodeMLtoCXXにより次のように変形される。
void f()
{
int i = 0;
for ((i = 0);(i - 10);(i = (i + 1)))
{
{
int num = 1;
}
}
while (12)
{
return;
}
do {
(i = (i - 1));
}
while (i);
}
int square(int x)
{
return (x * x);
}
masterにマージされたのでブランチを指定する必要がなくなった。
$ git clone https://github.com/omni-compiler/ClangXcodeML.git
$ cd ClangXcodeML/XcodeMLtoCXX
$ make
XcodeML文書をC++ソースコードに変換するプログラムを実装中である。現在次のコマンドによってコンパイルできる。
$ git clone -b hnagamin-20160623-XcodeMlType-shared_ptr https://github.com/omni-compiler/ClangXcodeML.git
$ cd ClangXcodeML/XcodeMLtoCXX
$ make
現在対応している文法要素は次の通りである。
- 関数定義
- ローカル変数宣言
- 式文
- 式
- 整数, 文字列リテラル
- 変数
- 単項演算(負数, sizeof, 論理否定, ビット否定)
- 二項演算(加減乗除算, 剰余, 代入)
- 三項演算
- 関数呼び出し
- this
例えば次のようなコードは、
void f(int i, int j) {
int x = 42;
int y = (-i + x) * j;
bool cond = !0;
const char* str = "some string";
x = (i + j) ? x : y;
f(x, x);
}
CtoXcodeMLとXcodeMLtoCXXにより次のように変形される。
void f(int i, int j)
{
int x = 42;
int y = ((-(i) + x) * j);
bool cond = !(0);
char* str = "some string";
(x = (i + j) ? x : y);
f(x,x);
}
対応していないXcodeML要素はただ単に無視される(if文を含むコードを変形してみよ)。
name要素にfullName属性を追加する処理を実装した。 fullName属性は、関数およびメンバー関数のqualified nameを表す。
次のコードを
class A {
void f(int x, int y);
int operator* () { return 42; }
};
void A::f(int x, int y) {
};
次のように変換する。
<?xml version="1.0" encoding="UTF-8"?>
<XcodeProgram source="/home/hnagamin/Documents/ClangXcodeML/src/class.cc" language="C" time="2016-03-22 20:07:11">
<typeTable>
<name type="int">x</name>
<name type="int">y</name>
<classType type="Class0">
<name>A</name>
<symbols>
<id type="Function0" sclass="extern_def" access="private">
<name>f</name>
</id>
<id type="Function1" sclass="extern_def" access="private"/>
</symbols>
</classType>
<functionType type="Function0" return_type="void">
<params>
<name type="int">x</name>
<name type="int">y</name>
</params>
</functionType>
<functionType type="Function1" return_type="int">
<params/>
</functionType>
</typeTable>
<globalSymbols/>
<globalDeclarations>
<Decl_CXXRecord type="Class0"/>
<functionDecl>
<name fullName="A::f">f</name>
</functionDecl>
<functionDefinition>
<operator fullName="A::operator*">pointerRef</operator>
<symbols/>
<params/>
<body>
<compoundStatement>
<symbols/>
<declarations/>
<body>
<returnStatement>
<intConstant type="int">42</intConstant>
</returnStatement>
</body>
</compoundStatement>
</body>
</functionDefinition>
<functionDefinition>
<NestedNameSpecifier_TypeSpec/>
<name fullName="A::f">f</name>
<symbols>
<id type="int" sclass="param">
<name>x</name>
</id>
<id type="int" sclass="param">
<name>y</name>
</id>
</symbols>
<params>
<name type="int">x</name>
<name type="int">y</name>
</params>
<body>
<compoundStatement>
<symbols/>
<declarations/>
</compoundStatement>
</body>
</functionDefinition>
</globalDeclarations>
</XcodeProgram>
無名名前空間(unnamed namespace)は"(anonymous namespace)"、無名クラスは"(anonymous class)"として処理される。 このような場合のfullName属性の仕様をまず考える必要がある。
- クラス派生時の基本クラスのアクセス指定
- クラスメンバのアクセス指定 をtypeTable中で表示する処理を実装した。 次のコードを
class A {
int x, y;
public:
int getX() { return x; }
int getY();
protected:
};
int A::getY() { return y; }
class B {};
class C : virtual public A, public B {
public:
int getSum(int z) { return getX() + getY() + z; }
};
次のように変換する。
<?xml version="1.0" encoding="UTF-8"?>
<XcodeProgram source="/home/hnagamin/Documents/ClangXcodeML/src/class.cc" language="C" time="2016-02-26 18:23:46">
<typeTable>
<pointerType type="Pointer0" ref="Class0"/>
<pointerType type="Pointer1" ref="Class2"/>
<pointerType type="Pointer2" ref="int"/>
<classType type="Class0">
<name>A</name>
<symbols>
<id type="int" access="private">
<name>x</name>
</id>
<id type="int" access="private">
<name>y</name>
</id>
<id type="Function0" sclass="extern_def" access="public">
<name>getX</name>
</id>
<id type="Function0" sclass="extern_def" access="public">
<name>getY</name>
</id>
</symbols>
</classType>
<classType type="Class1">
<name>B</name>
<symbols/>
</classType>
<classType type="Class2">
<name>C</name>
<inheritedFrom>
<typeName ref="Class0" access="public" is_virtual="1"/>
<typeName ref="Class1" access="public"/>
</inheritedFrom>
<symbols>
<id type="Function1" sclass="extern_def" access="public">
<name>getSum</name>
</id>
</symbols>
</classType>
<functionType type="Function0" return_type="int">
<params/>
</functionType>
<functionType type="Function1" return_type="int">
<params>
<name type="int">z</name>
</params>
</functionType>
</typeTable>
<globalSymbols/>
<globalDeclarations>
<Decl_CXXRecord>
<id type="int">
<name>x</name>
</id>
<id type="int">
<name>y</name>
</id>
<functionDefinition>
<name>getX</name>
<symbols/>
<params/>
<body>
<compoundStatement>
<symbols/>
<declarations/>
<body>
<returnStatement>
<memberRef type="int" member="x">
<Stmt_CXXThisExprClass/>
</memberRef>
</returnStatement>
</body>
</compoundStatement>
</body>
</functionDefinition>
<functionDecl>
<name>getY</name>
</functionDecl>
</Decl_CXXRecord>
<functionDefinition>
<NestedNameSpecifier_TypeSpec/>
<name>getY</name>
<symbols/>
<params/>
<body>
<compoundStatement>
<symbols/>
<declarations/>
<body>
<returnStatement>
<memberRef type="int" member="y">
<Stmt_CXXThisExprClass/>
</memberRef>
</returnStatement>
</body>
</compoundStatement>
</body>
</functionDefinition>
<Decl_CXXRecord/>
<Decl_CXXRecord>
<inheritedFrom>
<typeName ref="Class0"/>
<typeName ref="Class1"/>
</inheritedFrom>
<functionDefinition>
<name>getSum</name>
<symbols>
<id type="int" sclass="param">
<name>z</name>
</id>
</symbols>
<params>
<name type="int">z</name>
</params>
<body>
<compoundStatement>
<symbols/>
<declarations/>
<body>
<returnStatement>
<plusExpr type="int">
<plusExpr type="int">
<Stmt_CXXMemberCallExprClass>
<memberRef type="_bound_member_function_type_" member="getX">
<Stmt_CXXThisExprClass/>
</memberRef>
</Stmt_CXXMemberCallExprClass>
<Stmt_CXXMemberCallExprClass>
<memberRef type="_bound_member_function_type_" member="getY">
<Stmt_CXXThisExprClass/>
</memberRef>
</Stmt_CXXMemberCallExprClass>
</plusExpr>
<Var type="int" scope="param">z</Var>
</plusExpr>
</returnStatement>
</body>
</compoundStatement>
</body>
</functionDefinition>
</Decl_CXXRecord>
</globalDeclarations>
</XcodeProgram>
初期化子リストをfunctionDefinition要素中に表示する処理を実装した。 次のコードを
class A {
int x, y, z;
A(int a): x(a * a), y(a + a), z(0) {}
};
次のように変換する。
<?xml version="1.0" encoding="UTF-8"?>
<XcodeProgram source="/home/hnagamin/Documents/ClangXcodeML/src/initializer_list.cpp" language="C" time="2016-02-24 18:28:11">
<typeTable>
<pointerType type="Pointer0" ref="int"/>
<classType type="Class0">
<symbols>
<id type="int">
<name>x</name>
</id>
<id type="int">
<name>y</name>
</id>
<id type="int">
<name>z</name>
</id>
<id type="Function0" sclass="extern_def"/>
</symbols>
</classType>
<functionType type="Function0" return_type="void">
<params>
<name type="int">a</name>
</params>
</functionType>
</typeTable>
<globalSymbols/>
<globalDeclarations>
<Decl_CXXRecord>
<id access="private" type="int">
<name>x</name>
</id>
<id access="private" type="int">
<name>y</name>
</id>
<id access="private" type="int">
<name>z</name>
</id>
<functionDefinition access="private">
<constructor/>
<symbols>
<id type="int" sclass="param">
<name>a</name>
</id>
</symbols>
<params>
<name type="int">a</name>
</params>
<constructorInitializerList>
<constructorInitializer>
<mulExpr type="int">
<Var type="int" scope="param">a</Var>
<Var type="int" scope="param">a</Var>
</mulExpr>
</constructorInitializer>
<constructorInitializer>
<plusExpr type="int">
<Var type="int" scope="param">a</Var>
<Var type="int" scope="param">a</Var>
</plusExpr>
</constructorInitializer>
<constructorInitializer>
<intConstant type="int">0</intConstant>
</constructorInitializer>
</constructorInitializerList>
<body>
<compoundStatement>
<symbols/>
<declarations/>
</compoundStatement>
</body>
</functionDefinition>
</Decl_CXXRecord>
</globalDeclarations>
</XcodeProgram>
初期化子リストの各メンバ名をどう表示するか考える必要がある。
<constructorInitializer>
<name>x</name>
<body>
<mulExpr type="int">
<Var type="int" scope="param">a</Var>
<Var type="int" scope="param">a</Var>
</mulExpr>
</body>
</constructorInitializer>
などとしても良いかもしれない。
5.3 functionDefinition要素 に従い演算子オーバーロードを扱う処理を実装した。 次のコードを
class A {
int value;
public:
int operator*() {
return value;
}
A operator*(A other);
};
A operator*(int k, A x);
次のように変換する。
<?xml version="1.0" encoding="UTF-8"?>
<XcodeProgram source="/home/hnagamin/Documents/ClangXcodeML/src/operator.cc" language="C" time="2016-02-19 20:21:28">
<typeTable>
<pointerType type="Pointer0" ref="Class0"/>
<classType type="Class0">
<symbols>
<id type="int">
<name>value</name>
</id>
<id type="Function0" sclass="extern_def"/>
<id type="Function1" sclass="extern_def"/>
</symbols>
</classType>
<functionType type="Function0" return_type="int">
<params/>
</functionType>
<functionType type="Function1" return_type="Class0">
<params>
<name type="Class0">other</name>
</params>
</functionType>
<functionType type="Function2" return_type="Class0">
<params>
<name type="int">k</name>
<name type="Class0">x</name>
</params>
</functionType>
</typeTable>
<globalSymbols>
<id type="Function2" sclass="extern_def"/>
</globalSymbols>
<globalDeclarations>
<Decl_CXXRecord>
<id access="private" type="int">
<name>value</name>
</id>
<Decl_AccessSpec access="public"/>
<functionDefinition access="public">
<operator>pointerRef</operator> <!-- ここ -->
<symbols/>
<params/>
<body>
<compoundStatement>
<symbols/>
<declarations/>
<body>
<returnStatement>
<memberRef type="int" member="value">
<Stmt_CXXThisExprClass/>
</memberRef>
</returnStatement>
</body>
</compoundStatement>
</body>
</functionDefinition>
<functionDecl access="public">
<operator>mulExpr</operator>
</functionDecl>
</Decl_CXXRecord>
<functionDecl>
<operator>mulExpr</operator>
</functionDecl>
</globalDeclarations>
</XcodeProgram>
コミット 046250df55c52cce827efa98e6dfb942acc25dd9 を参照せよ。
ユーザー定義リテラルはC++11で導入された機能である。これを用いると、例えば
for (int i : 10_times) { // _timesというユーザー定義リテラルが使われている
std::cout << i << std::endl;
}
のようなコードを書くことができる。 優先度が低いと判断したため実装しなかった。コミット 1b7cf0950d4a7f1703f5b1493a86edff4639eaea も参照せよ。
5.3.1 operator要素 では以下の演算子名が定義されていない。()内に現在の実装における仮の演算子名を示す。
-
->
(arrowExpr) -
->*
(arrowStarExpr) -
()
(callExpr) -
[]
(subScriptExpr) - 単項
*
(pointerRef) - 単項
&
(varAddr) - 単項
+
(unaryPlusExpr)
5.3.1 operator要素 ではキャスト演算子に関する言及がない。 functionDefinition要素の子要素として新たにcastOperator要素を定義することを提案する。
5.5 functionDecl要素は子要素としてname要素だけをもつが、functionDefinition要素との対称性を考慮して operator要素、constructor要素、destructor要素も子要素にもてる方が良い。
これらは例えば以下のコードで必要となる:
class Rational {
public:
Rational(int denom, int numer); // コンストラクタの宣言
~Rational(); // デストラクタの宣言
private:
int denominator, numerator;
};
Rational operator*(const Rational &lhs, const Rational &rhs); // 演算子オーバーロードの宣言
3.9.1 inheritedFrom要素 (C++) に従い実装した。
typeTableとglobalDeclarationsの該当する場所に基本クラスの情報を出力する。
virtual基本クラスのとき、値が"1"のis_virtual
属性をもつ。
派生時のアクセス指定子に基づくaccess
属性をもつ。
次のコードを
class A {};
class B {};
class C : virtual public A, public B {};
次のように変換する。
<?xml version="1.0" encoding="UTF-8"?>
<XcodeProgram source="/home/hnagamin/Documents/ClangXcodeML/src/inheritedFrom.cc" language="C" time="2016-02-24 20:41:30">
<typeTable>
<classType type="Class0">
<symbols/>
</classType>
<classType type="Class1">
<symbols/>
</classType>
<classType type="Class2">
<inheritedFrom> <!-- ここ -->
<typeName ref="Class0"/>
<typeName ref="Class1"/>
</inheritedFrom>
<symbols/>
</classType>
</typeTable>
<globalSymbols/>
<globalDeclarations>
<Decl_CXXRecord/>
<Decl_CXXRecord/>
<Decl_CXXRecord>
<inheritedFrom> <!-- ここ -->
<typeName ref="Class0" access="public" is_virtual="1"/>
<typeName ref="Class1" access="public"/>
</inheritedFrom>
</Decl_CXXRecord>
</globalDeclarations>
</XcodeProgram>
次のコミットも参照せよ。
- f30ef47486ea2d36fe6daf0a9bf50a78784b5e84
- 74315e385fc6bfc47cecf4aa39f3861ec206644e