blob: d483775a6cc7fcb720cf0e4878f506e1d19460ba [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"
Chris Lattner53361ac2006-08-10 05:19:57 +000017#include "clang/Parse/Declarations.h"
Chris Lattner0ccd51e2006-08-09 05:47:47 +000018using namespace llvm;
19using namespace clang;
20
21//===----------------------------------------------------------------------===//
22// C99 6.8: Statements and Blocks.
23//===----------------------------------------------------------------------===//
24
25/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
26/// StatementOrDeclaration:
27/// statement
28/// declaration
29///
30/// statement:
31/// labeled-statement
32/// compound-statement
33/// expression-statement
34/// selection-statement
35/// iteration-statement
36/// jump-statement
37/// [OBC] objc-throw-statement [TODO]
38/// [OBC] objc-try-catch-statement [TODO]
39/// [OBC] objc-synchronized-statement [TODO]
40/// [GNU] asm-statement [TODO]
41/// [OMP] openmp-construct [TODO]
42///
43/// labeled-statement:
44/// identifier ':' statement
45/// 'case' constant-expression ':' statement
46/// 'default' ':' statement
47///
Chris Lattner0ccd51e2006-08-09 05:47:47 +000048/// selection-statement:
49/// if-statement
50/// switch-statement
51///
52/// iteration-statement:
53/// while-statement
54/// do-statement
55/// for-statement
56///
Chris Lattner9075bd72006-08-10 04:59:57 +000057/// expression-statement:
58/// expression[opt] ';'
59///
Chris Lattner0ccd51e2006-08-09 05:47:47 +000060/// jump-statement:
61/// 'goto' identifier ';'
62/// 'continue' ';'
63/// 'break' ';'
64/// 'return' expression[opt] ';'
Chris Lattner503fadc2006-08-10 05:45:44 +000065/// [GNU] 'goto' '*' expression ';'
Chris Lattner0ccd51e2006-08-09 05:47:47 +000066///
67/// [OBC] objc-throw-statement: [TODO]
68/// [OBC] '@' 'throw' expression ';' [TODO]
69/// [OBC] '@' 'throw' ';' [TODO]
70///
Chris Lattnerc951dae2006-08-10 04:23:57 +000071void Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
Chris Lattner503fadc2006-08-10 05:45:44 +000072 const char *SemiError = 0;
73
74 // Cases in this switch statement should fall through if the parser expects
75 // the token to end in a semicolon (in which case SemiError should be set),
76 // or they directly 'return;' if not.
Chris Lattner0ccd51e2006-08-09 05:47:47 +000077 switch (Tok.getKind()) {
78 default:
79 Diag(Tok, diag::err_expected_statement_declaration);
80 SkipUntil(tok::semi);
Chris Lattner503fadc2006-08-10 05:45:44 +000081 return;
Chris Lattner0ccd51e2006-08-09 05:47:47 +000082
Chris Lattner9075bd72006-08-10 04:59:57 +000083
84 case tok::l_brace: // C99 6.8.2: compound-statement
Chris Lattner0ccd51e2006-08-09 05:47:47 +000085 ParseCompoundStatement();
Chris Lattner503fadc2006-08-10 05:45:44 +000086 return;
Chris Lattner9075bd72006-08-10 04:59:57 +000087 case tok::semi: // C99 6.8.3: expression[opt] ';'
Chris Lattnerc951dae2006-08-10 04:23:57 +000088 ConsumeToken();
Chris Lattner503fadc2006-08-10 05:45:44 +000089 return;
90
Chris Lattner9075bd72006-08-10 04:59:57 +000091 case tok::kw_if: // C99 6.8.4.1: if-statement
Chris Lattnerc951dae2006-08-10 04:23:57 +000092 ParseIfStatement();
Chris Lattner503fadc2006-08-10 05:45:44 +000093 return;
Chris Lattner9075bd72006-08-10 04:59:57 +000094 case tok::kw_switch: // C99 6.8.4.2: switch-statement
95 ParseSwitchStatement();
Chris Lattner503fadc2006-08-10 05:45:44 +000096 return;
97
Chris Lattner9075bd72006-08-10 04:59:57 +000098 case tok::kw_while: // C99 6.8.5.1: while-statement
99 ParseWhileStatement();
Chris Lattner503fadc2006-08-10 05:45:44 +0000100 return;
Chris Lattner9075bd72006-08-10 04:59:57 +0000101 case tok::kw_do: // C99 6.8.5.2: do-statement
102 ParseDoStatement();
Chris Lattner503fadc2006-08-10 05:45:44 +0000103 SemiError = "do/while loop";
Chris Lattner9075bd72006-08-10 04:59:57 +0000104 break;
105 case tok::kw_for: // C99 6.8.5.3: for-statement
106 ParseForStatement();
Chris Lattner503fadc2006-08-10 05:45:44 +0000107 return;
108
109 case tok::kw_goto: // C99 6.8.6.1: goto-statement
110 ParseGotoStatement();
111 SemiError = "goto statement";
Chris Lattner9075bd72006-08-10 04:59:57 +0000112 break;
Chris Lattner503fadc2006-08-10 05:45:44 +0000113 case tok::kw_continue: // C99 6.8.6.2: continue-statement
114 ConsumeToken(); // eat the 'continue'.
115 SemiError = "continue statement";
116 break;
117 case tok::kw_break: // C99 6.8.6.3: break-statement
118 ConsumeToken(); // eat the 'break'.
119 SemiError = "break statement";
120 break;
121 case tok::kw_return: // C99 6.8.6.4: return-statement
122 ParseReturnStatement();
123 SemiError = "return statement";
124 break;
125
Chris Lattnerc951dae2006-08-10 04:23:57 +0000126 // TODO: Handle OnlyStatement..
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000127 }
Chris Lattner503fadc2006-08-10 05:45:44 +0000128
129 // If we reached this code, the statement must end in a semicolon.
130 if (Tok.getKind() == tok::semi) {
131 ConsumeToken();
132 } else {
133 Diag(Tok, diag::err_expected_semi_after, SemiError);
134 SkipUntil(tok::semi);
135 }
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000136}
137
138/// ParseCompoundStatement - Parse a "{}" block.
139///
140/// compound-statement: [C99 6.8.2]
141/// { block-item-list[opt] }
142/// [GNU] { label-declarations block-item-list } [TODO]
143///
144/// block-item-list:
145/// block-item
146/// block-item-list block-item
147///
148/// block-item:
149/// declaration
150/// [GNU] '__extension__' declaration [TODO]
151/// statement
152/// [OMP] openmp-directive [TODO]
153///
154/// [GNU] label-declarations:
155/// [GNU] label-declaration
156/// [GNU] label-declarations label-declaration
157///
158/// [GNU] label-declaration:
159/// [GNU] '__label__' identifier-list ';'
160///
161/// [OMP] openmp-directive: [TODO]
162/// [OMP] barrier-directive
163/// [OMP] flush-directive
164void Parser::ParseCompoundStatement() {
165 assert(Tok.getKind() == tok::l_brace && "Not a compount stmt!");
166 ConsumeBrace(); // eat the '{'.
167
168 while (Tok.getKind() != tok::r_brace && Tok.getKind() != tok::eof)
Chris Lattnerc951dae2006-08-10 04:23:57 +0000169 ParseStatementOrDeclaration(false);
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000170
171 // We broke out of the while loop because we found a '}' or EOF.
172 if (Tok.getKind() == tok::r_brace)
173 ConsumeBrace();
174 else
175 Diag(Tok, diag::err_expected_rbrace);
176}
Chris Lattnerc951dae2006-08-10 04:23:57 +0000177
178/// ParseIfStatement
179/// if-statement: [C99 6.8.4.1]
180/// 'if' '(' expression ')' statement
181/// 'if' '(' expression ')' statement 'else' statement
182void Parser::ParseIfStatement() {
183 assert(Tok.getKind() == tok::kw_if && "Not an if stmt!");
184 ConsumeToken(); // eat the 'if'.
185
186 if (Tok.getKind() != tok::l_paren) {
Chris Lattner9075bd72006-08-10 04:59:57 +0000187 Diag(Tok, diag::err_expected_lparen_after, "if");
Chris Lattnerc951dae2006-08-10 04:23:57 +0000188 SkipUntil(tok::semi);
189 return;
190 }
191
192 // Parse the condition.
193 ParseParenExpression();
194
195 // Read the if condition.
196 ParseStatement();
197
198 // If it has an else, parse it.
199 if (Tok.getKind() == tok::kw_else) {
200 ConsumeToken();
201 ParseStatement();
202 }
Chris Lattnerc951dae2006-08-10 04:23:57 +0000203}
204
Chris Lattner9075bd72006-08-10 04:59:57 +0000205/// ParseSwitchStatement
206/// switch-statement:
207/// 'switch' '(' expression ')' statement
208void Parser::ParseSwitchStatement() {
209 assert(Tok.getKind() == tok::kw_switch && "Not a switch stmt!");
210 ConsumeToken(); // eat the 'switch'.
211
212 if (Tok.getKind() != tok::l_paren) {
213 Diag(Tok, diag::err_expected_lparen_after, "switch");
214 SkipUntil(tok::semi);
215 return;
216 }
217
218 // Parse the condition.
219 ParseParenExpression();
220
221 // Read the body statement.
222 ParseStatement();
223}
224
225/// ParseWhileStatement
226/// while-statement: [C99 6.8.5.1]
227/// 'while' '(' expression ')' statement
228void Parser::ParseWhileStatement() {
229 assert(Tok.getKind() == tok::kw_while && "Not a while stmt!");
230 ConsumeToken(); // eat the 'while'.
231
232 if (Tok.getKind() != tok::l_paren) {
233 Diag(Tok, diag::err_expected_lparen_after, "while");
234 SkipUntil(tok::semi);
235 return;
236 }
237
238 // Parse the condition.
239 ParseParenExpression();
240
241 // Read the body statement.
242 ParseStatement();
243}
244
245/// ParseDoStatement
246/// do-statement: [C99 6.8.5.2]
247/// 'do' statement 'while' '(' expression ')' ';'
Chris Lattner503fadc2006-08-10 05:45:44 +0000248/// Note: this lets the caller parse the end ';'.
Chris Lattner9075bd72006-08-10 04:59:57 +0000249void Parser::ParseDoStatement() {
250 assert(Tok.getKind() == tok::kw_do && "Not a do stmt!");
251 SourceLocation DoLoc = Tok.getLocation();
252 ConsumeToken(); // eat the 'do'.
253
254 // Read the body statement.
255 ParseStatement();
256
257 if (Tok.getKind() != tok::kw_while) {
258 Diag(Tok, diag::err_expected_while);
259 Diag(DoLoc, diag::err_matching);
260 SkipUntil(tok::semi);
261 return;
262 }
263 ConsumeToken();
264
265 if (Tok.getKind() != tok::l_paren) {
266 Diag(Tok, diag::err_expected_lparen_after, "do/while");
267 SkipUntil(tok::semi);
268 return;
269 }
270
271 // Parse the condition.
272 ParseParenExpression();
Chris Lattner9075bd72006-08-10 04:59:57 +0000273}
274
275/// ParseForStatement
276/// for-statement: [C99 6.8.5.3]
277/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
278/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
279void Parser::ParseForStatement() {
280 assert(Tok.getKind() == tok::kw_for && "Not a for stmt!");
281 SourceLocation ForLoc = Tok.getLocation();
282 ConsumeToken(); // eat the 'for'.
283
284 if (Tok.getKind() != tok::l_paren) {
285 Diag(Tok, diag::err_expected_lparen_after, "for");
286 SkipUntil(tok::semi);
287 return;
288 }
289
290 SourceLocation LParenLoc = Tok.getLocation();
291 ConsumeParen();
292
293 // Parse the first part of the for specifier.
294 if (Tok.getKind() == tok::semi) { // for (;
Chris Lattner53361ac2006-08-10 05:19:57 +0000295 // no first part, eat the ';'.
296 ConsumeToken();
Chris Lattner9075bd72006-08-10 04:59:57 +0000297 } else if (isDeclarationSpecifier()) { // for (int X = 4;
Chris Lattner53361ac2006-08-10 05:19:57 +0000298 // Parse declaration, which eats the ';'.
Chris Lattnerab1803652006-08-10 05:22:36 +0000299 if (!getLang().C99) // Use of C99-style for loops in C90 mode?
300 Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
Chris Lattner53361ac2006-08-10 05:19:57 +0000301 ParseDeclaration(Declarator::ForContext);
Chris Lattner9075bd72006-08-10 04:59:57 +0000302 } else {
303 ParseExpression();
Chris Lattner9075bd72006-08-10 04:59:57 +0000304
Chris Lattner53361ac2006-08-10 05:19:57 +0000305 if (Tok.getKind() == tok::semi) {
306 ConsumeToken();
307 } else {
308 Diag(Tok, diag::err_expected_semi_for);
309 Diag(ForLoc, diag::err_matching);
310 SkipUntil(tok::semi);
311 }
Chris Lattner9075bd72006-08-10 04:59:57 +0000312 }
313
314 // Parse the second part of the for specifier.
315 if (Tok.getKind() == tok::semi) { // for (...;;
316 // no second part.
317 } else {
318 ParseExpression();
319 }
320
321 if (Tok.getKind() == tok::semi) {
322 ConsumeToken();
323 } else {
324 Diag(Tok, diag::err_expected_semi_for);
325 Diag(ForLoc, diag::err_matching);
326 SkipUntil(tok::semi);
327 }
328
329 // Parse the third part of the for specifier.
330 if (Tok.getKind() == tok::r_paren) { // for (...;...;)
331 // no third part.
332 } else {
333 ParseExpression();
334 }
335
336 if (Tok.getKind() == tok::r_paren) {
337 ConsumeParen();
338 } else {
339 Diag(Tok, diag::err_expected_rparen);
340 Diag(LParenLoc, diag::err_matching);
341 SkipUntil(tok::r_paren);
342 return;
343 }
344
345 // Read the body statement.
346 ParseStatement();
347}
Chris Lattnerc951dae2006-08-10 04:23:57 +0000348
Chris Lattner503fadc2006-08-10 05:45:44 +0000349/// ParseGotoStatement
350/// jump-statement:
351/// 'goto' identifier ';'
352/// [GNU] 'goto' '*' expression ';'
353///
354/// Note: this lets the caller parse the end ';'.
355///
356void Parser::ParseGotoStatement() {
357 assert(Tok.getKind() == tok::kw_goto && "Not a goto stmt!");
358 ConsumeToken(); // eat the 'goto'.
359
360 if (Tok.getKind() == tok::identifier) {
361 ConsumeToken();
362 } else if (Tok.getKind() == tok::star && !getLang().NoExtensions) {
363 // GNU indirect goto extension.
364 Diag(Tok, diag::ext_gnu_indirect_goto);
365 ConsumeToken();
366 ParseExpression();
367 }
368}
369
370/// ParseReturnStatement
371/// jump-statement:
372/// 'return' expression[opt] ';'
373void Parser::ParseReturnStatement() {
374 assert(Tok.getKind() == tok::kw_return && "Not a return stmt!");
375 ConsumeToken(); // eat the 'return'.
376
377 if (Tok.getKind() != tok::semi)
378 ParseExpression();
379}