blob: 11f596f11df211385d0d06d616e49f1860447ecd [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 // NOTE: this can not be missing for C99 'declaration's.
191 DeclSpec DS;
192 ParseDeclarationSpecifiers(DS);
Chris Lattnerd2864882006-08-05 08:09:44 +0000193
194 // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
195 if (Tok.getKind() == tok::semi)
196 assert(0 && "Unimp!");
197
Chris Lattner70f32b72006-07-31 05:09:04 +0000198
Chris Lattner15356a72006-08-06 00:02:28 +0000199 // Parse the declarator.
200 {
Chris Lattneracd58a32006-08-06 17:24:14 +0000201 Declarator DeclaratorInfo(DS, Declarator::FileContext);
Chris Lattner15356a72006-08-06 00:02:28 +0000202 ParseDeclarator(DeclaratorInfo);
Chris Lattner70f32b72006-07-31 05:09:04 +0000203
Chris Lattner15356a72006-08-06 00:02:28 +0000204 // If the declarator was a function type... handle it.
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000205
Chris Lattner15356a72006-08-06 00:02:28 +0000206 // must be: decl-spec[opt] declarator init-declarator-list
207 // Parse declarator '=' initializer.
208 if (Tok.getKind() == tok::equal)
209 assert(0 && "cannot handle initializer yet!");
210 }
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000211
Chris Lattnerd2864882006-08-05 08:09:44 +0000212 while (Tok.getKind() == tok::comma) {
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000213 // Consume the comma.
214 ConsumeToken();
215
Chris Lattner15356a72006-08-06 00:02:28 +0000216 // Parse the declarator.
Chris Lattneracd58a32006-08-06 17:24:14 +0000217 Declarator DeclaratorInfo(DS, Declarator::FileContext);
Chris Lattner15356a72006-08-06 00:02:28 +0000218 ParseDeclarator(DeclaratorInfo);
Chris Lattnerd9c3c592006-08-05 06:26:47 +0000219
220 // declarator '=' initializer
221 if (Tok.getKind() == tok::equal)
222 assert(0 && "cannot handle initializer yet!");
223
224
225 }
Chris Lattnerd2864882006-08-05 08:09:44 +0000226
227 if (Tok.getKind() == tok::semi) {
Chris Lattner70f32b72006-07-31 05:09:04 +0000228 ConsumeToken();
Chris Lattnerd2864882006-08-05 08:09:44 +0000229 } else {
230 Diag(Tok, diag::err_parse_error);
Chris Lattnereec40f92006-08-06 21:55:29 +0000231 // Skip to end of block or statement
232 SkipUntil(tok::r_brace, true);
Chris Lattnerd2864882006-08-05 08:09:44 +0000233 if (Tok.getKind() == tok::semi)
234 ConsumeToken();
Chris Lattner70f32b72006-07-31 05:09:04 +0000235 }
236}
237