blob: 64b48b4c5cabf66963c9611f1ae61117121e89d1 [file] [log] [blame]
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001//
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +00002// Copyright (c) 2011-2013 The ANGLE Project Authors. All rights reserved.
alokp@chromium.org04d7d222012-05-16 19:24:07 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "DirectiveParser.h"
8
Geoff Lang26be18d2015-04-27 14:05:57 -04009#include <algorithm>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000010#include <cassert>
alokp@chromium.org51b96852012-05-30 20:25:05 +000011#include <cstdlib>
alokp@chromium.org36124de82012-05-24 02:17:43 +000012#include <sstream>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000013
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000014#include "DiagnosticsBase.h"
15#include "DirectiveHandlerBase.h"
alokp@chromium.org04d7d222012-05-16 19:24:07 +000016#include "ExpressionParser.h"
17#include "MacroExpander.h"
18#include "Token.h"
19#include "Tokenizer.h"
20
21namespace {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000022enum DirectiveType
23{
24 DIRECTIVE_NONE,
25 DIRECTIVE_DEFINE,
26 DIRECTIVE_UNDEF,
27 DIRECTIVE_IF,
28 DIRECTIVE_IFDEF,
29 DIRECTIVE_IFNDEF,
30 DIRECTIVE_ELSE,
31 DIRECTIVE_ELIF,
32 DIRECTIVE_ENDIF,
33 DIRECTIVE_ERROR,
34 DIRECTIVE_PRAGMA,
35 DIRECTIVE_EXTENSION,
36 DIRECTIVE_VERSION,
37 DIRECTIVE_LINE
38};
alokp@chromium.org04d7d222012-05-16 19:24:07 +000039
Zhenyao Mod526f982014-05-13 14:51:19 -070040DirectiveType getDirective(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000041{
Zhenyao Mob5e17752014-10-22 10:57:10 -070042 const char kDirectiveDefine[] = "define";
43 const char kDirectiveUndef[] = "undef";
44 const char kDirectiveIf[] = "if";
45 const char kDirectiveIfdef[] = "ifdef";
46 const char kDirectiveIfndef[] = "ifndef";
47 const char kDirectiveElse[] = "else";
48 const char kDirectiveElif[] = "elif";
49 const char kDirectiveEndif[] = "endif";
50 const char kDirectiveError[] = "error";
51 const char kDirectivePragma[] = "pragma";
52 const char kDirectiveExtension[] = "extension";
53 const char kDirectiveVersion[] = "version";
54 const char kDirectiveLine[] = "line";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000055
56 if (token->type != pp::Token::IDENTIFIER)
57 return DIRECTIVE_NONE;
58
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000059 if (token->text == kDirectiveDefine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000060 return DIRECTIVE_DEFINE;
Zhenyao Mod526f982014-05-13 14:51:19 -070061 if (token->text == kDirectiveUndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000062 return DIRECTIVE_UNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070063 if (token->text == kDirectiveIf)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000064 return DIRECTIVE_IF;
Zhenyao Mod526f982014-05-13 14:51:19 -070065 if (token->text == kDirectiveIfdef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000066 return DIRECTIVE_IFDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070067 if (token->text == kDirectiveIfndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000068 return DIRECTIVE_IFNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070069 if (token->text == kDirectiveElse)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000070 return DIRECTIVE_ELSE;
Zhenyao Mod526f982014-05-13 14:51:19 -070071 if (token->text == kDirectiveElif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000072 return DIRECTIVE_ELIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070073 if (token->text == kDirectiveEndif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000074 return DIRECTIVE_ENDIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070075 if (token->text == kDirectiveError)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000076 return DIRECTIVE_ERROR;
Zhenyao Mod526f982014-05-13 14:51:19 -070077 if (token->text == kDirectivePragma)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000078 return DIRECTIVE_PRAGMA;
Zhenyao Mod526f982014-05-13 14:51:19 -070079 if (token->text == kDirectiveExtension)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000080 return DIRECTIVE_EXTENSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070081 if (token->text == kDirectiveVersion)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000082 return DIRECTIVE_VERSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070083 if (token->text == kDirectiveLine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000084 return DIRECTIVE_LINE;
85
86 return DIRECTIVE_NONE;
87}
88
Zhenyao Mod526f982014-05-13 14:51:19 -070089bool isConditionalDirective(DirectiveType directive)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000090{
91 switch (directive)
92 {
93 case DIRECTIVE_IF:
94 case DIRECTIVE_IFDEF:
95 case DIRECTIVE_IFNDEF:
96 case DIRECTIVE_ELSE:
97 case DIRECTIVE_ELIF:
98 case DIRECTIVE_ENDIF:
99 return true;
100 default:
101 return false;
102 }
103}
104
105// Returns true if the token represents End Of Directive.
Zhenyao Mod526f982014-05-13 14:51:19 -0700106bool isEOD(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000107{
108 return (token->type == '\n') || (token->type == pp::Token::LAST);
109}
110
Zhenyao Mod526f982014-05-13 14:51:19 -0700111void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000112{
113 while(!isEOD(token))
114 {
115 lexer->lex(token);
116 }
117}
118
Zhenyao Mod526f982014-05-13 14:51:19 -0700119bool isMacroNameReserved(const std::string &name)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000120{
Geoff Lang942e3622015-04-30 11:00:01 -0400121 const char *kPredefinedMacros[] =
122 {
123 "__LINE__",
124 "__FILE__",
125 "__VERSION__",
126 "GL_ES",
127 };
128 const size_t kPredefinedMacrosCount = sizeof(kPredefinedMacros) / sizeof(*kPredefinedMacros);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000129
Geoff Lang942e3622015-04-30 11:00:01 -0400130 for (size_t i = 0; i < kPredefinedMacrosCount; i++)
131 {
132 if (name == kPredefinedMacros[i])
133 {
134 return true;
135 }
136 }
137
138 // Names prefixed with "GL_" are reserved.
139 if (name.compare(0, 3, "GL_") == 0)
140 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000141 return true;
Geoff Lang942e3622015-04-30 11:00:01 -0400142 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000143
144 return false;
145}
146
Zhenyao Mod526f982014-05-13 14:51:19 -0700147bool isMacroPredefined(const std::string &name,
148 const pp::MacroSet &macroSet)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000149{
150 pp::MacroSet::const_iterator iter = macroSet.find(name);
151 return iter != macroSet.end() ? iter->second.predefined : false;
152}
153
Zhenyao Mod526f982014-05-13 14:51:19 -0700154} // namespace anonymous
155
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000156namespace pp
157{
158
159class DefinedParser : public Lexer
160{
161 public:
Zhenyao Mod526f982014-05-13 14:51:19 -0700162 DefinedParser(Lexer *lexer,
163 const MacroSet *macroSet,
164 Diagnostics *diagnostics)
165 : mLexer(lexer),
166 mMacroSet(macroSet),
167 mDiagnostics(diagnostics)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000168 {
169 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000170
171 protected:
Zhenyao Mod526f982014-05-13 14:51:19 -0700172 virtual void lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000173 {
Zhenyao Mob5e17752014-10-22 10:57:10 -0700174 const char kDefined[] = "defined";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000175
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000176 mLexer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000177 if (token->type != Token::IDENTIFIER)
178 return;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000179 if (token->text != kDefined)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000180 return;
181
182 bool paren = false;
183 mLexer->lex(token);
184 if (token->type == '(')
185 {
186 paren = true;
187 mLexer->lex(token);
188 }
189
190 if (token->type != Token::IDENTIFIER)
191 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500192 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000193 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000194 skipUntilEOD(mLexer, token);
195 return;
196 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000197 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000198 std::string expression = iter != mMacroSet->end() ? "1" : "0";
199
200 if (paren)
201 {
202 mLexer->lex(token);
203 if (token->type != ')')
204 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500205 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000206 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000207 skipUntilEOD(mLexer, token);
208 return;
209 }
210 }
211
212 // We have a valid defined operator.
213 // Convert the current token into a CONST_INT token.
214 token->type = Token::CONST_INT;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000215 token->text = expression;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000216 }
217
218 private:
Zhenyao Mod526f982014-05-13 14:51:19 -0700219 Lexer *mLexer;
220 const MacroSet *mMacroSet;
221 Diagnostics *mDiagnostics;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000222};
223
Zhenyao Mod526f982014-05-13 14:51:19 -0700224DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
225 MacroSet *macroSet,
226 Diagnostics *diagnostics,
227 DirectiveHandler *directiveHandler)
228 : mPastFirstStatement(false),
229 mTokenizer(tokenizer),
230 mMacroSet(macroSet),
231 mDiagnostics(diagnostics),
232 mDirectiveHandler(directiveHandler)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000233{
234}
235
Zhenyao Mod526f982014-05-13 14:51:19 -0700236void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000237{
238 do
239 {
240 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000241
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000242 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000243 {
244 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000245 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000246 }
247
248 if (token->type == Token::LAST)
249 {
250 if (!mConditionalStack.empty())
251 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700252 const ConditionalBlock &block = mConditionalStack.back();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500253 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000254 block.location, block.type);
255 }
256 break;
257 }
258
Zhenyao Mod526f982014-05-13 14:51:19 -0700259 }
260 while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000261
262 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000263}
264
Zhenyao Mod526f982014-05-13 14:51:19 -0700265void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000266{
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000267 assert(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000268
269 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000270 if (isEOD(token))
271 {
272 // Empty Directive.
273 return;
274 }
275
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000276 DirectiveType directive = getDirective(token);
277
278 // While in an excluded conditional block/group,
279 // we only parse conditional directives.
280 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000281 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000282 skipUntilEOD(mTokenizer, token);
283 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000284 }
285
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000286 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000287 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000288 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500289 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000290 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000291 skipUntilEOD(mTokenizer, token);
292 break;
293 case DIRECTIVE_DEFINE:
294 parseDefine(token);
295 break;
296 case DIRECTIVE_UNDEF:
297 parseUndef(token);
298 break;
299 case DIRECTIVE_IF:
300 parseIf(token);
301 break;
302 case DIRECTIVE_IFDEF:
303 parseIfdef(token);
304 break;
305 case DIRECTIVE_IFNDEF:
306 parseIfndef(token);
307 break;
308 case DIRECTIVE_ELSE:
309 parseElse(token);
310 break;
311 case DIRECTIVE_ELIF:
312 parseElif(token);
313 break;
314 case DIRECTIVE_ENDIF:
315 parseEndif(token);
316 break;
317 case DIRECTIVE_ERROR:
318 parseError(token);
319 break;
320 case DIRECTIVE_PRAGMA:
321 parsePragma(token);
322 break;
323 case DIRECTIVE_EXTENSION:
324 parseExtension(token);
325 break;
326 case DIRECTIVE_VERSION:
327 parseVersion(token);
328 break;
329 case DIRECTIVE_LINE:
330 parseLine(token);
331 break;
332 default:
333 assert(false);
334 break;
335 }
336
337 skipUntilEOD(mTokenizer, token);
338 if (token->type == Token::LAST)
339 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500340 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000341 token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000342 }
343}
344
Zhenyao Mod526f982014-05-13 14:51:19 -0700345void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000346{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000347 assert(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000348
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000349 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000350 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000351 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500352 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000353 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000354 return;
355 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000356 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000357 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500358 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000359 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000360 return;
361 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000362 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000363 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500364 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000365 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000366 return;
367 }
368
369 Macro macro;
370 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000371 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000372
373 mTokenizer->lex(token);
374 if (token->type == '(' && !token->hasLeadingSpace())
375 {
376 // Function-like macro. Collect arguments.
377 macro.type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700378 do
379 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000380 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000381 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000382 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400383
384 if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
385 {
386 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
387 token->location, token->text);
388 return;
389 }
390
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000391 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000392
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000393 mTokenizer->lex(token); // Get ','.
Zhenyao Mod526f982014-05-13 14:51:19 -0700394 }
395 while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000396
397 if (token->type != ')')
398 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500399 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000400 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000401 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000402 return;
403 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000404 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000405 }
406
alokp@chromium.org7c884542012-05-24 19:13:03 +0000407 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000408 {
409 // Reset the token location because it is unnecessary in replacement
410 // list. Resetting it also allows us to reuse Token::equals() to
411 // compare macros.
412 token->location = SourceLocation();
413 macro.replacements.push_back(*token);
414 mTokenizer->lex(token);
415 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000416 if (!macro.replacements.empty())
417 {
418 // Whitespace preceding the replacement list is not considered part of
419 // the replacement list for either form of macro.
420 macro.replacements.front().setHasLeadingSpace(false);
421 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000422
423 // Check for macro redefinition.
424 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
425 if (iter != mMacroSet->end() && !macro.equals(iter->second))
426 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500427 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000428 token->location,
429 macro.name);
430 return;
431 }
432 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000433}
434
Zhenyao Mod526f982014-05-13 14:51:19 -0700435void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000436{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000437 assert(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000438
439 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000440 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000441 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500442 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000443 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000444 return;
445 }
446
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000447 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000448 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000449 {
450 if (iter->second.predefined)
451 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500452 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000453 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000454 }
455 else
456 {
457 mMacroSet->erase(iter);
458 }
459 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000460
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000461 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400462 if (!isEOD(token))
463 {
464 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
465 token->location, token->text);
466 skipUntilEOD(mTokenizer, token);
467 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000468}
469
Zhenyao Mod526f982014-05-13 14:51:19 -0700470void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000471{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000472 assert(getDirective(token) == DIRECTIVE_IF);
473 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000474}
475
Zhenyao Mod526f982014-05-13 14:51:19 -0700476void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000477{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000478 assert(getDirective(token) == DIRECTIVE_IFDEF);
479 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000480}
481
Zhenyao Mod526f982014-05-13 14:51:19 -0700482void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000483{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000484 assert(getDirective(token) == DIRECTIVE_IFNDEF);
485 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000486}
487
Zhenyao Mod526f982014-05-13 14:51:19 -0700488void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000489{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000490 assert(getDirective(token) == DIRECTIVE_ELSE);
491
492 if (mConditionalStack.empty())
493 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500494 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000495 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000496 skipUntilEOD(mTokenizer, token);
497 return;
498 }
499
Zhenyao Mod526f982014-05-13 14:51:19 -0700500 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000501 if (block.skipBlock)
502 {
503 // No diagnostics. Just skip the whole line.
504 skipUntilEOD(mTokenizer, token);
505 return;
506 }
507 if (block.foundElseGroup)
508 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500509 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000510 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000511 skipUntilEOD(mTokenizer, token);
512 return;
513 }
514
515 block.foundElseGroup = true;
516 block.skipGroup = block.foundValidGroup;
517 block.foundValidGroup = true;
518
Geoff Lang95a423d2015-04-28 11:09:45 -0400519 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000520 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000521 if (!isEOD(token))
522 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500523 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000524 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000525 skipUntilEOD(mTokenizer, token);
526 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000527}
528
Zhenyao Mod526f982014-05-13 14:51:19 -0700529void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000530{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000531 assert(getDirective(token) == DIRECTIVE_ELIF);
532
533 if (mConditionalStack.empty())
534 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500535 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000536 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000537 skipUntilEOD(mTokenizer, token);
538 return;
539 }
540
Zhenyao Mod526f982014-05-13 14:51:19 -0700541 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000542 if (block.skipBlock)
543 {
544 // No diagnostics. Just skip the whole line.
545 skipUntilEOD(mTokenizer, token);
546 return;
547 }
548 if (block.foundElseGroup)
549 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500550 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000551 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000552 skipUntilEOD(mTokenizer, token);
553 return;
554 }
555 if (block.foundValidGroup)
556 {
557 // Do not parse the expression.
558 // Also be careful not to emit a diagnostic.
559 block.skipGroup = true;
560 skipUntilEOD(mTokenizer, token);
561 return;
562 }
563
564 int expression = parseExpressionIf(token);
565 block.skipGroup = expression == 0;
566 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000567}
568
Zhenyao Mod526f982014-05-13 14:51:19 -0700569void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000570{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000571 assert(getDirective(token) == DIRECTIVE_ENDIF);
572
573 if (mConditionalStack.empty())
574 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500575 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000576 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000577 skipUntilEOD(mTokenizer, token);
578 return;
579 }
580
581 mConditionalStack.pop_back();
582
Geoff Lang95a423d2015-04-28 11:09:45 -0400583 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000584 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000585 if (!isEOD(token))
586 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500587 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000588 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000589 skipUntilEOD(mTokenizer, token);
590 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000591}
592
Zhenyao Mod526f982014-05-13 14:51:19 -0700593void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000594{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000595 assert(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000596
alokp@chromium.org2e818912012-06-29 21:26:03 +0000597 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000598 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000599 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000600 {
601 stream << *token;
602 mTokenizer->lex(token);
603 }
604 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000605}
606
alokp@chromium.org36124de82012-05-24 02:17:43 +0000607// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700608void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000609{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000610 assert(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000611
612 enum State
613 {
614 PRAGMA_NAME,
615 LEFT_PAREN,
616 PRAGMA_VALUE,
617 RIGHT_PAREN
618 };
619
620 bool valid = true;
621 std::string name, value;
622 int state = PRAGMA_NAME;
623
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000624 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700625 bool stdgl = token->text == "STDGL";
626 if (stdgl)
627 {
628 mTokenizer->lex(token);
629 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000630 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000631 {
632 switch(state++)
633 {
634 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000635 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000636 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000637 break;
638 case LEFT_PAREN:
639 valid = valid && (token->type == '(');
640 break;
641 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000642 value = token->text;
Geoff Langd3c29f52015-04-28 11:23:02 -0400643 // Pragma value validation is handled in DirectiveHandler::handlePragma
644 // because the proper pragma value is dependent on the pragma name.
alokp@chromium.org36124de82012-05-24 02:17:43 +0000645 break;
646 case RIGHT_PAREN:
647 valid = valid && (token->type == ')');
648 break;
649 default:
650 valid = false;
651 break;
652 }
653 mTokenizer->lex(token);
654 }
655
656 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
657 (state == LEFT_PAREN) || // Without value.
658 (state == RIGHT_PAREN + 1)); // With value.
659 if (!valid)
660 {
Geoff Langd3c29f52015-04-28 11:23:02 -0400661 mDiagnostics->report(Diagnostics::PP_INVALID_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000662 token->location, name);
663 }
664 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
665 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700666 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000667 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000668}
669
Zhenyao Mod526f982014-05-13 14:51:19 -0700670void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000671{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000672 assert(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000673
674 enum State
675 {
676 EXT_NAME,
677 COLON,
678 EXT_BEHAVIOR
679 };
680
681 bool valid = true;
682 std::string name, behavior;
683 int state = EXT_NAME;
684
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000685 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000686 while ((token->type != '\n') && (token->type != Token::LAST))
687 {
688 switch (state++)
689 {
690 case EXT_NAME:
691 if (valid && (token->type != Token::IDENTIFIER))
692 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500693 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000694 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000695 valid = false;
696 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000697 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000698 break;
699 case COLON:
700 if (valid && (token->type != ':'))
701 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500702 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000703 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000704 valid = false;
705 }
706 break;
707 case EXT_BEHAVIOR:
708 if (valid && (token->type != Token::IDENTIFIER))
709 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500710 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000711 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000712 valid = false;
713 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000714 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000715 break;
716 default:
717 if (valid)
718 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500719 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000720 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000721 valid = false;
722 }
723 break;
724 }
725 mTokenizer->lex(token);
726 }
727 if (valid && (state != EXT_BEHAVIOR + 1))
728 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500729 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000730 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000731 valid = false;
732 }
733 if (valid)
734 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000735}
736
Zhenyao Mod526f982014-05-13 14:51:19 -0700737void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000738{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000739 assert(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000740
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000741 if (mPastFirstStatement)
742 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500743 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000744 token->location, token->text);
745 skipUntilEOD(mTokenizer, token);
746 return;
747 }
748
alokp@chromium.org7c884542012-05-24 19:13:03 +0000749 enum State
750 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000751 VERSION_NUMBER,
752 VERSION_PROFILE,
753 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000754 };
755
756 bool valid = true;
757 int version = 0;
758 int state = VERSION_NUMBER;
759
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000760 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000761 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000762 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000763 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000764 {
765 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000766 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000767 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500768 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000769 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000770 valid = false;
771 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000772 if (valid && !token->iValue(&version))
773 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500774 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000775 token->location, token->text);
776 valid = false;
777 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000778 if (valid)
779 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000780 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
781 }
782 break;
783 case VERSION_PROFILE:
784 if (token->type != Token::IDENTIFIER || token->text != "es")
785 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500786 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000787 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000788 valid = false;
789 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000790 state = VERSION_ENDLINE;
791 break;
792 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500793 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000794 token->location, token->text);
795 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000796 break;
797 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000798
alokp@chromium.org7c884542012-05-24 19:13:03 +0000799 mTokenizer->lex(token);
800 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000801
802 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000803 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500804 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000805 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000806 valid = false;
807 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000808
alokp@chromium.org7c884542012-05-24 19:13:03 +0000809 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000810 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000811 mDirectiveHandler->handleVersion(token->location, version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000812 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000813}
814
Zhenyao Mod526f982014-05-13 14:51:19 -0700815void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000816{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000817 assert(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000818
819 enum State
820 {
821 LINE_NUMBER,
822 FILE_NUMBER
823 };
824
825 bool valid = true;
826 int line = 0, file = 0;
827 int state = LINE_NUMBER;
828
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000829 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000830 macroExpander.lex(token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000831 while ((token->type != '\n') && (token->type != Token::LAST))
832 {
833 switch (state++)
834 {
835 case LINE_NUMBER:
836 if (valid && (token->type != Token::CONST_INT))
837 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500838 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000839 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000840 valid = false;
841 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000842 if (valid && !token->iValue(&line))
843 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500844 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000845 token->location, token->text);
846 valid = false;
847 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000848 break;
849 case FILE_NUMBER:
850 if (valid && (token->type != Token::CONST_INT))
851 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500852 mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000853 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000854 valid = false;
855 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000856 if (valid && !token->iValue(&file))
857 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500858 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000859 token->location, token->text);
860 valid = false;
861 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000862 break;
863 default:
864 if (valid)
865 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500866 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000867 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000868 valid = false;
869 }
870 break;
871 }
872 macroExpander.lex(token);
873 }
874
875 if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
876 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500877 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000878 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000879 valid = false;
880 }
881 if (valid)
882 {
883 mTokenizer->setLineNumber(line);
Zhenyao Mod526f982014-05-13 14:51:19 -0700884 if (state == FILE_NUMBER + 1)
885 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000886 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000887}
888
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000889bool DirectiveParser::skipping() const
890{
Zhenyao Mod526f982014-05-13 14:51:19 -0700891 if (mConditionalStack.empty())
892 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000893
894 const ConditionalBlock& block = mConditionalStack.back();
895 return block.skipBlock || block.skipGroup;
896}
897
Zhenyao Mod526f982014-05-13 14:51:19 -0700898void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000899{
900 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000901 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000902 block.location = token->location;
903
904 if (skipping())
905 {
906 // This conditional block is inside another conditional group
907 // which is skipped. As a consequence this whole block is skipped.
908 // Be careful not to parse the conditional expression that might
909 // emit a diagnostic.
910 skipUntilEOD(mTokenizer, token);
911 block.skipBlock = true;
912 }
913 else
914 {
915 DirectiveType directive = getDirective(token);
916
917 int expression = 0;
918 switch (directive)
919 {
920 case DIRECTIVE_IF:
921 expression = parseExpressionIf(token);
922 break;
923 case DIRECTIVE_IFDEF:
924 expression = parseExpressionIfdef(token);
925 break;
926 case DIRECTIVE_IFNDEF:
927 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
928 break;
929 default:
930 assert(false);
931 break;
932 }
933 block.skipGroup = expression == 0;
934 block.foundValidGroup = expression != 0;
935 }
936 mConditionalStack.push_back(block);
937}
938
Zhenyao Mod526f982014-05-13 14:51:19 -0700939int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000940{
941 assert((getDirective(token) == DIRECTIVE_IF) ||
942 (getDirective(token) == DIRECTIVE_ELIF));
943
944 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
945 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
946 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
947
948 int expression = 0;
949 macroExpander.lex(token);
950 expressionParser.parse(token, &expression);
951
Geoff Lang95a423d2015-04-28 11:09:45 -0400952 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000953 if (!isEOD(token))
954 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500955 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000956 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000957 skipUntilEOD(mTokenizer, token);
958 }
959
960 return expression;
961}
962
Zhenyao Mod526f982014-05-13 14:51:19 -0700963int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000964{
965 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
966 (getDirective(token) == DIRECTIVE_IFNDEF));
967
968 mTokenizer->lex(token);
969 if (token->type != Token::IDENTIFIER)
970 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500971 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000972 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000973 skipUntilEOD(mTokenizer, token);
974 return 0;
975 }
976
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000977 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000978 int expression = iter != mMacroSet->end() ? 1 : 0;
979
Geoff Lang95a423d2015-04-28 11:09:45 -0400980 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000981 mTokenizer->lex(token);
982 if (!isEOD(token))
983 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500984 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000985 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000986 skipUntilEOD(mTokenizer, token);
987 }
988 return expression;
989}
990
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000991} // namespace pp