blob: 9d2e9b52393708cfd6986006b5ef7f715864db0f [file] [log] [blame]
Chris Lattner0ccd51e2006-08-09 05:47:47 +00001//===--- Statement.cpp - Statement and Block Parser -----------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Statement and Block portions of the Parser
11// interface.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Parse/Parser.h"
16#include "clang/Basic/Diagnostic.h"
17using namespace llvm;
18using namespace clang;
19
20//===----------------------------------------------------------------------===//
21// C99 6.8: Statements and Blocks.
22//===----------------------------------------------------------------------===//
23
24/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
25/// StatementOrDeclaration:
26/// statement
27/// declaration
28///
29/// statement:
30/// labeled-statement
31/// compound-statement
32/// expression-statement
33/// selection-statement
34/// iteration-statement
35/// jump-statement
36/// [OBC] objc-throw-statement [TODO]
37/// [OBC] objc-try-catch-statement [TODO]
38/// [OBC] objc-synchronized-statement [TODO]
39/// [GNU] asm-statement [TODO]
40/// [OMP] openmp-construct [TODO]
41///
42/// labeled-statement:
43/// identifier ':' statement
44/// 'case' constant-expression ':' statement
45/// 'default' ':' statement
46///
Chris Lattner0ccd51e2006-08-09 05:47:47 +000047/// selection-statement:
48/// if-statement
49/// switch-statement
50///
51/// iteration-statement:
52/// while-statement
53/// do-statement
54/// for-statement
55///
Chris Lattner9075bd72006-08-10 04:59:57 +000056/// expression-statement:
57/// expression[opt] ';'
58///
Chris Lattner0ccd51e2006-08-09 05:47:47 +000059/// jump-statement:
60/// 'goto' identifier ';'
61/// 'continue' ';'
62/// 'break' ';'
63/// 'return' expression[opt] ';'
64/// [GNU] 'goto' '*' expression ';' [TODO]
65///
66/// [OBC] objc-throw-statement: [TODO]
67/// [OBC] '@' 'throw' expression ';' [TODO]
68/// [OBC] '@' 'throw' ';' [TODO]
69///
Chris Lattnerc951dae2006-08-10 04:23:57 +000070void Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
Chris Lattner0ccd51e2006-08-09 05:47:47 +000071 switch (Tok.getKind()) {
72 default:
73 Diag(Tok, diag::err_expected_statement_declaration);
74 SkipUntil(tok::semi);
75 break;
76
Chris Lattner9075bd72006-08-10 04:59:57 +000077
78 case tok::l_brace: // C99 6.8.2: compound-statement
Chris Lattner0ccd51e2006-08-09 05:47:47 +000079 ParseCompoundStatement();
80 break;
Chris Lattner9075bd72006-08-10 04:59:57 +000081 case tok::semi: // C99 6.8.3: expression[opt] ';'
Chris Lattnerc951dae2006-08-10 04:23:57 +000082 ConsumeToken();
83 break;
Chris Lattner9075bd72006-08-10 04:59:57 +000084 case tok::kw_if: // C99 6.8.4.1: if-statement
Chris Lattnerc951dae2006-08-10 04:23:57 +000085 ParseIfStatement();
86 break;
Chris Lattner9075bd72006-08-10 04:59:57 +000087 case tok::kw_switch: // C99 6.8.4.2: switch-statement
88 ParseSwitchStatement();
89 break;
90 case tok::kw_while: // C99 6.8.5.1: while-statement
91 ParseWhileStatement();
92 break;
93 case tok::kw_do: // C99 6.8.5.2: do-statement
94 ParseDoStatement();
95 break;
96 case tok::kw_for: // C99 6.8.5.3: for-statement
97 ParseForStatement();
98 break;
Chris Lattnerc951dae2006-08-10 04:23:57 +000099 // TODO: Handle OnlyStatement..
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000100 }
101}
102
103/// ParseCompoundStatement - Parse a "{}" block.
104///
105/// compound-statement: [C99 6.8.2]
106/// { block-item-list[opt] }
107/// [GNU] { label-declarations block-item-list } [TODO]
108///
109/// block-item-list:
110/// block-item
111/// block-item-list block-item
112///
113/// block-item:
114/// declaration
115/// [GNU] '__extension__' declaration [TODO]
116/// statement
117/// [OMP] openmp-directive [TODO]
118///
119/// [GNU] label-declarations:
120/// [GNU] label-declaration
121/// [GNU] label-declarations label-declaration
122///
123/// [GNU] label-declaration:
124/// [GNU] '__label__' identifier-list ';'
125///
126/// [OMP] openmp-directive: [TODO]
127/// [OMP] barrier-directive
128/// [OMP] flush-directive
129void Parser::ParseCompoundStatement() {
130 assert(Tok.getKind() == tok::l_brace && "Not a compount stmt!");
131 ConsumeBrace(); // eat the '{'.
132
133 while (Tok.getKind() != tok::r_brace && Tok.getKind() != tok::eof)
Chris Lattnerc951dae2006-08-10 04:23:57 +0000134 ParseStatementOrDeclaration(false);
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000135
136 // We broke out of the while loop because we found a '}' or EOF.
137 if (Tok.getKind() == tok::r_brace)
138 ConsumeBrace();
139 else
140 Diag(Tok, diag::err_expected_rbrace);
141}
Chris Lattnerc951dae2006-08-10 04:23:57 +0000142
143/// ParseIfStatement
144/// if-statement: [C99 6.8.4.1]
145/// 'if' '(' expression ')' statement
146/// 'if' '(' expression ')' statement 'else' statement
147void Parser::ParseIfStatement() {
148 assert(Tok.getKind() == tok::kw_if && "Not an if stmt!");
149 ConsumeToken(); // eat the 'if'.
150
151 if (Tok.getKind() != tok::l_paren) {
Chris Lattner9075bd72006-08-10 04:59:57 +0000152 Diag(Tok, diag::err_expected_lparen_after, "if");
Chris Lattnerc951dae2006-08-10 04:23:57 +0000153 SkipUntil(tok::semi);
154 return;
155 }
156
157 // Parse the condition.
158 ParseParenExpression();
159
160 // Read the if condition.
161 ParseStatement();
162
163 // If it has an else, parse it.
164 if (Tok.getKind() == tok::kw_else) {
165 ConsumeToken();
166 ParseStatement();
167 }
Chris Lattnerc951dae2006-08-10 04:23:57 +0000168}
169
Chris Lattner9075bd72006-08-10 04:59:57 +0000170/// ParseSwitchStatement
171/// switch-statement:
172/// 'switch' '(' expression ')' statement
173void Parser::ParseSwitchStatement() {
174 assert(Tok.getKind() == tok::kw_switch && "Not a switch stmt!");
175 ConsumeToken(); // eat the 'switch'.
176
177 if (Tok.getKind() != tok::l_paren) {
178 Diag(Tok, diag::err_expected_lparen_after, "switch");
179 SkipUntil(tok::semi);
180 return;
181 }
182
183 // Parse the condition.
184 ParseParenExpression();
185
186 // Read the body statement.
187 ParseStatement();
188}
189
190/// ParseWhileStatement
191/// while-statement: [C99 6.8.5.1]
192/// 'while' '(' expression ')' statement
193void Parser::ParseWhileStatement() {
194 assert(Tok.getKind() == tok::kw_while && "Not a while stmt!");
195 ConsumeToken(); // eat the 'while'.
196
197 if (Tok.getKind() != tok::l_paren) {
198 Diag(Tok, diag::err_expected_lparen_after, "while");
199 SkipUntil(tok::semi);
200 return;
201 }
202
203 // Parse the condition.
204 ParseParenExpression();
205
206 // Read the body statement.
207 ParseStatement();
208}
209
210/// ParseDoStatement
211/// do-statement: [C99 6.8.5.2]
212/// 'do' statement 'while' '(' expression ')' ';'
213void Parser::ParseDoStatement() {
214 assert(Tok.getKind() == tok::kw_do && "Not a do stmt!");
215 SourceLocation DoLoc = Tok.getLocation();
216 ConsumeToken(); // eat the 'do'.
217
218 // Read the body statement.
219 ParseStatement();
220
221 if (Tok.getKind() != tok::kw_while) {
222 Diag(Tok, diag::err_expected_while);
223 Diag(DoLoc, diag::err_matching);
224 SkipUntil(tok::semi);
225 return;
226 }
227 ConsumeToken();
228
229 if (Tok.getKind() != tok::l_paren) {
230 Diag(Tok, diag::err_expected_lparen_after, "do/while");
231 SkipUntil(tok::semi);
232 return;
233 }
234
235 // Parse the condition.
236 ParseParenExpression();
237
238 if (Tok.getKind() != tok::semi) {
239 Diag(Tok, diag::err_expected_semi_do_while);
240 SkipUntil(tok::semi);
241 return;
242 }
243}
244
245/// ParseForStatement
246/// for-statement: [C99 6.8.5.3]
247/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
248/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
249void Parser::ParseForStatement() {
250 assert(Tok.getKind() == tok::kw_for && "Not a for stmt!");
251 SourceLocation ForLoc = Tok.getLocation();
252 ConsumeToken(); // eat the 'for'.
253
254 if (Tok.getKind() != tok::l_paren) {
255 Diag(Tok, diag::err_expected_lparen_after, "for");
256 SkipUntil(tok::semi);
257 return;
258 }
259
260 SourceLocation LParenLoc = Tok.getLocation();
261 ConsumeParen();
262
263 // Parse the first part of the for specifier.
264 if (Tok.getKind() == tok::semi) { // for (;
265 // no first part.
266 } else if (isDeclarationSpecifier()) { // for (int X = 4;
267 // FIXME: Parse declaration.
268 assert(0);
269 } else {
270 ParseExpression();
271 }
272
273 if (Tok.getKind() == tok::semi) {
274 ConsumeToken();
275 } else {
276 Diag(Tok, diag::err_expected_semi_for);
277 Diag(ForLoc, diag::err_matching);
278 SkipUntil(tok::semi);
279 }
280
281 // Parse the second part of the for specifier.
282 if (Tok.getKind() == tok::semi) { // for (...;;
283 // no second part.
284 } else {
285 ParseExpression();
286 }
287
288 if (Tok.getKind() == tok::semi) {
289 ConsumeToken();
290 } else {
291 Diag(Tok, diag::err_expected_semi_for);
292 Diag(ForLoc, diag::err_matching);
293 SkipUntil(tok::semi);
294 }
295
296 // Parse the third part of the for specifier.
297 if (Tok.getKind() == tok::r_paren) { // for (...;...;)
298 // no third part.
299 } else {
300 ParseExpression();
301 }
302
303 if (Tok.getKind() == tok::r_paren) {
304 ConsumeParen();
305 } else {
306 Diag(Tok, diag::err_expected_rparen);
307 Diag(LParenLoc, diag::err_matching);
308 SkipUntil(tok::r_paren);
309 return;
310 }
311
312 // Read the body statement.
313 ParseStatement();
314}
Chris Lattnerc951dae2006-08-10 04:23:57 +0000315