blob: b469dc687262f8efa4923ea501425e8ef9e51e87 [file] [log] [blame]
Chris Lattnereb8a28f2006-08-10 18:43:39 +00001//===--- Parser.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 Lattner4564bc12006-08-10 23:14:52 +000039/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
40/// this helper function matches and consumes the specified RHS token if
41/// present. If not present, it emits the specified diagnostic indicating
42/// that the parser failed to match the RHS of the token at LHSLoc. LHSName
43/// should be the name of the unmatched LHS token.
44void Parser::MatchRHSPunctuation(tok::TokenKind RHSTok, SourceLocation LHSLoc,
45 const char *LHSName, unsigned DiagID) {
46
47 if (Tok.getKind() == RHSTok) {
48 if (isTokenParen())
49 ConsumeParen();
50 else if (isTokenBracket())
51 ConsumeBracket();
52 else if (isTokenBrace())
53 ConsumeBrace();
54 else
55 ConsumeParen();
56 } else {
57 Diag(Tok, DiagID);
58 Diag(LHSLoc, diag::err_matching, LHSName);
59 SkipUntil(RHSTok);
60 }
61}
62
Chris Lattner70f32b72006-07-31 05:09:04 +000063//===----------------------------------------------------------------------===//
Chris Lattnereec40f92006-08-06 21:55:29 +000064// Error recovery.
65//===----------------------------------------------------------------------===//
66
67/// SkipUntil - Read tokens until we get to the specified token, then consume
68/// it (unless DontConsume is false). Because we cannot guarantee that the
69/// token will ever occur, this skips to the next token, or to some likely
70/// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
71/// character.
72///
73/// If SkipUntil finds the specified token, it returns true, otherwise it
74/// returns false.
75bool Parser::SkipUntil(tok::TokenKind T, bool StopAtSemi, bool DontConsume) {
76 while (1) {
77 // If we found the token, stop and return true.
78 if (Tok.getKind() == T) {
79 if (DontConsume) {
80 // Noop, don't consume the token.
81 } else if (isTokenParen()) {
82 ConsumeParen();
83 } else if (isTokenBracket()) {
84 ConsumeBracket();
85 } else if (isTokenBrace()) {
86 ConsumeBrace();
87 } else if (T == tok::string_literal) {
88 ConsumeStringToken();
89 } else {
90 ConsumeToken();
91 }
92 return true;
93 }
94
95 switch (Tok.getKind()) {
96 case tok::eof:
97 // Ran out of tokens.
98 return false;
99
100 case tok::l_paren:
101 // Recursively skip properly-nested parens.
102 ConsumeParen();
103 SkipUntil(tok::r_paren);
104 break;
105 case tok::l_square:
106 // Recursively skip properly-nested square brackets.
107 ConsumeBracket();
108 SkipUntil(tok::r_square);
109 break;
110 case tok::l_brace:
111 // Recursively skip properly-nested braces.
112 ConsumeBrace();
113 SkipUntil(tok::r_brace);
114 break;
115
116 // Okay, we found a ']' or '}' or ')', which we think should be balanced.
117 // Since the user wasn't looking for this token (if they were, it would
118 // already be handled), this isn't balanced. If there is a LHS token at a
119 // higher level, we will assume that this matches the unbalanced token
120 // and return it. Otherwise, this is a spurious RHS token, which we skip.
121 case tok::r_paren:
122 if (ParenCount) return false; // Matches something.
123 ConsumeParen();
124 break;
125 case tok::r_square:
126 if (BracketCount) return false; // Matches something.
127 ConsumeBracket();
128 break;
129 case tok::r_brace:
130 if (BraceCount) return false; // Matches something.
131 ConsumeBrace();
132 break;
133
134 case tok::string_literal:
135 ConsumeStringToken();
136 break;
137 case tok::semi:
138 if (StopAtSemi)
139 return false;
140 // FALL THROUGH.
141 default:
142 // Skip this token.
143 ConsumeToken();
144 break;
145 }
146 }
147}
148
149//===----------------------------------------------------------------------===//
Chris Lattner70f32b72006-07-31 05:09:04 +0000150// C99 6.9: External Definitions.
151//===----------------------------------------------------------------------===//
Chris Lattner0bb5f832006-07-31 01:59:18 +0000152
153/// ParseTranslationUnit:
Chris Lattner70f32b72006-07-31 05:09:04 +0000154/// translation-unit: [C99 6.9]
Chris Lattner0bb5f832006-07-31 01:59:18 +0000155/// external-declaration
156/// translation-unit external-declaration
157void Parser::ParseTranslationUnit() {
158
159 if (Tok.getKind() == tok::eof) // Empty source file is an extension.
160 Diag(diag::ext_empty_source_file);
161
162 while (Tok.getKind() != tok::eof)
163 ParseExternalDeclaration();
164}
165
166/// ParseExternalDeclaration:
Chris Lattner70f32b72006-07-31 05:09:04 +0000167/// external-declaration: [C99 6.9]
Chris Lattner0bb5f832006-07-31 01:59:18 +0000168/// function-definition [TODO]
169/// declaration [TODO]
170/// [EXT] ';'
171/// [GNU] asm-definition [TODO]
172/// [GNU] __extension__ external-declaration [TODO]
173/// [OBJC] objc-class-definition [TODO]
174/// [OBJC] objc-class-declaration [TODO]
175/// [OBJC] objc-alias-declaration [TODO]
176/// [OBJC] objc-protocol-definition [TODO]
177/// [OBJC] objc-method-definition [TODO]
178/// [OBJC] @end [TODO]
179///
180void Parser::ParseExternalDeclaration() {
181 switch (Tok.getKind()) {
182 case tok::semi:
183 Diag(diag::ext_top_level_semi);
184 ConsumeToken();
185 break;
186 default:
187 // We can't tell whether this is a function-definition or declaration yet.
188 ParseDeclarationOrFunctionDefinition();
189 break;
190 }
191}
192
193/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
Chris Lattner70f32b72006-07-31 05:09:04 +0000194/// a declaration. We can't tell which we have until we read up to the
195/// compound-statement in function-definition.
Chris Lattner0bb5f832006-07-31 01:59:18 +0000196///
Chris Lattner70f32b72006-07-31 05:09:04 +0000197/// function-definition: [C99 6.9.1]
198/// declaration-specifiers[opt] declarator declaration-list[opt]
199/// compound-statement [TODO]
200/// declaration: [C99 6.7]
Chris Lattner0bb5f832006-07-31 01:59:18 +0000201/// declaration-specifiers init-declarator-list[opt] ';' [TODO]
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000202/// [!C99] init-declarator-list ';' [TODO]
Chris Lattner70f32b72006-07-31 05:09:04 +0000203/// [OMP] threadprivate-directive [TODO]
204///
205/// init-declarator-list: [C99 6.7]
206/// init-declarator
207/// init-declarator-list ',' init-declarator
208/// init-declarator: [C99 6.7]
209/// declarator
210/// declarator '=' initializer
211///
Chris Lattner0bb5f832006-07-31 01:59:18 +0000212void Parser::ParseDeclarationOrFunctionDefinition() {
Chris Lattner70f32b72006-07-31 05:09:04 +0000213 // Parse the common declaration-specifiers piece.
Chris Lattnerb9093cd2006-08-04 04:39:53 +0000214 DeclSpec DS;
215 ParseDeclarationSpecifiers(DS);
Chris Lattnerd2864882006-08-05 08:09:44 +0000216
217 // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
Chris Lattner53361ac2006-08-10 05:19:57 +0000218 // declaration-specifiers init-declarator-list[opt] ';'
Chris Lattnerd2864882006-08-05 08:09:44 +0000219 if (Tok.getKind() == tok::semi)
220 assert(0 && "Unimp!");
221
Chris Lattner70f32b72006-07-31 05:09:04 +0000222
Chris Lattnerfff824f2006-08-07 06:31:38 +0000223 // Parse the first declarator.
224 Declarator DeclaratorInfo(DS, Declarator::FileContext);
225 ParseDeclarator(DeclaratorInfo);
226 // Error parsing the declarator?
227 if (DeclaratorInfo.getIdentifier() == 0) {
228 // If so, skip until the semi-colon or a }.
229 SkipUntil(tok::r_brace, true);
230 if (Tok.getKind() == tok::semi)
231 ConsumeToken();
232 return;
233 }
Chris Lattner70f32b72006-07-31 05:09:04 +0000234
Chris Lattnerfff824f2006-08-07 06:31:38 +0000235 // If the declarator is the start of a function definition, handle it.
236 if (Tok.getKind() == tok::equal || // int X()= -> not a function def
237 Tok.getKind() == tok::comma || // int X(), -> not a function def
238 Tok.getKind() == tok::semi || // int X(); -> not a function def
239 Tok.getKind() == tok::kw_asm || // int X() __asm__ -> not a fn def
240 Tok.getKind() == tok::kw___attribute) {// int X() __attr__ -> not a fn def
241 // FALL THROUGH.
242 } else if (DeclaratorInfo.isInnermostFunctionType() &&
243 (Tok.getKind() == tok::l_brace || // int X() {}
244 isDeclarationSpecifier())) { // int X(f) int f; {}
245 ParseFunctionDefinition(DeclaratorInfo);
246 return;
247 } else {
248 if (DeclaratorInfo.isInnermostFunctionType())
249 Diag(Tok, diag::err_expected_fn_body);
250 else
251 Diag(Tok, diag::err_expected_after_declarator);
252 SkipUntil(tok::r_brace, true);
253 if (Tok.getKind() == tok::semi)
254 ConsumeToken();
255 return;
256 }
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000257
Chris Lattner53361ac2006-08-10 05:19:57 +0000258 // Parse the init-declarator-list for a normal declaration.
259 ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
Chris Lattner70f32b72006-07-31 05:09:04 +0000260}
261
Chris Lattnerfff824f2006-08-07 06:31:38 +0000262/// ParseFunctionDefinition - We parsed and verified that the specified
263/// Declarator is well formed. If this is a K&R-style function, read the
264/// parameters declaration-list, then start the compound-statement.
265///
266/// declaration-specifiers[opt] declarator declaration-list[opt]
267/// compound-statement [TODO]
268///
269void Parser::ParseFunctionDefinition(Declarator &D) {
270 const DeclaratorTypeInfo &FnTypeInfo = D.getTypeObject(0);
271 assert(FnTypeInfo.Kind == DeclaratorTypeInfo::Function &&
272 "This isn't a function declarator!");
273
274 // If this declaration was formed with a K&R-style identifier list for the
275 // arguments, parse declarations for all of the args next.
276 // int foo(a,b) int a; float b; {}
277 if (!FnTypeInfo.Fun.hasPrototype && !FnTypeInfo.Fun.isEmpty) {
278 // Read all the argument declarations.
Chris Lattner53361ac2006-08-10 05:19:57 +0000279 while (isDeclarationSpecifier())
280 ParseDeclaration(Declarator::KNRTypeListContext);
Chris Lattnerfff824f2006-08-07 06:31:38 +0000281
282 // Note, check that we got them all.
283 } else {
284 //if (isDeclarationSpecifier())
285 // Diag('k&r declspecs with prototype?');
286
287 // FIXME: Install the arguments into the current scope.
288 }
289
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000290 // We should have an opening brace now.
291 if (Tok.getKind() != tok::l_brace) {
292 Diag(Tok, diag::err_expected_fn_body);
293
294 // Skip over garbage, until we get to '{'. Don't eat the '{'.
295 SkipUntil(tok::l_brace, true, true);
296
297 // If we didn't find the '{', bail out.
298 if (Tok.getKind() != tok::l_brace)
299 return;
300 }
Chris Lattnerfff824f2006-08-07 06:31:38 +0000301
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000302 ParseCompoundStatement();
Chris Lattnerfff824f2006-08-07 06:31:38 +0000303}
304