blob: 38ece5391374c715165600372a8a62d0cdd8b5e8 [file] [log] [blame]
Chris Lattnerb9093cd2006-08-04 04:39:53 +00001//===--- Parse.cpp - C Language Family Parser -----------------------------===//
Chris Lattner0bb5f832006-07-31 01:59:18 +00002//
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 Parser interfaces.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Parse/Parser.h"
Chris Lattnerb9093cd2006-08-04 04:39:53 +000015#include "clang/Parse/Declarations.h"
Chris Lattner971c6b62006-08-05 22:46:42 +000016#include "clang/Parse/Scope.h"
Chris Lattner0bb5f832006-07-31 01:59:18 +000017using namespace llvm;
18using namespace clang;
19
20Parser::Parser(Preprocessor &pp, ParserActions &actions)
Chris Lattner971c6b62006-08-05 22:46:42 +000021 : PP(pp), Actions(actions), Diags(PP.getDiagnostics()) {
22 // Create the global scope, install it as the current scope.
23 CurScope = new Scope(0);
Chris Lattneracd58a32006-08-06 17:24:14 +000024 Tok.SetKind(tok::eof);
Chris Lattnereec40f92006-08-06 21:55:29 +000025
26 ParenCount = BracketCount = BraceCount = 0;
Chris Lattner971c6b62006-08-05 22:46:42 +000027}
28
29Parser::~Parser() {
30 delete CurScope;
31}
32
Chris Lattner0bb5f832006-07-31 01:59:18 +000033
Chris Lattnerb9093cd2006-08-04 04:39:53 +000034void Parser::Diag(SourceLocation Loc, unsigned DiagID,
Chris Lattner0bb5f832006-07-31 01:59:18 +000035 const std::string &Msg) {
Chris Lattnerb9093cd2006-08-04 04:39:53 +000036 Diags.Report(Loc, DiagID, Msg);
Chris Lattner0bb5f832006-07-31 01:59:18 +000037}
38
Chris Lattner70f32b72006-07-31 05:09:04 +000039//===----------------------------------------------------------------------===//
Chris Lattnereec40f92006-08-06 21:55:29 +000040// Error recovery.
41//===----------------------------------------------------------------------===//
42
43/// SkipUntil - Read tokens until we get to the specified token, then consume
44/// it (unless DontConsume is false). Because we cannot guarantee that the
45/// token will ever occur, this skips to the next token, or to some likely
46/// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
47/// character.
48///
49/// If SkipUntil finds the specified token, it returns true, otherwise it
50/// returns false.
51bool Parser::SkipUntil(tok::TokenKind T, bool StopAtSemi, bool DontConsume) {
52 while (1) {
53 // If we found the token, stop and return true.
54 if (Tok.getKind() == T) {
55 if (DontConsume) {
56 // Noop, don't consume the token.
57 } else if (isTokenParen()) {
58 ConsumeParen();
59 } else if (isTokenBracket()) {
60 ConsumeBracket();
61 } else if (isTokenBrace()) {
62 ConsumeBrace();
63 } else if (T == tok::string_literal) {
64 ConsumeStringToken();
65 } else {
66 ConsumeToken();
67 }
68 return true;
69 }
70
71 switch (Tok.getKind()) {
72 case tok::eof:
73 // Ran out of tokens.
74 return false;
75
76 case tok::l_paren:
77 // Recursively skip properly-nested parens.
78 ConsumeParen();
79 SkipUntil(tok::r_paren);
80 break;
81 case tok::l_square:
82 // Recursively skip properly-nested square brackets.
83 ConsumeBracket();
84 SkipUntil(tok::r_square);
85 break;
86 case tok::l_brace:
87 // Recursively skip properly-nested braces.
88 ConsumeBrace();
89 SkipUntil(tok::r_brace);
90 break;
91
92 // Okay, we found a ']' or '}' or ')', which we think should be balanced.
93 // Since the user wasn't looking for this token (if they were, it would
94 // already be handled), this isn't balanced. If there is a LHS token at a
95 // higher level, we will assume that this matches the unbalanced token
96 // and return it. Otherwise, this is a spurious RHS token, which we skip.
97 case tok::r_paren:
98 if (ParenCount) return false; // Matches something.
99 ConsumeParen();
100 break;
101 case tok::r_square:
102 if (BracketCount) return false; // Matches something.
103 ConsumeBracket();
104 break;
105 case tok::r_brace:
106 if (BraceCount) return false; // Matches something.
107 ConsumeBrace();
108 break;
109
110 case tok::string_literal:
111 ConsumeStringToken();
112 break;
113 case tok::semi:
114 if (StopAtSemi)
115 return false;
116 // FALL THROUGH.
117 default:
118 // Skip this token.
119 ConsumeToken();
120 break;
121 }
122 }
123}
124
125//===----------------------------------------------------------------------===//
Chris Lattner70f32b72006-07-31 05:09:04 +0000126// C99 6.9: External Definitions.
127//===----------------------------------------------------------------------===//
Chris Lattner0bb5f832006-07-31 01:59:18 +0000128
129/// ParseTranslationUnit:
Chris Lattner70f32b72006-07-31 05:09:04 +0000130/// translation-unit: [C99 6.9]
Chris Lattner0bb5f832006-07-31 01:59:18 +0000131/// external-declaration
132/// translation-unit external-declaration
133void Parser::ParseTranslationUnit() {
134
135 if (Tok.getKind() == tok::eof) // Empty source file is an extension.
136 Diag(diag::ext_empty_source_file);
137
138 while (Tok.getKind() != tok::eof)
139 ParseExternalDeclaration();
140}
141
142/// ParseExternalDeclaration:
Chris Lattner70f32b72006-07-31 05:09:04 +0000143/// external-declaration: [C99 6.9]
Chris Lattner0bb5f832006-07-31 01:59:18 +0000144/// function-definition [TODO]
145/// declaration [TODO]
146/// [EXT] ';'
147/// [GNU] asm-definition [TODO]
148/// [GNU] __extension__ external-declaration [TODO]
149/// [OBJC] objc-class-definition [TODO]
150/// [OBJC] objc-class-declaration [TODO]
151/// [OBJC] objc-alias-declaration [TODO]
152/// [OBJC] objc-protocol-definition [TODO]
153/// [OBJC] objc-method-definition [TODO]
154/// [OBJC] @end [TODO]
155///
156void Parser::ParseExternalDeclaration() {
157 switch (Tok.getKind()) {
158 case tok::semi:
159 Diag(diag::ext_top_level_semi);
160 ConsumeToken();
161 break;
162 default:
163 // We can't tell whether this is a function-definition or declaration yet.
164 ParseDeclarationOrFunctionDefinition();
165 break;
166 }
167}
168
169/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
Chris Lattner70f32b72006-07-31 05:09:04 +0000170/// a declaration. We can't tell which we have until we read up to the
171/// compound-statement in function-definition.
Chris Lattner0bb5f832006-07-31 01:59:18 +0000172///
Chris Lattner70f32b72006-07-31 05:09:04 +0000173/// function-definition: [C99 6.9.1]
174/// declaration-specifiers[opt] declarator declaration-list[opt]
175/// compound-statement [TODO]
176/// declaration: [C99 6.7]
Chris Lattner0bb5f832006-07-31 01:59:18 +0000177/// declaration-specifiers init-declarator-list[opt] ';' [TODO]
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000178/// [!C99] init-declarator-list ';' [TODO]
Chris Lattner70f32b72006-07-31 05:09:04 +0000179/// [OMP] threadprivate-directive [TODO]
180///
181/// init-declarator-list: [C99 6.7]
182/// init-declarator
183/// init-declarator-list ',' init-declarator
184/// init-declarator: [C99 6.7]
185/// declarator
186/// declarator '=' initializer
187///
Chris Lattner0bb5f832006-07-31 01:59:18 +0000188void Parser::ParseDeclarationOrFunctionDefinition() {
Chris Lattner70f32b72006-07-31 05:09:04 +0000189 // Parse the common declaration-specifiers piece.
Chris Lattnerb9093cd2006-08-04 04:39:53 +0000190 DeclSpec DS;
191 ParseDeclarationSpecifiers(DS);
Chris Lattnerd2864882006-08-05 08:09:44 +0000192
193 // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
194 if (Tok.getKind() == tok::semi)
195 assert(0 && "Unimp!");
196
Chris Lattner70f32b72006-07-31 05:09:04 +0000197
Chris Lattnerfff824f2006-08-07 06:31:38 +0000198 // Parse the first declarator.
199 Declarator DeclaratorInfo(DS, Declarator::FileContext);
200 ParseDeclarator(DeclaratorInfo);
201 // Error parsing the declarator?
202 if (DeclaratorInfo.getIdentifier() == 0) {
203 // If so, skip until the semi-colon or a }.
204 SkipUntil(tok::r_brace, true);
205 if (Tok.getKind() == tok::semi)
206 ConsumeToken();
207 return;
208 }
Chris Lattner70f32b72006-07-31 05:09:04 +0000209
Chris Lattnerfff824f2006-08-07 06:31:38 +0000210 // If the declarator is the start of a function definition, handle it.
211 if (Tok.getKind() == tok::equal || // int X()= -> not a function def
212 Tok.getKind() == tok::comma || // int X(), -> not a function def
213 Tok.getKind() == tok::semi || // int X(); -> not a function def
214 Tok.getKind() == tok::kw_asm || // int X() __asm__ -> not a fn def
215 Tok.getKind() == tok::kw___attribute) {// int X() __attr__ -> not a fn def
216 // FALL THROUGH.
217 } else if (DeclaratorInfo.isInnermostFunctionType() &&
218 (Tok.getKind() == tok::l_brace || // int X() {}
219 isDeclarationSpecifier())) { // int X(f) int f; {}
220 ParseFunctionDefinition(DeclaratorInfo);
221 return;
222 } else {
223 if (DeclaratorInfo.isInnermostFunctionType())
224 Diag(Tok, diag::err_expected_fn_body);
225 else
226 Diag(Tok, diag::err_expected_after_declarator);
227 SkipUntil(tok::r_brace, true);
228 if (Tok.getKind() == tok::semi)
229 ConsumeToken();
230 return;
231 }
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000232
Chris Lattnerfff824f2006-08-07 06:31:38 +0000233 // At this point, we know that it is not a function definition. Parse the
234 // rest of the init-declarator-list.
235 while (1) {
Chris Lattner15356a72006-08-06 00:02:28 +0000236 // must be: decl-spec[opt] declarator init-declarator-list
237 // Parse declarator '=' initializer.
238 if (Tok.getKind() == tok::equal)
239 assert(0 && "cannot handle initializer yet!");
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000240
Chris Lattnerfff824f2006-08-07 06:31:38 +0000241
242 // TODO: install declarator.
243
244 // If we don't have a comma, it is either the end of the list (a ';') or an
245 // error, bail out.
246 if (Tok.getKind() != tok::comma)
247 break;
248
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000249 // Consume the comma.
250 ConsumeToken();
251
Chris Lattnerfff824f2006-08-07 06:31:38 +0000252 // Parse the next declarator.
253 DeclaratorInfo.clear();
Chris Lattner15356a72006-08-06 00:02:28 +0000254 ParseDeclarator(DeclaratorInfo);
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000255 }
Chris Lattnerd2864882006-08-05 08:09:44 +0000256
257 if (Tok.getKind() == tok::semi) {
Chris Lattner70f32b72006-07-31 05:09:04 +0000258 ConsumeToken();
Chris Lattnerd2864882006-08-05 08:09:44 +0000259 } else {
260 Diag(Tok, diag::err_parse_error);
Chris Lattnereec40f92006-08-06 21:55:29 +0000261 // Skip to end of block or statement
262 SkipUntil(tok::r_brace, true);
Chris Lattnerd2864882006-08-05 08:09:44 +0000263 if (Tok.getKind() == tok::semi)
264 ConsumeToken();
Chris Lattner70f32b72006-07-31 05:09:04 +0000265 }
266}
267
Chris Lattnerfff824f2006-08-07 06:31:38 +0000268/// ParseFunctionDefinition - We parsed and verified that the specified
269/// Declarator is well formed. If this is a K&R-style function, read the
270/// parameters declaration-list, then start the compound-statement.
271///
272/// declaration-specifiers[opt] declarator declaration-list[opt]
273/// compound-statement [TODO]
274///
275void Parser::ParseFunctionDefinition(Declarator &D) {
276 const DeclaratorTypeInfo &FnTypeInfo = D.getTypeObject(0);
277 assert(FnTypeInfo.Kind == DeclaratorTypeInfo::Function &&
278 "This isn't a function declarator!");
279
280 // If this declaration was formed with a K&R-style identifier list for the
281 // arguments, parse declarations for all of the args next.
282 // int foo(a,b) int a; float b; {}
283 if (!FnTypeInfo.Fun.hasPrototype && !FnTypeInfo.Fun.isEmpty) {
284 // Read all the argument declarations.
285 while (isDeclarationSpecifier()) {
286 // Parse the common declaration-specifiers piece.
287 DeclSpec DS;
288 ParseDeclarationSpecifiers(DS);
289
290 Declarator DeclaratorInfo(DS, Declarator::FileContext);
291 ParseDeclarator(DeclaratorInfo);
292
293 while (Tok.getKind() == tok::comma) {
294 // Consume the comma.
295 ConsumeToken();
296
297 // Parse the next declarator.
298 DeclaratorInfo.clear();
299 ParseDeclarator(DeclaratorInfo);
300 }
301
302 if (Tok.getKind() == tok::semi) {
303 ConsumeToken();
304 } else {
305 Diag(Tok, diag::err_expected_semi_knr_fn_body);
306 // Skip to end of block or statement
307 SkipUntil(tok::l_brace, true);
308 if (Tok.getKind() == tok::semi)
309 ConsumeToken();
310 }
311 }
312
313 // Note, check that we got them all.
314 } else {
315 //if (isDeclarationSpecifier())
316 // Diag('k&r declspecs with prototype?');
317
318 // FIXME: Install the arguments into the current scope.
319 }
320
321
322
323}
324