blob: c800ad0e1ff444ee338cf3c191371f32f546947f [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] ';'
65/// [GNU] 'goto' '*' expression ';' [TODO]
66///
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 Lattner0ccd51e2006-08-09 05:47:47 +000072 switch (Tok.getKind()) {
73 default:
74 Diag(Tok, diag::err_expected_statement_declaration);
75 SkipUntil(tok::semi);
76 break;
77
Chris Lattner9075bd72006-08-10 04:59:57 +000078
79 case tok::l_brace: // C99 6.8.2: compound-statement
Chris Lattner0ccd51e2006-08-09 05:47:47 +000080 ParseCompoundStatement();
81 break;
Chris Lattner9075bd72006-08-10 04:59:57 +000082 case tok::semi: // C99 6.8.3: expression[opt] ';'
Chris Lattnerc951dae2006-08-10 04:23:57 +000083 ConsumeToken();
84 break;
Chris Lattner9075bd72006-08-10 04:59:57 +000085 case tok::kw_if: // C99 6.8.4.1: if-statement
Chris Lattnerc951dae2006-08-10 04:23:57 +000086 ParseIfStatement();
87 break;
Chris Lattner9075bd72006-08-10 04:59:57 +000088 case tok::kw_switch: // C99 6.8.4.2: switch-statement
89 ParseSwitchStatement();
90 break;
91 case tok::kw_while: // C99 6.8.5.1: while-statement
92 ParseWhileStatement();
93 break;
94 case tok::kw_do: // C99 6.8.5.2: do-statement
95 ParseDoStatement();
96 break;
97 case tok::kw_for: // C99 6.8.5.3: for-statement
98 ParseForStatement();
99 break;
Chris Lattnerc951dae2006-08-10 04:23:57 +0000100 // TODO: Handle OnlyStatement..
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000101 }
102}
103
104/// ParseCompoundStatement - Parse a "{}" block.
105///
106/// compound-statement: [C99 6.8.2]
107/// { block-item-list[opt] }
108/// [GNU] { label-declarations block-item-list } [TODO]
109///
110/// block-item-list:
111/// block-item
112/// block-item-list block-item
113///
114/// block-item:
115/// declaration
116/// [GNU] '__extension__' declaration [TODO]
117/// statement
118/// [OMP] openmp-directive [TODO]
119///
120/// [GNU] label-declarations:
121/// [GNU] label-declaration
122/// [GNU] label-declarations label-declaration
123///
124/// [GNU] label-declaration:
125/// [GNU] '__label__' identifier-list ';'
126///
127/// [OMP] openmp-directive: [TODO]
128/// [OMP] barrier-directive
129/// [OMP] flush-directive
130void Parser::ParseCompoundStatement() {
131 assert(Tok.getKind() == tok::l_brace && "Not a compount stmt!");
132 ConsumeBrace(); // eat the '{'.
133
134 while (Tok.getKind() != tok::r_brace && Tok.getKind() != tok::eof)
Chris Lattnerc951dae2006-08-10 04:23:57 +0000135 ParseStatementOrDeclaration(false);
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000136
137 // We broke out of the while loop because we found a '}' or EOF.
138 if (Tok.getKind() == tok::r_brace)
139 ConsumeBrace();
140 else
141 Diag(Tok, diag::err_expected_rbrace);
142}
Chris Lattnerc951dae2006-08-10 04:23:57 +0000143
144/// ParseIfStatement
145/// if-statement: [C99 6.8.4.1]
146/// 'if' '(' expression ')' statement
147/// 'if' '(' expression ')' statement 'else' statement
148void Parser::ParseIfStatement() {
149 assert(Tok.getKind() == tok::kw_if && "Not an if stmt!");
150 ConsumeToken(); // eat the 'if'.
151
152 if (Tok.getKind() != tok::l_paren) {
Chris Lattner9075bd72006-08-10 04:59:57 +0000153 Diag(Tok, diag::err_expected_lparen_after, "if");
Chris Lattnerc951dae2006-08-10 04:23:57 +0000154 SkipUntil(tok::semi);
155 return;
156 }
157
158 // Parse the condition.
159 ParseParenExpression();
160
161 // Read the if condition.
162 ParseStatement();
163
164 // If it has an else, parse it.
165 if (Tok.getKind() == tok::kw_else) {
166 ConsumeToken();
167 ParseStatement();
168 }
Chris Lattnerc951dae2006-08-10 04:23:57 +0000169}
170
Chris Lattner9075bd72006-08-10 04:59:57 +0000171/// ParseSwitchStatement
172/// switch-statement:
173/// 'switch' '(' expression ')' statement
174void Parser::ParseSwitchStatement() {
175 assert(Tok.getKind() == tok::kw_switch && "Not a switch stmt!");
176 ConsumeToken(); // eat the 'switch'.
177
178 if (Tok.getKind() != tok::l_paren) {
179 Diag(Tok, diag::err_expected_lparen_after, "switch");
180 SkipUntil(tok::semi);
181 return;
182 }
183
184 // Parse the condition.
185 ParseParenExpression();
186
187 // Read the body statement.
188 ParseStatement();
189}
190
191/// ParseWhileStatement
192/// while-statement: [C99 6.8.5.1]
193/// 'while' '(' expression ')' statement
194void Parser::ParseWhileStatement() {
195 assert(Tok.getKind() == tok::kw_while && "Not a while stmt!");
196 ConsumeToken(); // eat the 'while'.
197
198 if (Tok.getKind() != tok::l_paren) {
199 Diag(Tok, diag::err_expected_lparen_after, "while");
200 SkipUntil(tok::semi);
201 return;
202 }
203
204 // Parse the condition.
205 ParseParenExpression();
206
207 // Read the body statement.
208 ParseStatement();
209}
210
211/// ParseDoStatement
212/// do-statement: [C99 6.8.5.2]
213/// 'do' statement 'while' '(' expression ')' ';'
214void Parser::ParseDoStatement() {
215 assert(Tok.getKind() == tok::kw_do && "Not a do stmt!");
216 SourceLocation DoLoc = Tok.getLocation();
217 ConsumeToken(); // eat the 'do'.
218
219 // Read the body statement.
220 ParseStatement();
221
222 if (Tok.getKind() != tok::kw_while) {
223 Diag(Tok, diag::err_expected_while);
224 Diag(DoLoc, diag::err_matching);
225 SkipUntil(tok::semi);
226 return;
227 }
228 ConsumeToken();
229
230 if (Tok.getKind() != tok::l_paren) {
231 Diag(Tok, diag::err_expected_lparen_after, "do/while");
232 SkipUntil(tok::semi);
233 return;
234 }
235
236 // Parse the condition.
237 ParseParenExpression();
238
239 if (Tok.getKind() != tok::semi) {
240 Diag(Tok, diag::err_expected_semi_do_while);
241 SkipUntil(tok::semi);
242 return;
243 }
244}
245
246/// ParseForStatement
247/// for-statement: [C99 6.8.5.3]
248/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
249/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
250void Parser::ParseForStatement() {
251 assert(Tok.getKind() == tok::kw_for && "Not a for stmt!");
252 SourceLocation ForLoc = Tok.getLocation();
253 ConsumeToken(); // eat the 'for'.
254
255 if (Tok.getKind() != tok::l_paren) {
256 Diag(Tok, diag::err_expected_lparen_after, "for");
257 SkipUntil(tok::semi);
258 return;
259 }
260
261 SourceLocation LParenLoc = Tok.getLocation();
262 ConsumeParen();
263
264 // Parse the first part of the for specifier.
265 if (Tok.getKind() == tok::semi) { // for (;
Chris Lattner53361ac2006-08-10 05:19:57 +0000266 // no first part, eat the ';'.
267 ConsumeToken();
Chris Lattner9075bd72006-08-10 04:59:57 +0000268 } else if (isDeclarationSpecifier()) { // for (int X = 4;
Chris Lattner53361ac2006-08-10 05:19:57 +0000269 // Parse declaration, which eats the ';'.
Chris Lattnerab1803652006-08-10 05:22:36 +0000270 if (!getLang().C99) // Use of C99-style for loops in C90 mode?
271 Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
Chris Lattner53361ac2006-08-10 05:19:57 +0000272 ParseDeclaration(Declarator::ForContext);
Chris Lattner9075bd72006-08-10 04:59:57 +0000273 } else {
274 ParseExpression();
Chris Lattner9075bd72006-08-10 04:59:57 +0000275
Chris Lattner53361ac2006-08-10 05:19:57 +0000276 if (Tok.getKind() == tok::semi) {
277 ConsumeToken();
278 } else {
279 Diag(Tok, diag::err_expected_semi_for);
280 Diag(ForLoc, diag::err_matching);
281 SkipUntil(tok::semi);
282 }
Chris Lattner9075bd72006-08-10 04:59:57 +0000283 }
284
285 // Parse the second part of the for specifier.
286 if (Tok.getKind() == tok::semi) { // for (...;;
287 // no second part.
288 } else {
289 ParseExpression();
290 }
291
292 if (Tok.getKind() == tok::semi) {
293 ConsumeToken();
294 } else {
295 Diag(Tok, diag::err_expected_semi_for);
296 Diag(ForLoc, diag::err_matching);
297 SkipUntil(tok::semi);
298 }
299
300 // Parse the third part of the for specifier.
301 if (Tok.getKind() == tok::r_paren) { // for (...;...;)
302 // no third part.
303 } else {
304 ParseExpression();
305 }
306
307 if (Tok.getKind() == tok::r_paren) {
308 ConsumeParen();
309 } else {
310 Diag(Tok, diag::err_expected_rparen);
311 Diag(LParenLoc, diag::err_matching);
312 SkipUntil(tok::r_paren);
313 return;
314 }
315
316 // Read the body statement.
317 ParseStatement();
318}
Chris Lattnerc951dae2006-08-10 04:23:57 +0000319