annotate final_main/chapter4.tex @ 0:ce014a8b669e draft default tip

wrote final thesis
author kaito
date Mon, 21 Apr 2014 21:42:23 +0900
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
1 \chapter{実装}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
2 第 \ref{chapter:CbC}, \ref{chapter:LLVM/clang} 章をもとに LLVM, clang への CbC コンパイル機能の実装を行う. 実装の流れは以下のようになる.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
3 \begin{enumerate}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
4 \item clang 側での \_\_code 型の追加.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
5 \item LLVM 側での \_\_code 型の追加.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
6 \item 継続のための goto syntax の構文解析.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
7 \item Tail call elimination の条件の達成.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
8 \item 環境付き継続の実装.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
9 \end{enumerate}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
10  \_\_code 型の追加が clang 側と LLVM 側とで分かれているのはそれぞれが型を扱うために使うクラスが異なるからである. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
11  以下の節ではそれぞれの工程について詳しく説明する. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
12  また, 以降に示される LLVM, clang のファイルパスについて, \$(CLANG) を clang のソースコードを展開したディレクトリのパス, \$(LLVM) を LLVM のソースコードを展開したディレクトリのパスとする.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
13
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
14 \section{clang 側での \_\_code 型の追加とその構文解析}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
15 \label{sec:add__code}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
16 まず最初に関数が code segment であることを示す \_\_code 型の追加を行う. そのためには \_\_code を予約語として定義する必要がある. clang では, 予約語は全て \$(CLANG)/include/ clang/Basic/TokenKinds.def に定義されており, ここで定義した予約語の頭に kw\_ を付けたものがその予約語の ID となる. ここに, 次のように変更を加えて \_\_code を追加した. ここで使われている KEYWORD マクロは予約語の定義に用いられるもので, 第一引数が登録したい予約語, 第二引数がその予約語が利用される範囲を表す. KEYALL は全ての C, C++ でサポートされることを示し, この他には C++ の予約語であることを示す KEYCXX や C++11 以降で利用されることを示す KEYCXX11 等がある. code segment は C のバージョンに関わらずサポートされるべきであるので KEYALL を選択した. また, 同時に定義されている \_\_return, \_\_environment は環境付き継続のための予約語である. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
17 \begin{lstlisting}[frame=lrbt,label=token,caption={TokenKinds.def}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
18 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
19 KEYWORD(__func__ , KEYALL)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
20 KEYWORD(__objc_yes , KEYALL)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
21 KEYWORD(__objc_no , KEYALL)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
22
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
23 #ifndef noCbC // CbC Keywords.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
24 KEYWORD(__code , KEYALL)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
25 KEYWORD(__return , KEYALL)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
26 KEYWORD(__environment , KEYALL)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
27 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
28 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
29 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
30  予約語を定義したことで, clang の字句解析器が各予約語を認識できるようになった. しかし, まだ予約語を認識できるようになっただけで \_\_code という型自体は用意されていない. したがって, 次に clang に \_\_code 型を認識させる必要がある.\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
31  clang では型の識別子の管理に TypeSpecType という enum を用いる. この enum の定義は \$(CLANG)/include/clang/Basic/Specifiers.h で行われており, これを以下のように編集した.\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
32 \begin{lstlisting}[frame=lrbt,label=TST,caption={Specifiers.h}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
33 enum TypeSpecifierType {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
34 TST_unspecified,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
35 TST_void,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
36 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
37 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
38 TST___code,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
39 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
40 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
41 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
42  これに加えてさらに\ref{sec:QualType} 節で説明した QualType が用いる Type を作らなければならない. この定義は \$(CLANG)/include/clang/AST/BuiltinTypes.def で行われているので, これを以下のように編集した. ここで使用されているマクロには符号付き整数であることを示す SIGNED\_TYPE や符号無し整数であることを示す UNSIGNED\_TYPE 等があり, それらは BUILTIN\_TYPE マクロを拡張するものである. \_\_code 型は符号無し,有りといった性質を保つ必要はなく, また void 型が BUILTIN\_TYPE を利用していることから \_\_code 型も BUILTIN\_TYPE を使うべきだと判断した.\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
43 \begin{lstlisting}[frame=lrbt,label=clangType,caption={BuiltinTypes.def}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
44 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
45 // 'bool' in C++, '_Bool' in C99
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
46 UNSIGNED_TYPE(Bool, BoolTy)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
47
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
48 // 'char' for targets where it's unsigned
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
49 SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(Char_U, CharTy))
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
50
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
51 // 'unsigned char', explicitly qualified
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
52 UNSIGNED_TYPE(UChar, UnsignedCharTy)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
53
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
54 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
55 BUILTIN_TYPE(__Code, __CodeTy)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
56 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
57 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
58 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
59  これで clang が \_\_code 型を扱えるようになり, \_\_code 型の関数, 即ち code segment を解析する準備が整った. よって次に \_\_code 型を解析できるよう clang に変更を加える. clang では型の構文解析は Parser クラスの ParseDeclarationSpecifiers 関数で行われる. この関数のもつ巨大な switch 文に kw\_\_\_code が来た時の処理を加えてやれば良い. 具体的には switch 文内に以下のように記述を加えた. また, この関数の定義は \$(CLANG)/lib/Parse/ParseDecl.cpp で行われている.\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
60 \begin{lstlisting}[frame=lrbt,label=parse__Code,caption={\_\_code の parse}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
61 case tok::kw___code: {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
62 LangOptions* LOP;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
63 LOP = const_cast<LangOptions*>(&getLangOpts());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
64 LOP->HasCodeSegment = 1;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
65 isInvalid = DS.SetTypeSpecType(DeclSpec::TST___code, Loc, PrevSpec, DiagID);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
66 break;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
67 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
68 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
69  重要なのは 5行目で, ここで \_\_code 型が DeclSpec に登録される. DeclSpec は 型の識別子を持つためのクラスであり, 後に \ref{sec:QualType} 節で述べた QualType に変換される. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
70  その他の処理について, 最初にある LangOptions はコンパイル時のオプションのうち, プログラミング言語に関わるオプションを管理するクラスであり, このオプションの値を変更しているのはコード内に code segment が存在することを LLVM に伝え, tailcallopt を有効化するためである. LangOptions が管理するオプションは \$(CLANG)/include/clang/Basic/LangOptions.def で定義される. これを以下のリスト \ref{langOpt} のように変更して HasCodeSegment というオプションを追加した. LANGOPT マクロの引数は第一引数から順にオプション名, 必要ビット数, デフォルトの値, オプションの説明 となっている.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
71 \begin{lstlisting}[frame=lrbt,label=langOpt,caption={LangOptions の追加}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
72 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
73 LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
74
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
75 BENIGN_LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
76
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
77 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
78 LANGOPT(HasCodeSegment , 1, 0, "CbC")
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
79 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
80 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
81 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
82
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
83
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
84 \section{LLVM 側での \_\_code 型の追加}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
85 LLVM でも clang と同様に \_\_code 型の追加を行う. 型の追加を行うと言っても LLVM IR の持つ type の拡張を行うわけではなく, コンパイル時に内部で code segment であることを知るためだけに型の定義を行い, LLVM IR として出力した場合には 型は void となる. LLVM では型の情報は Type というクラスで管理しており, Type の定義は \$(LLVM)/lib/IR/LLVMContextImpl.h で行う. これに加えて TypeID の登録も行う必要があり, これは \$(LLVM)/include/llvm/IR/Type.h で定義されている. それぞれ, 以下のように編集した. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
86  さらに, \_\_CodeTy は VoidTy としても扱いたいため, 型判別に用いられる isVoidTy 関数の編集も行った. この関数は Type が VoidTy の場合に真を返す関数である. この関数を Type が \_\_CodeTy の場合にも真を返すようにした. ここで変更されたは if 文の条件文のみなので, ソースコードの記載はしない.\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
87 \begin{lstlisting}[frame=lrbt,label=LLVMType,caption={LLVMContextImpl.h}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
88 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
89 // Basic type instances.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
90 Type VoidTy, LabelTy, HalfTy, FloatTy, DoubleTy, MetadataTy;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
91 Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
92 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
93 Type __CodeTy;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
94 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
95 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
96 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
97 \begin{lstlisting}[frame=lrbt,label=LLVMType,caption={Type.h}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
98 enum TypeID {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
99 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
100 StructTyID, ///< 12: Structures
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
101 ArrayTyID, ///< 13: Arrays
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
102 PointerTyID, ///< 14: Pointers
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
103 VectorTyID ///< 15: SIMD 'packed' format, or other vector type
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
104 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
105 ,__CodeTyID /// for CbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
106 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
107 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
108 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
109  これらの編集により, LLVM 側でも code segment を認識できるようになった.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
110
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
111 \section{継続のための goto syntax の構文解析}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
112 続いて, 継続のための新しい goto syntax の構文解析を行えるようにする. 継続のための goto syntax は, goto の後に関数呼び出しと同じ構文が来る形になる. したがって, goto の構文解析を行う際にこの構文も解析できるように変更を加える必要がある. clang が goto 文の構文解析を行っているのは, Parser クラスの ParseStatementOrDeclarationAfterAttributes 関数であり, この関数は \$(clang)/lib/Parse/ParseStmt.cpp で定義されている. この関数内にも switch 文があり, この中の kw\_goto が来た時の処理に手を加える. 具体的には以下のように変更した. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
113 \begin{lstlisting}[frame=lrbt,label=ParseStmt,caption={goto 文の構文解析}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
114 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
115 case tok::kw_goto: // C99 6.8.6.1: goto-statement
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
116 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
117 if (!(NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::semi)) && // C: 'goto' identifier ';'
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
118 NextToken().isNot(tok::star)) { // C: 'goto' '*' expression ';'
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
119 SemiError = "goto code segment";
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
120 return ParseCbCGotoStatement(Attrs, Stmts); // CbC: goto codesegment statement
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
121 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
122 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
123 Res = ParseGotoStatement();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
124 SemiError = "goto";
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
125 break;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
126 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
127 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
128  ifndef, endif マクロで囲まれた部分が追加したコードである. 初めの if 文は, token の先読みを行い, この goto が C の goto 文のためのものなのか, そうでないのかを判断している. C のための goto でないと判断した場合のみ ParseCbCGotoStatement 関数に入り, 継続構文の構文解析を行う. ParseCbCGotoStatement 関数は独自に定義した関数で, その内容を以下のリスト\ref{ParseCbCGotoStmt} に示す.\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
129 \begin{lstlisting}[frame=lrbt,label=ParseCbCGotoStmt,caption={ParseCbCGotoStatement}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
130 StmtResult Parser::ParseCbCGotoStatement(ParsedAttributesWithRange &Attrs,StmtVector &Stmts) {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
131 assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
132 ParseScope CompoundScope(this, Scope::DeclScope);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
133 StmtVector CompoundedStmts;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
134
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
135 SourceLocation gotoLoc = ConsumeToken(); // eat the 'goto'.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
136 StmtResult gotoRes;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
137 Token TokAfterGoto = Tok;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
138 Stmtsp = &Stmts;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
139
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
140 gotoRes = ParseStatementOrDeclaration(Stmts, false);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
141 if (gotoRes.get() == NULL)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
142 return StmtError();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
143 else if (gotoRes.get()->getStmtClass() != Stmt::CallExprClass) { // if it is not function call
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
144 Diag(TokAfterGoto, diag::err_expected_ident_or_cs);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
145 return StmtError();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
146 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
147
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
148 assert((Attrs.empty() || gotoRes.isInvalid() || gotoRes.isUsable()) &&
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
149 "attributes on empty statement");
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
150 if (!(Attrs.empty() || gotoRes.isInvalid()))
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
151 gotoRes = Actions.ProcessStmtAttributes(gotoRes.get(), Attrs.getList(), Attrs.Range);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
152 if (gotoRes.isUsable())
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
153 CompoundedStmts.push_back(gotoRes.release());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
154
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
155 // add return; after goto codesegment();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
156 if (Actions.getCurFunctionDecl()->getResultType().getTypePtr()->is__CodeType()) {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
157 ExprResult retExpr;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
158 StmtResult retRes;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
159 retRes = Actions.ActOnReturnStmt(gotoLoc, retExpr.take());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
160 if (retRes.isUsable())
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
161 CompoundedStmts.push_back(retRes.release());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
162 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
163 return Actions.ActOnCompoundStmt(gotoLoc, Tok.getLocation(), CompoundedStmts, false);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
164 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
165 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
166  この関数では, goto の後の構文を解析して関数呼び出しの Stmt を生成する. その後, tail call elimination の条件を満たすために直後に return statement の生成も行う. 関数呼び出しの解析部分は ParseStatementOrDeclaration 関数に任せ, goto の後に関数呼び出しの構文がきていない場合にはエラーを出力する.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
167 \section{Tail call elimination pass の条件の達成}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
168 \label{sec:TCEreq}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
169 CbC の構文が解析できるようになったところで, 次に tail call elimination を強制する処理, つまり tail call elimination の条件を満たす処理の追加を行う. \ref{sec:TCE}節で述べた条件のうち, code segment を tail call にする (呼び出した直後に return 文がくる) という条件は前節で達成した. したがって残りの条件は, 呼び出し規約を fastcc, cc 10, cc 11 のいずれかにする, tailcallopt の有効化, tail call elimination pass の追加の三つである. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
170  まず初めに, tail call elimination pass の追加を行う. clang は最適化の pass の追加を \$(CLANG)/lib/CodeGen/BackendUtil.cpp の CreatePasses 関数内で行っている. clang では最適化レベルを 2 以上にした場合に tail call elimination が有効化されるが, その pass の追加はこの関数から呼び出される populateModulePassManager 関数で行われる. この関数は LLVM が用意した最適化に用いられる主要な pass を追加するものである. この関数を以下のリスト\ref{PassManager}のように変更した. 変数 MPM は PassManagerBase という pass の管理を行うクラスのインスタンスで, MPM の持つ add 関数を用いて pass の登録を行う. add 関数の引数に createTailCallEliminationPass 関数を指定することで tail call elimination pass が追加され, リスト\ref{PassManager}の 5, 11, 13 行目がその処理を行っている. この中で書き加えられたのは 5 行目と 11 行目のものである. 二箇所に記述しているのはこの関数が最適化レベルが 0 かどうかによって追加する pass を変えるためである. CbC コンパイラを実装するためにはどちらの場合でも tail call elimination pass が必要となるので二箇所に記述している. 5 行目 最適化レベルが 0 の場合, 11行目がそれ以外の場合ののための記述である. このとき, createTailCallEliminationPass 関数の引数は, tail call elimination を code segment のみに適用するかどうかを表す. 最適化レベルが 0 の場合に code segment 以外の関数に触れないようにするためにこのような引数を設けた.\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
171 \begin{lstlisting}[frame=lrbt,label=PassManager,caption={tail call elimnation pass の追加}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
172 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
173 if (OptLevel == 0) {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
174 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
175 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
176 MPM.add(createTailCallEliminationPass(true)); // Eliminate tail calls
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
177 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
178 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
179 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
180 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
181 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
182 MPM.add(createTailCallEliminationPass(false)); // Eliminate tail calls
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
183 #else
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
184 MPM.add(createTailCallEliminationPass()); // Eliminate tail calls
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
185 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
186 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
187 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
188  これで code segment の呼び出しに対して tail フラグが付与されるようになった. しかし実際にはこれだけでは不十分でさらに二つの pass を追加する必要がある. 追加する pass は SROA pass と codeGenPrepare pass である. 一つ目の SROA pass は メモリ参照を減らすスカラー置換を行う pass でこれにより LLVM IR の alloca 命令を可能な限り除去できる. tail call elimination の条件に直接記されてはいないが, tail call elimination pass を用いて tail フラグを付与する場合には 呼び出し元の関数に alloca がないことが求められるのである. 二つ目の codeGenPrepare pass は名前の通りコード生成の準備を行う pass で, これを通さないと if 文を用いた時に call の直後に配置した return 文が消えてしまう. これらの pass 追加されるように変更する必要がある. SROA pass は tail call elimination と同じようにして追加される pass なので同様にして追加することができる. codeGenPrepare pass はこれら二つとは異なり, addPassesToEmitFile という関数を とおして LLVM によって追加される. この時の追加されるかどうか条件が最適化レベルに依存するものであったため, code segment を持つ場合には最適化レベルに関わらず追加するように変更した.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
189  次に, 呼び出し規約の問題を解消する. 条件を満たす呼び出し規約は fastcc, cc 10, cc 11 の三種類があり, それぞれ簡単に説明すると以下の様な特徴がある.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
190 \begin{description}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
191 \item[fastcc]\mbox{}\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
192 この規約を指定すると, 情報をレジスタを用いて渡す等して, 可能な限り高速な呼び出しを試みるようになる. この呼び出し規約は可変引数をサポートせず, 呼び出される関数のプロトタイプと呼び出される関数が正確に一致する必要がある.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
193 \item[cc 10]\mbox{}\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
194 Glasgow Haskell Compiler のために実装された呼び出し規約. X86 でのみサポートされており, 引数に関するいくつかの制限をもつ. レジスタ内の値を全て渡し, 呼び出された関数はレジスタの値を保存できない. この呼び出し規約は関数型プログラミング言語を実装する際に使用される register pinning という技術の代わりとして特定の状況でしか使用してはならない.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
195 \item[cc 11]\mbox{}\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
196 High-Performance Erlang のために実装された呼び出し規約. 通常の C の呼び出し規約以上に引数を渡すためにレジスタを利用する. X86 でのみサポートされており, cc 10 同様に register pinning を用いる.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
197 \end{description}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
198  これらのうち, cc 10, cc 11 は関数型プログラミング言語の実装に用いられる register pinning という技術の代わりに用いられ, これを積極的に利用することは好ましくないとある. 対して fastcc には, 可変引数をサポートしない, プロトタイプは正確でなければならないといった条件があるが, 前者は \ref{sec:TCE}節で説明したとおり tail call elimination の条件に含まれており, 後者は特別厳しい条件ではない上, プロトタイプの不正な関数は clang がエラーを出してくれるので問題ないだろう. よって code segment の呼び出し規約には fastcc を用いることにした. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
199  fastcc の追加は clang が関数情報の設定処理を行っている箇所で行った. 関数情報は CGFunctionInfo というクラスを用いて管理される. 関数情報の設定は \$(CLANG)/lib/CodeGen /CGCall.cpp 内の arrangeLLVMFunctionInfo という関数で行われる. この関数内に以下のリスト\ref{CC} に示されるコードを加えた. 5行目が fastcc を設定している箇所である. 関数が \_\_code型の場合で, かつ可変長引数を持たない場合に呼び出し規約を fastcc に設定する. 可変長引数に関する条件を加えているのは, 可変長引数が使用されている場合には呼び出し規約を変えず tail call elimination を行わないことで通常の関数呼び出しを生成するためである.\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
200 \begin{lstlisting}[frame=lrbt,label=CC,caption={fastcc の追加}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
201 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
202 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
203 if(resultType.getTypePtr()->is__CodeType()){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
204 if(!required.allowsOptionalArgs())
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
205 CC = llvm::CallingConv::Fast;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
206 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
207 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
208 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
209 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
210  最後に, tailcallopt を有効化を行う. clang と LLVM は指定されたオプションを管理するクラスを別々に持っており, clang はユーザーに指定されたオプションを LLVM に引き継ぐ処理を持つ. その処理が行われているのが \$(CLANG)/lib/CodeGen/BackendUtil.cpp 内の CreateTargetMachine 関数である. この関数のオプションの引き継ぎを行っている箇所を以下のリスト\ref{option}のように変更する. 6 行目が tailcallopt を有効にしている箇所である. tailcallopt は内部では GuaranteedTailCallOpt となっており, code segment を持つ場合にこれを有効化する. 右辺の HasCodeSegment が code segment を持つか否かを表し, これは \ref{sec:add__code} 節で記したように, 予約語 \_\_code を解析する際に有効化される. また, 5 行目からわかるように LLVM 側でも HasCodeSegment というオプションを追加している. これは \ref{sec:TCEreq} 節で述べた codeGenPrepare pass を追加する際に利用する. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
211 \begin{lstlisting}[frame=lrbt,label=option,caption={オプションの引き継ぎ}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
212 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
213 Options.PositionIndependentExecutable = LangOpts.PIELevel != 0;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
214 Options.EnableSegmentedStacks = CodeGenOpts.EnableSegmentedStacks;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
215 #ifndef noCbC
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
216 Options.HasCodeSegment = LangOpts.HasCodeSegment;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
217 Options.GuaranteedTailCallOpt = LangOpts.HasCodeSegment;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
218 #endif
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
219 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
220 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
221  LLVM でのオプションの追加方法についてもここで述べておく. LLVM のオプションは TargetOptions というクラスが管理しており, その定義は \$(LLVM)/include/llvm/Target/ TargetOptions.h で行われている. こちらはマクロは使っておらずビットフィールドを用いて定義されている. TargetOptions クラスの中で変数を宣言するだけで追加できるので, コードは省略する.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
222 \section{環境付き継続の実装}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
223 環境付き継続を行うためには \ref{sec:withEnv} 節で述べたように, \_\_return, \_\_environment という特殊変数を用いる. これら二つの変数の実装方法には様々な方法が考えられる. GCC 上に実装した CbC コンパイラでは GCC による C の拡張構文である内部関数を用いていた. しかし, clang ではこの拡張構文は対応しておらず, 別の方法をとる必要がある. そこで今回の実装には setjmp, longjmp を用いた実装を行った.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
224
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
225 \subsection{clang により追加されるコード}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
226 環境付き継続は, \_\_return, \_\_environment が使用された時に自動的にあるコードを生成することで実現される. 具体的には, リスト \ref{autoCodeGenB} のようなコードを, コンパイルした場合にはリスト \ref{autoCodeGenA} のように解釈することで実現される.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
227 \begin{lstlisting}[frame=lrbt,label=autoCodeGenB,caption={環境付き継続の例}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
228 __code cs(int retval,__code(*ret)(int,void *),void *env){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
229 goto ret(n, env);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
230 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
231
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
232 int func (){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
233 goto cs(30, __return, __environment);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
234 return 0;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
235 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
236 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
237 \begin{lstlisting}[frame=lrbt,label=autoCodeGenA,caption={内部での解釈}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
238 #include <setjmp.h>
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
239
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
240 struct CbC_env {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
241 void *ret_p,*env;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
242 };
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
243
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
244 __code cs(int retval,__code(*ret)(int,void *),void *env){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
245 goto ret(n, env);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
246 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
247
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
248 __code return1 (int retval, void* env){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
249 *(int*)((struct CbC_env *)(env))->ret_p = retcal;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
250 longjmp((int*)(((struct CbC_env *)env)->env),1);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
251 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
252
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
253 int func (){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
254 __code (*__return)();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
255 struct CbC_env __environment;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
256 jmp_buf env;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
257 int retval;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
258 __environment.ret_p = &retval;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
259 __environment.env = &env;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
260 __return = return1;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
261 if (setjmp(__environment.env)){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
262 return retval;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
263 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
264 goto code1(30, __return, &__environment);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
265 return 0;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
266 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
267 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
268  追加された処理は, setjmp ヘッダのインクルード, 環境と戻り値を保持する構造体 CbC\_env の定義, 元の環境に戻るための特殊 code segment return1 の定義, そして関数 func 内の 17 行目から 26 行目までの処理であり, 27 行目の継続の第三引数も参照渡しに変更される. 追加された処理の大まかな流れを説明する. 環境付き継続を用いる関数は継続前に setjmp を用いて戻り先の環境を保存し, 継続を行う. このとき, 引数として渡される \_\_return には特殊 code segment return1 のアドレス, \_\_environment の持つメンバには戻り値として返される値を持つ変数のアドレスと, setjmp により保存された継続前の環境が保持されている. 元の環境に戻るための code segment は自動生成されるので, 継続先の code segment は返す戻り値と \_\_environemnt を引数として \_\_return の指す code segment を呼び出すだけで元の環境に戻れる. return1 は 構造体の持つ戻り値へのポインタを利用して戻り値を更新した後, longjmp を用いて元の環境に戻る. longjmp によって再度 setjmp の呼び出しに戻るが今回は if文内に入り, 戻り値を返す.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
269 %% \begin{lstlisting}[frame=lrbt,label=autoCodeGenA,caption={内部で自動追加されるコード}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
270 %% #include <setjmp.h>
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
271
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
272 %% struct CbC_env {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
273 %% void *ret_p,*env;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
274 %% };
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
275
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
276 %% __code cs(int retval,__code(*ret)(int,void *),void *env){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
277 %% goto ret(n, env);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
278 %% }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
279
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
280 %% __code return1 (int retval, void* env){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
281 %% *(int*)((struct CbC_env *)(env))->ret_p = retval;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
282 %% longjmp((int*)(((struct CbC_env *)env)->env),1);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
283 %% }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
284
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
285 %% int func (){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
286 %% goto code1(30,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
287 %% ({
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
288 %% __code (*__CbC_return)();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
289 %% __CbC_return = return1;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
290 %% __CbC_return;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
291 %% }),
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
292 %% ({
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
293 %% struct CbC_env __CbC_environment;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
294 %% jmp_buf env;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
295 %% int retval;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
296 %% __CbC_environment.ret_p = &retval;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
297 %% __CbC_environment.env = &env;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
298 %% if (setjmp(__CbC_environment.env)){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
299 %% return retval;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
300 %% }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
301 %% &__CbC_environment;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
302 %% })
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
303 %% );
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
304 %% return 0;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
305 %% }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
306 %% \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
307 %%  自動生成された処理は, setjmp ヘッダのインクルード, 構造体 CbC\_env の定義, 元の環境に戻るための特殊 code segment return1 の定義であり, これに加えて \_\_return, \_\_environment が環境付き継続の前準備を行う処理に変更される. \_\_return は内部では元の環境に戻るための code segment へのポインタの宣言文と, アドレスの代入を行う文に変換され, \_\_environment は内部では環境を保持する構造体, setjmp, longjmp が用いる jmp\_buf, 関数の戻り値となる retval の宣言文, 構造体のメンバの値の設定を行う代入文, そして特殊 code segment return1 の戻り先となる setjmp を用いた構文に変換される. また, \_\_return, \_\_environment 変数を置換した処理は Statement Exprs を利用しており, これにより, 変数への代入も可能となっている. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
308
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
309 \section{実装方法}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
310  前節より, それぞれの予約語を解析する際に自動生成しなければならない文は次のようになることがわかる.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
311 \begin{itemize}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
312 \item \_\_return
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
313 \begin{itemize}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
314 \item 元の環境に戻るための特殊な code segment
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
315 \item 各変数の宣言及び代入文
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
316 \end{itemize}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
317 \item \_\_environment
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
318 \begin{itemize}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
319 \item 環境を保持する構造体 CbC\_env の定義
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
320 \item 各変数の宣言及び代入文
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
321 \item setjmp を条件文にとり, 真の場合に関数の戻り値を返す if文
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
322 \end{itemize}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
323 \item どちらにも依存しない
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
324 \begin{itemize}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
325 \item setjmp.h のインクルード文
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
326 \end{itemize}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
327 \end{itemize}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
328  setjmp.h のインクルード文がどちらにも属さないのは, 無条件でこのヘッダをインクルードするようにしてもよいからである. 必要のないコードは最適化によって除去されるので, 使用されない場合でもインクルードして構わない. また, これらの文を生成する際, 元の関数の型の戻り値を返せるようにしなければならないが, \ref{QualType} 節で説明したように, clang では型情報を QualType が管理しているので, 生成する関数や変数に対して元の関数の返り値に対応する QualType を与えるだけでこの問題は解決する. 尚, 二つの予約語を登録する処理は既に \ref{sec:add__code} 節で説明したので省く.\\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
329  まずはじめに setjmp.h のインクルード文の生成について説明する. clang では include マクロによって他のファイルのインクルードを行う場合, 字句解析対象となるのファイルの変更を行う. 本研究では, これらの処理に必要なものを IncludeHeader という一つの関数にまとめ, それを呼び出すことで任意のファイルをインクルードできるようにした. その関数のうち, 重要な部分を抜き出したものを以下のリスト \ref{IncludeHeader} に示す. この関数は引数に現在の token とインクルードするファイルの名前を求める. まずこの関数は, 現在の token の保存処理を行う. これは, この関数が呼ばれた時点で取得された token はすでに字句解析対象のバッファから取り除かれており, これを保存しておかないとインクルード処理終了後の構文解析に影響が出るために行っている. 次に, 指定されたファイルの検索を行う. その処理を行っているのは 11行目であり, このときファイルが見つからなかった場合には NULL が返るので, これを利用してエラーの生成も行っている. 解析対象の変更を行っているのが 16行目以降の処理で, 実際にファイルを移っているのは 18行目の EnterSourceFile 関数である. この関数によって字句解析対象が現在のファイルから指定したファイルへと変更される. また, この関数の戻り値はファイルのインクルード処理を行ったかどうかを判断するために用いる. \\
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
330 \begin{lstlisting}[frame=lrbt,label=IncludeHeader,caption={IncludeHeader 関数}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
331 bool Preprocessor::IncludeHeader(Token Tok, const char* Name) {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
332 if (SavedTokenFlag) // If the lexer has already entered a header file, we have to leave this function.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
333 return false;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
334 SourceLocation Loc = Tok.getLocation();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
335 SavedToken = Tok;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
336 SavedDepth = IncludeMacroStack.size();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
337 SavedTokenFlag = true;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
338
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
339 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
340
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
341 const FileEntry *File = LookupFile(Loc, Filename, isAngled, LookupFrom, CurDir, NULL, NULL,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
342 HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule : 0);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
343
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
344 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
345
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
346 FileID FID = SourceMgr.createFileID(File, Loc, FileCharacter);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
347 EnterSourceFile(FID, CurDir, FilenameTok.getLocation(), static_cast<bool>(BuildingModule));
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
348 return true;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
349 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
350 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
351  次に, 元の環境に戻るための特殊な code segment の定義生成処理の説明をする. これを行うためには clang の持つ AST に関数の定義を加えてやれば良い. 今回の実装でその処理を担うのが以下のリスト \ref{return1} に示される CreateRetCS 関数である. ただしここでは重要でない箇所を省いている. この関数は引数として生成する関数の名前を受け取る. 2, 3 行目が元の関数の QualType を取得する処理である. 5 行目から 14 行目までの処理は関数宣言のためにスコープをグローバルスコープに変更するための処理で, すべての処理を終えた後, 59 行目から 62 行目の処理によって元のスコープに戻す. 16 行目から 42 行目までが関数のプロトタイプ宣言に関する設定処理を行っており, 29 行目で 取得しておいた QualType を利用していることがわかる. 44 行目からが関数の持つ処理の定義を指定する部分にあたり, 52 行目にある StmtVector クラスのインスタンスに対して任意の文に対応する StmtResult を追加し, 54 行目の関数を呼び出すと戻り値としてこの関数の中身を表す StmtResult を得ることができる. その後これを定義や宣言を管理するクラスである Decl へと変換し, 58 行目の関数を呼び出すことで生成した関数の定義が AST に追加される.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
352 \begin{lstlisting}[frame=lrbt,label=return1,caption={CreateRetCS 関数}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
353 bool Parser::CreateRetCS(IdentifierInfo *csName){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
354 FunctionDecl *CurFunctionDecl = Actions.getCurFunctionDecl();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
355 QualType CurFuncResQT = CurFunctionDecl->getResultType();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
356
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
357 Scope *SavedScope = getCurScope();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
358 DeclContext *SavedContext = Actions.CurContext;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
359 TypeSourceInfo *CurFuncTI = Actions.Context.CreateTypeSourceInfo(CurFuncResQT);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
360 sema::FunctionScopeInfo *SavedFSI = Actions.FunctionScopes.pop_back_val();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
361
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
362 Actions.CurContext = static_cast<DeclContext *>(Actions.Context.getTranslationUnitDecl());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
363 Scope *TopScope = getCurScope();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
364 while(TopScope->getParent() != NULL)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
365 TopScope = TopScope->getParent();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
366 Actions.CurScope = TopScope;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
367
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
368 DeclGroupPtrTy returnDecl = DeclGroupPtrTy();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
369 ParsingDeclSpec PDS(*this);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
370 setTST(&PDS, DeclSpec::TST___code);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
371 ParsingDeclarator D(*this, PDS, static_cast<Declarator::TheContext>(Declarator::FileContext));
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
372 D.SetIdentifier(csName, Loc);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
373 ParseScope PrototypeScope(this,Scope::FunctionPrototypeScope|Scope::DeclScope|Scope::FunctionDeclarationScope);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
374 SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
375 DeclSpec FDS(AttrFactory);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
376 ParmVarDecl *Param;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
377
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
378 IdentifierInfo *retvalII = CreateIdentifierInfo(__CBC_RETVAL_NAME, Loc);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
379 Param = CreateParam(retvalII);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
380 Param->setTypeSourceInfo(CurFuncTI);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
381 Param->setType(CurFuncResQT);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
382
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
383 ParamInfo.push_back(DeclaratorChunk::ParamInfo(retvalII, Loc, Param, 0));
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
384 IdentifierInfo *envII = CreateIdentifierInfo(__CBC_STRUCT_ENV_NAME, Loc);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
385 Param = CreateParam(envII, 1, DeclSpec::TST_void);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
386 ParamInfo.push_back(DeclaratorChunk::ParamInfo(envII, Loc, Param, 0));
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
387
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
388 D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto, IsAmbiguous, Loc, ParamInfo.data(), ParamInfo.size(), EllipsisLoc, Loc,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
389 FDS.getTypeQualifiers(), RefQualifierIsLValueRef, RefQualifierLoc, ConstQualifierLoc,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
390 VolatileQualifierLoc, SourceLocation(), ESpecType, ESpecRange.getBegin(),
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
391 DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(),
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
392 NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
393 Loc, Loc, D, TrailingReturnType), FnAttrs, Loc);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
394 PrototypeScope.Exit();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
395
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
396 Decl *TheDecl;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
397 ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
398 Decl *BodyRes = Actions.ActOnStartOfFunctionDef(getCurScope(), D);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
399
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
400 D.complete(BodyRes);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
401 D.getMutableDeclSpec().abort();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
402 Actions.ActOnDefaultCtorInitializers(BodyRes);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
403 StmtResult FnBody;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
404 StmtVector FnStmts;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
405 /* add function body statements */
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
406 FnBody = Actions.ActOnCompoundStmt(Loc, Loc, FnStmts, false);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
407 BodyScope.Exit();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
408 TheDecl = Actions.ActOnFinishFunctionBody(BodyRes, FnBody.take());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
409 returnDecl = Actions.ConvertDeclToDeclGroup(TheDecl);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
410 (&Actions.getASTConsumer())->HandleTopLevelDecl(returnDecl.get());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
411 Actions.CurScope = SavedScope;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
412 Actions.CurContext = SavedContext;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
413 Actions.FunctionScopes.push_back(SavedFSI);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
414 return false;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
415 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
416 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
417  つづいて構造体 CbC\_env の定義を行う. この構造体は setjmp, longjmp が環境の保持に使う jmp\_buf へのポインタと元の関数の戻り値となる変数へのポインタを持つ. 構造体の宣言は通常, 構文解析器によって Decl というクラスのインスタンスが生成され, それを利用して行う. 今回の実装では Decl の生成を手書きのコードで行うことで, 自動で構造体の定義を行う処理を実現した. 今回の実装ではそのコード群を Create\_\_CbC\_envStruct という一つの関数にまとめた. その関数のうち,重要な部分を抜き出したものを以下のリスト \ref{CbC_env} に示す. この関数はソースコードの位置と C++ で用いられるアクセス修飾子を引数に取る. この関数もスコープを変更する処理を持つが, それについては先ほど説明したので省いている. 12 行目から 22 行目までが, この構造体の Decl を生成する処理である. メンバの設定を行っているのが 27 行目から 30 行目で, ここで使用している Create\_\_CbC\_envBody 関数はメンバの宣言を行うために独自に作成した関数である. 構造体のメンバとして宣言するために ActOnField という Sema クラスの関数を呼び出す以外は後述する CreateDeclStmt 関数と処理内容にあまり差が無いため, この関数については本論文では説明を省く. 32 行目で呼び出している ActOnTagFinishDefinision が, 生成した Decl を元に構造体の宣言の意味解析を行ってくれる関数である. これにより, 生成した構造体に対応する Type も生成される.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
418 \begin{lstlisting}[frame=lrbt,label=CbC_env,caption={Create\_\_CbC\_envStruct 関数}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
419 void Parser::Create__CbC_envStruct(SourceLocation Loc, AccessSpecifier AS) {
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
420
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
421 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
422
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
423 ParsingDeclSpec SDS(*this);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
424 DeclSpec::TST TagType = DeclSpec::TST_struct;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
425 DeclResult TagOrTempResult = true;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
426 bool Owned = false;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
427 bool IsDependent = false;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
428 TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, Sema::TUK_Definition, Loc,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
429 SDS.getTypeSpecScope(), Name, Loc, attrs.getList(), AS,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
430 SDS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
431 SourceLocation(), false, clang::TypeResult());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
432
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
433 Decl *TagDecl = TagOrTempResult.get();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
434 ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
435 Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
436 SmallVector<Decl *, 32> FieldDecls;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
437
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
438 FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_void, Loc, __CBC_STRUCT_POINTER_NAME));
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
439 FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_int, Loc, __CBC_STRUCT_ENV_NAME));
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
440
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
441 Actions.ActOnFields(getCurScope(),Loc, TagDecl, FieldDecls,Loc, Loc,attrs.getList());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
442 StructScope.Exit();
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
443 Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, Loc);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
444
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
445 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
446 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
447 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
448  つづいて両予約語解析時に共通する処理の一つである変数の定義文に関して説明する. これも定義に関する文であるので Decl の生成がメインとなる. 今回の実装では以下のリスト\ref{DeclStmt} に示す CreateDeclStmt という関数を作り, その関数によってその処理を行う. ここでも重要でない処理は省いている. この関数は引数として変数名, code segment へのポインタかどうか, 呼び出し元の関数の型をコピーするかどうか, 変数の型, 構造体だった場合の構造体名を持つ. 4 行目の setTST 関数が指定された型修飾子を設定している箇所である. 変数名は 6 行目の SetIdentifier 関数によって設定され, その後は関数へのポインタだった場合や構造体だった場合のときにのみ行われる処理が来るがここでは省いた. その後型コピーを行うかどうかで処理が異なる. 型コピーの方法については既に述べたのでここでは省く. すべての処理を終えると, Decl の意味解析が行われ, その結果が StmtResult として返る.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
449 \begin{lstlisting}[frame=lrbt,label=DeclStmt,caption={CreateDeclStmt 関数}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
450 StmtResult Parser::CreateDeclStmt(IdentifierInfo *II, bool isRetCS, bool copyType, DeclSpec::TST valueType, IdentifierInfo* Name){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
451 DeclGroupPtrTy DeclGPT;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
452 ParsingDeclSpec DS(*this);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
453 setTST(&DS, valueType, Name);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
454 ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Declarator::BlockContext));
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
455 D.SetIdentifier(II, Loc);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
456
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
457 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
458
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
459 SmallVector<Decl *, 8> DeclsInGroup;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
460 Decl *FirstDecl;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
461
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
462 if (copyType)
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
463 FirstDecl = HandleDeclAndChangeDeclType(D);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
464 else
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
465 FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
466
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
467 D.complete(FirstDecl);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
468 DeclsInGroup.push_back(FirstDecl);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
469 DeclGPT = Actions.FinalizeDeclaratorGroup(getCurScope(), *DSp, DeclsInGroup);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
470 return Actions.ActOnDeclStmt(DeclGPT, Loc, Loc);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
471 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
472 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
473  つづいて両予約語解析時に共通するもう一つの処理, 代入文の生成について説明する. 今回の実装ではこの処理を以下のリスト \ref{assignment} に示す CreateAssginmentStmt 関数にまとめた. ここでも重要でない処理は省いている. この関数は引数として左辺,右辺の変数名と, 左辺が構造体のメンバかどうか, 右辺が演算子 \& を持つかどうか, 左辺が構造体だった場合の構造体名を求める. 8 行目から 14 行目までは左辺に対応する ExprResult を取得する処理で, ExprResult は一つの式に対応するクラスである. 同様に, 18 行目が右辺に対応する ExprResult を取得する処理で, 代入式の生成は 20 行目に当たる. ここで生成した ExprResult を ActOnExprStmt に渡すことで, 式として StmtResult に変換される.
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
474 \begin{lstlisting}[frame=lrbt,label=assignment,caption={CreateAssignmentStmt 関数}]
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
475 StmtResult Parser::CreateAssignmentStmt(IdentifierInfo* LHSII, IdentifierInfo* RHSII, bool LHSisMemberAccess, bool RHShasAmp,
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
476 IdentifierInfo* extraLHSII){
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
477 ExprResult Expr,LHS,RHS;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
478 Token Next,LHSToken;
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
479
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
480 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
481
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
482 ExternalSpace::StatementFilterCCC Validator(Next);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
483 Sema::NameClassification Classification = Actions.ClassifyName(getCurScope(), SS, LHSII, Loc, Next, false, SS.isEmpty() ? &Validator : 0);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
484 setExprAnnotation(LHSToken, Classification.getExpression());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
485 LHSToken.setAnnotationEndLoc(Loc);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
486 PP.AnnotateCachedTokens(LHSToken);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
487
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
488 LHS = getExprAnnotation(LHSToken);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
489
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
490 :
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
491
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
492 RHS = LookupNameAndBuildExpr(RHSII);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
493
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
494 Expr = Actions.ActOnBinOp(getCurScope(), Loc,tok::equal,LHS.take(),RHS.take());
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
495
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
496 return Actions.ActOnExprStmt(Expr);
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
497 }
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
498 \end{lstlisting}
ce014a8b669e wrote final thesis
kaito
parents:
diff changeset
499  さて, 残る if 文の自動生成についてであるが, これは if 文のためのスコープを生成した後条件文を作り, その後 if 文内のスコープを作りそこに文を生成していくことで行える. この処理は前述した code segment の生成に含まれる処理に酷似する. したがってここではその説明を省略する. \\