blob: be39120d26504c26a45dc66449c658f3158729e4 [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) {
Chris Lattner5bd57e02006-08-11 06:40:25 +000076 // We always want this function to skip at least one token if the first token
77 // isn't T and if not at EOF.
78 bool isFirstTokenSkipped = true;
Chris Lattnereec40f92006-08-06 21:55:29 +000079 while (1) {
80 // If we found the token, stop and return true.
81 if (Tok.getKind() == T) {
82 if (DontConsume) {
83 // Noop, don't consume the token.
84 } else if (isTokenParen()) {
85 ConsumeParen();
86 } else if (isTokenBracket()) {
87 ConsumeBracket();
88 } else if (isTokenBrace()) {
89 ConsumeBrace();
Chris Lattner5bd57e02006-08-11 06:40:25 +000090 } else if (isTokenStringLiteral()) {
Chris Lattnereec40f92006-08-06 21:55:29 +000091 ConsumeStringToken();
92 } else {
93 ConsumeToken();
94 }
95 return true;
96 }
97
98 switch (Tok.getKind()) {
99 case tok::eof:
100 // Ran out of tokens.
101 return false;
102
103 case tok::l_paren:
104 // Recursively skip properly-nested parens.
105 ConsumeParen();
Chris Lattner5bd57e02006-08-11 06:40:25 +0000106 SkipUntil(tok::r_paren, false);
Chris Lattnereec40f92006-08-06 21:55:29 +0000107 break;
108 case tok::l_square:
109 // Recursively skip properly-nested square brackets.
110 ConsumeBracket();
Chris Lattner5bd57e02006-08-11 06:40:25 +0000111 SkipUntil(tok::r_square, false);
Chris Lattnereec40f92006-08-06 21:55:29 +0000112 break;
113 case tok::l_brace:
114 // Recursively skip properly-nested braces.
115 ConsumeBrace();
Chris Lattner5bd57e02006-08-11 06:40:25 +0000116 SkipUntil(tok::r_brace, false);
Chris Lattnereec40f92006-08-06 21:55:29 +0000117 break;
118
119 // Okay, we found a ']' or '}' or ')', which we think should be balanced.
120 // Since the user wasn't looking for this token (if they were, it would
121 // already be handled), this isn't balanced. If there is a LHS token at a
122 // higher level, we will assume that this matches the unbalanced token
123 // and return it. Otherwise, this is a spurious RHS token, which we skip.
124 case tok::r_paren:
Chris Lattner5bd57e02006-08-11 06:40:25 +0000125 if (ParenCount && !isFirstTokenSkipped)
126 return false; // Matches something.
Chris Lattnereec40f92006-08-06 21:55:29 +0000127 ConsumeParen();
128 break;
129 case tok::r_square:
Chris Lattner5bd57e02006-08-11 06:40:25 +0000130 if (BracketCount && !isFirstTokenSkipped)
131 return false; // Matches something.
Chris Lattnereec40f92006-08-06 21:55:29 +0000132 ConsumeBracket();
133 break;
134 case tok::r_brace:
Chris Lattner5bd57e02006-08-11 06:40:25 +0000135 if (BraceCount && !isFirstTokenSkipped)
136 return false; // Matches something.
Chris Lattnereec40f92006-08-06 21:55:29 +0000137 ConsumeBrace();
138 break;
139
140 case tok::string_literal:
141 ConsumeStringToken();
142 break;
143 case tok::semi:
144 if (StopAtSemi)
145 return false;
146 // FALL THROUGH.
147 default:
148 // Skip this token.
149 ConsumeToken();
150 break;
151 }
Chris Lattner5bd57e02006-08-11 06:40:25 +0000152 isFirstTokenSkipped = false;
Chris Lattnereec40f92006-08-06 21:55:29 +0000153 }
154}
155
156//===----------------------------------------------------------------------===//
Chris Lattner70f32b72006-07-31 05:09:04 +0000157// C99 6.9: External Definitions.
158//===----------------------------------------------------------------------===//
Chris Lattner0bb5f832006-07-31 01:59:18 +0000159
160/// ParseTranslationUnit:
Chris Lattner70f32b72006-07-31 05:09:04 +0000161/// translation-unit: [C99 6.9]
Chris Lattner0bb5f832006-07-31 01:59:18 +0000162/// external-declaration
163/// translation-unit external-declaration
164void Parser::ParseTranslationUnit() {
165
166 if (Tok.getKind() == tok::eof) // Empty source file is an extension.
167 Diag(diag::ext_empty_source_file);
168
169 while (Tok.getKind() != tok::eof)
170 ParseExternalDeclaration();
171}
172
173/// ParseExternalDeclaration:
Chris Lattner70f32b72006-07-31 05:09:04 +0000174/// external-declaration: [C99 6.9]
Chris Lattner0bb5f832006-07-31 01:59:18 +0000175/// function-definition [TODO]
176/// declaration [TODO]
177/// [EXT] ';'
178/// [GNU] asm-definition [TODO]
179/// [GNU] __extension__ external-declaration [TODO]
180/// [OBJC] objc-class-definition [TODO]
181/// [OBJC] objc-class-declaration [TODO]
182/// [OBJC] objc-alias-declaration [TODO]
183/// [OBJC] objc-protocol-definition [TODO]
184/// [OBJC] objc-method-definition [TODO]
185/// [OBJC] @end [TODO]
186///
187void Parser::ParseExternalDeclaration() {
188 switch (Tok.getKind()) {
189 case tok::semi:
190 Diag(diag::ext_top_level_semi);
191 ConsumeToken();
192 break;
193 default:
194 // We can't tell whether this is a function-definition or declaration yet.
195 ParseDeclarationOrFunctionDefinition();
196 break;
197 }
198}
199
200/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
Chris Lattner70f32b72006-07-31 05:09:04 +0000201/// a declaration. We can't tell which we have until we read up to the
202/// compound-statement in function-definition.
Chris Lattner0bb5f832006-07-31 01:59:18 +0000203///
Chris Lattner70f32b72006-07-31 05:09:04 +0000204/// function-definition: [C99 6.9.1]
205/// declaration-specifiers[opt] declarator declaration-list[opt]
206/// compound-statement [TODO]
207/// declaration: [C99 6.7]
Chris Lattner0bb5f832006-07-31 01:59:18 +0000208/// declaration-specifiers init-declarator-list[opt] ';' [TODO]
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000209/// [!C99] init-declarator-list ';' [TODO]
Chris Lattner70f32b72006-07-31 05:09:04 +0000210/// [OMP] threadprivate-directive [TODO]
211///
212/// init-declarator-list: [C99 6.7]
213/// init-declarator
214/// init-declarator-list ',' init-declarator
215/// init-declarator: [C99 6.7]
216/// declarator
217/// declarator '=' initializer
218///
Chris Lattner0bb5f832006-07-31 01:59:18 +0000219void Parser::ParseDeclarationOrFunctionDefinition() {
Chris Lattner70f32b72006-07-31 05:09:04 +0000220 // Parse the common declaration-specifiers piece.
Chris Lattnerb9093cd2006-08-04 04:39:53 +0000221 DeclSpec DS;
222 ParseDeclarationSpecifiers(DS);
Chris Lattnerd2864882006-08-05 08:09:44 +0000223
224 // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
Chris Lattner53361ac2006-08-10 05:19:57 +0000225 // declaration-specifiers init-declarator-list[opt] ';'
Chris Lattnerd2864882006-08-05 08:09:44 +0000226 if (Tok.getKind() == tok::semi)
227 assert(0 && "Unimp!");
228
Chris Lattner70f32b72006-07-31 05:09:04 +0000229
Chris Lattnerfff824f2006-08-07 06:31:38 +0000230 // Parse the first declarator.
231 Declarator DeclaratorInfo(DS, Declarator::FileContext);
232 ParseDeclarator(DeclaratorInfo);
233 // Error parsing the declarator?
234 if (DeclaratorInfo.getIdentifier() == 0) {
235 // If so, skip until the semi-colon or a }.
236 SkipUntil(tok::r_brace, true);
237 if (Tok.getKind() == tok::semi)
238 ConsumeToken();
239 return;
240 }
Chris Lattner70f32b72006-07-31 05:09:04 +0000241
Chris Lattnerfff824f2006-08-07 06:31:38 +0000242 // If the declarator is the start of a function definition, handle it.
243 if (Tok.getKind() == tok::equal || // int X()= -> not a function def
244 Tok.getKind() == tok::comma || // int X(), -> not a function def
245 Tok.getKind() == tok::semi || // int X(); -> not a function def
246 Tok.getKind() == tok::kw_asm || // int X() __asm__ -> not a fn def
247 Tok.getKind() == tok::kw___attribute) {// int X() __attr__ -> not a fn def
248 // FALL THROUGH.
249 } else if (DeclaratorInfo.isInnermostFunctionType() &&
250 (Tok.getKind() == tok::l_brace || // int X() {}
251 isDeclarationSpecifier())) { // int X(f) int f; {}
252 ParseFunctionDefinition(DeclaratorInfo);
253 return;
254 } else {
255 if (DeclaratorInfo.isInnermostFunctionType())
256 Diag(Tok, diag::err_expected_fn_body);
257 else
258 Diag(Tok, diag::err_expected_after_declarator);
259 SkipUntil(tok::r_brace, true);
260 if (Tok.getKind() == tok::semi)
261 ConsumeToken();
262 return;
263 }
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000264
Chris Lattner53361ac2006-08-10 05:19:57 +0000265 // Parse the init-declarator-list for a normal declaration.
266 ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
Chris Lattner70f32b72006-07-31 05:09:04 +0000267}
268
Chris Lattnerfff824f2006-08-07 06:31:38 +0000269/// ParseFunctionDefinition - We parsed and verified that the specified
270/// Declarator is well formed. If this is a K&R-style function, read the
271/// parameters declaration-list, then start the compound-statement.
272///
273/// declaration-specifiers[opt] declarator declaration-list[opt]
274/// compound-statement [TODO]
275///
276void Parser::ParseFunctionDefinition(Declarator &D) {
277 const DeclaratorTypeInfo &FnTypeInfo = D.getTypeObject(0);
278 assert(FnTypeInfo.Kind == DeclaratorTypeInfo::Function &&
279 "This isn't a function declarator!");
280
281 // If this declaration was formed with a K&R-style identifier list for the
282 // arguments, parse declarations for all of the args next.
283 // int foo(a,b) int a; float b; {}
284 if (!FnTypeInfo.Fun.hasPrototype && !FnTypeInfo.Fun.isEmpty) {
285 // Read all the argument declarations.
Chris Lattner53361ac2006-08-10 05:19:57 +0000286 while (isDeclarationSpecifier())
287 ParseDeclaration(Declarator::KNRTypeListContext);
Chris Lattnerfff824f2006-08-07 06:31:38 +0000288
289 // Note, check that we got them all.
290 } else {
291 //if (isDeclarationSpecifier())
292 // Diag('k&r declspecs with prototype?');
293
294 // FIXME: Install the arguments into the current scope.
295 }
296
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000297 // We should have an opening brace now.
298 if (Tok.getKind() != tok::l_brace) {
299 Diag(Tok, diag::err_expected_fn_body);
300
301 // Skip over garbage, until we get to '{'. Don't eat the '{'.
302 SkipUntil(tok::l_brace, true, true);
303
304 // If we didn't find the '{', bail out.
305 if (Tok.getKind() != tok::l_brace)
306 return;
307 }
Chris Lattnerfff824f2006-08-07 06:31:38 +0000308
Chris Lattner0ccd51e2006-08-09 05:47:47 +0000309 ParseCompoundStatement();
Chris Lattnerfff824f2006-08-07 06:31:38 +0000310}
311