blob: 62fe6ab71ee71cdf4bdcc121adf2ae2d7d244d6c [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
9#include <cassert>
alokp@chromium.org51b96852012-05-30 20:25:05 +000010#include <cstdlib>
alokp@chromium.org36124de82012-05-24 02:17:43 +000011#include <sstream>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000012
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000013#include "DiagnosticsBase.h"
14#include "DirectiveHandlerBase.h"
alokp@chromium.org04d7d222012-05-16 19:24:07 +000015#include "ExpressionParser.h"
16#include "MacroExpander.h"
17#include "Token.h"
18#include "Tokenizer.h"
19
20namespace {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000021enum DirectiveType
22{
23 DIRECTIVE_NONE,
24 DIRECTIVE_DEFINE,
25 DIRECTIVE_UNDEF,
26 DIRECTIVE_IF,
27 DIRECTIVE_IFDEF,
28 DIRECTIVE_IFNDEF,
29 DIRECTIVE_ELSE,
30 DIRECTIVE_ELIF,
31 DIRECTIVE_ENDIF,
32 DIRECTIVE_ERROR,
33 DIRECTIVE_PRAGMA,
34 DIRECTIVE_EXTENSION,
35 DIRECTIVE_VERSION,
36 DIRECTIVE_LINE
37};
alokp@chromium.org04d7d222012-05-16 19:24:07 +000038
Zhenyao Mod526f982014-05-13 14:51:19 -070039DirectiveType getDirective(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000040{
Zhenyao Mob5e17752014-10-22 10:57:10 -070041 const char kDirectiveDefine[] = "define";
42 const char kDirectiveUndef[] = "undef";
43 const char kDirectiveIf[] = "if";
44 const char kDirectiveIfdef[] = "ifdef";
45 const char kDirectiveIfndef[] = "ifndef";
46 const char kDirectiveElse[] = "else";
47 const char kDirectiveElif[] = "elif";
48 const char kDirectiveEndif[] = "endif";
49 const char kDirectiveError[] = "error";
50 const char kDirectivePragma[] = "pragma";
51 const char kDirectiveExtension[] = "extension";
52 const char kDirectiveVersion[] = "version";
53 const char kDirectiveLine[] = "line";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000054
55 if (token->type != pp::Token::IDENTIFIER)
56 return DIRECTIVE_NONE;
57
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000058 if (token->text == kDirectiveDefine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000059 return DIRECTIVE_DEFINE;
Zhenyao Mod526f982014-05-13 14:51:19 -070060 if (token->text == kDirectiveUndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000061 return DIRECTIVE_UNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070062 if (token->text == kDirectiveIf)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000063 return DIRECTIVE_IF;
Zhenyao Mod526f982014-05-13 14:51:19 -070064 if (token->text == kDirectiveIfdef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000065 return DIRECTIVE_IFDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070066 if (token->text == kDirectiveIfndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000067 return DIRECTIVE_IFNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070068 if (token->text == kDirectiveElse)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000069 return DIRECTIVE_ELSE;
Zhenyao Mod526f982014-05-13 14:51:19 -070070 if (token->text == kDirectiveElif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000071 return DIRECTIVE_ELIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070072 if (token->text == kDirectiveEndif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000073 return DIRECTIVE_ENDIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070074 if (token->text == kDirectiveError)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000075 return DIRECTIVE_ERROR;
Zhenyao Mod526f982014-05-13 14:51:19 -070076 if (token->text == kDirectivePragma)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000077 return DIRECTIVE_PRAGMA;
Zhenyao Mod526f982014-05-13 14:51:19 -070078 if (token->text == kDirectiveExtension)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000079 return DIRECTIVE_EXTENSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070080 if (token->text == kDirectiveVersion)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000081 return DIRECTIVE_VERSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070082 if (token->text == kDirectiveLine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000083 return DIRECTIVE_LINE;
84
85 return DIRECTIVE_NONE;
86}
87
Zhenyao Mod526f982014-05-13 14:51:19 -070088bool isConditionalDirective(DirectiveType directive)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000089{
90 switch (directive)
91 {
92 case DIRECTIVE_IF:
93 case DIRECTIVE_IFDEF:
94 case DIRECTIVE_IFNDEF:
95 case DIRECTIVE_ELSE:
96 case DIRECTIVE_ELIF:
97 case DIRECTIVE_ENDIF:
98 return true;
99 default:
100 return false;
101 }
102}
103
104// Returns true if the token represents End Of Directive.
Zhenyao Mod526f982014-05-13 14:51:19 -0700105bool isEOD(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000106{
107 return (token->type == '\n') || (token->type == pp::Token::LAST);
108}
109
Zhenyao Mod526f982014-05-13 14:51:19 -0700110void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000111{
112 while(!isEOD(token))
113 {
114 lexer->lex(token);
115 }
116}
117
Zhenyao Mod526f982014-05-13 14:51:19 -0700118bool isMacroNameReserved(const std::string &name)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000119{
120 // Names prefixed with "GL_" are reserved.
121 if (name.substr(0, 3) == "GL_")
122 return true;
123
124 // Names containing two consecutive underscores are reserved.
125 if (name.find("__") != std::string::npos)
126 return true;
127
128 return false;
129}
130
Zhenyao Mod526f982014-05-13 14:51:19 -0700131bool isMacroPredefined(const std::string &name,
132 const pp::MacroSet &macroSet)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000133{
134 pp::MacroSet::const_iterator iter = macroSet.find(name);
135 return iter != macroSet.end() ? iter->second.predefined : false;
136}
137
Zhenyao Mod526f982014-05-13 14:51:19 -0700138} // namespace anonymous
139
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000140namespace pp
141{
142
143class DefinedParser : public Lexer
144{
145 public:
Zhenyao Mod526f982014-05-13 14:51:19 -0700146 DefinedParser(Lexer *lexer,
147 const MacroSet *macroSet,
148 Diagnostics *diagnostics)
149 : mLexer(lexer),
150 mMacroSet(macroSet),
151 mDiagnostics(diagnostics)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000152 {
153 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000154
155 protected:
Zhenyao Mod526f982014-05-13 14:51:19 -0700156 virtual void lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000157 {
Zhenyao Mob5e17752014-10-22 10:57:10 -0700158 const char kDefined[] = "defined";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000159
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000160 mLexer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000161 if (token->type != Token::IDENTIFIER)
162 return;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000163 if (token->text != kDefined)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000164 return;
165
166 bool paren = false;
167 mLexer->lex(token);
168 if (token->type == '(')
169 {
170 paren = true;
171 mLexer->lex(token);
172 }
173
174 if (token->type != Token::IDENTIFIER)
175 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500176 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000177 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000178 skipUntilEOD(mLexer, token);
179 return;
180 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000181 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000182 std::string expression = iter != mMacroSet->end() ? "1" : "0";
183
184 if (paren)
185 {
186 mLexer->lex(token);
187 if (token->type != ')')
188 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500189 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000190 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000191 skipUntilEOD(mLexer, token);
192 return;
193 }
194 }
195
196 // We have a valid defined operator.
197 // Convert the current token into a CONST_INT token.
198 token->type = Token::CONST_INT;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000199 token->text = expression;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000200 }
201
202 private:
Zhenyao Mod526f982014-05-13 14:51:19 -0700203 Lexer *mLexer;
204 const MacroSet *mMacroSet;
205 Diagnostics *mDiagnostics;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000206};
207
Zhenyao Mod526f982014-05-13 14:51:19 -0700208DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
209 MacroSet *macroSet,
210 Diagnostics *diagnostics,
211 DirectiveHandler *directiveHandler)
212 : mPastFirstStatement(false),
213 mTokenizer(tokenizer),
214 mMacroSet(macroSet),
215 mDiagnostics(diagnostics),
216 mDirectiveHandler(directiveHandler)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000217{
218}
219
Zhenyao Mod526f982014-05-13 14:51:19 -0700220void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000221{
222 do
223 {
224 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000225
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000226 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000227 {
228 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000229 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000230 }
231
232 if (token->type == Token::LAST)
233 {
234 if (!mConditionalStack.empty())
235 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700236 const ConditionalBlock &block = mConditionalStack.back();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500237 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000238 block.location, block.type);
239 }
240 break;
241 }
242
Zhenyao Mod526f982014-05-13 14:51:19 -0700243 }
244 while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000245
246 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000247}
248
Zhenyao Mod526f982014-05-13 14:51:19 -0700249void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000250{
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000251 assert(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000252
253 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000254 if (isEOD(token))
255 {
256 // Empty Directive.
257 return;
258 }
259
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000260 DirectiveType directive = getDirective(token);
261
262 // While in an excluded conditional block/group,
263 // we only parse conditional directives.
264 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000265 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000266 skipUntilEOD(mTokenizer, token);
267 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000268 }
269
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000270 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000271 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000272 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500273 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000274 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000275 skipUntilEOD(mTokenizer, token);
276 break;
277 case DIRECTIVE_DEFINE:
278 parseDefine(token);
279 break;
280 case DIRECTIVE_UNDEF:
281 parseUndef(token);
282 break;
283 case DIRECTIVE_IF:
284 parseIf(token);
285 break;
286 case DIRECTIVE_IFDEF:
287 parseIfdef(token);
288 break;
289 case DIRECTIVE_IFNDEF:
290 parseIfndef(token);
291 break;
292 case DIRECTIVE_ELSE:
293 parseElse(token);
294 break;
295 case DIRECTIVE_ELIF:
296 parseElif(token);
297 break;
298 case DIRECTIVE_ENDIF:
299 parseEndif(token);
300 break;
301 case DIRECTIVE_ERROR:
302 parseError(token);
303 break;
304 case DIRECTIVE_PRAGMA:
305 parsePragma(token);
306 break;
307 case DIRECTIVE_EXTENSION:
308 parseExtension(token);
309 break;
310 case DIRECTIVE_VERSION:
311 parseVersion(token);
312 break;
313 case DIRECTIVE_LINE:
314 parseLine(token);
315 break;
316 default:
317 assert(false);
318 break;
319 }
320
321 skipUntilEOD(mTokenizer, token);
322 if (token->type == Token::LAST)
323 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500324 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000325 token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000326 }
327}
328
Zhenyao Mod526f982014-05-13 14:51:19 -0700329void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000330{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000331 assert(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000332
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000333 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000334 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000335 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500336 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000337 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000338 return;
339 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000340 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000341 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500342 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000343 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000344 return;
345 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000346 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000347 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500348 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000349 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000350 return;
351 }
352
353 Macro macro;
354 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000355 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000356
357 mTokenizer->lex(token);
358 if (token->type == '(' && !token->hasLeadingSpace())
359 {
360 // Function-like macro. Collect arguments.
361 macro.type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700362 do
363 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000364 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000365 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000366 break;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000367 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000368
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000369 mTokenizer->lex(token); // Get ','.
Zhenyao Mod526f982014-05-13 14:51:19 -0700370 }
371 while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000372
373 if (token->type != ')')
374 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500375 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000376 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000377 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000378 return;
379 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000380 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000381 }
382
alokp@chromium.org7c884542012-05-24 19:13:03 +0000383 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000384 {
385 // Reset the token location because it is unnecessary in replacement
386 // list. Resetting it also allows us to reuse Token::equals() to
387 // compare macros.
388 token->location = SourceLocation();
389 macro.replacements.push_back(*token);
390 mTokenizer->lex(token);
391 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000392 if (!macro.replacements.empty())
393 {
394 // Whitespace preceding the replacement list is not considered part of
395 // the replacement list for either form of macro.
396 macro.replacements.front().setHasLeadingSpace(false);
397 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000398
399 // Check for macro redefinition.
400 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
401 if (iter != mMacroSet->end() && !macro.equals(iter->second))
402 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500403 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000404 token->location,
405 macro.name);
406 return;
407 }
408 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000409}
410
Zhenyao Mod526f982014-05-13 14:51:19 -0700411void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000412{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000413 assert(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000414
415 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000416 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000417 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500418 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000419 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000420 return;
421 }
422
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000423 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000424 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000425 {
426 if (iter->second.predefined)
427 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500428 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000429 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000430 }
431 else
432 {
433 mMacroSet->erase(iter);
434 }
435 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000436
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000437 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400438 if (!isEOD(token))
439 {
440 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
441 token->location, token->text);
442 skipUntilEOD(mTokenizer, token);
443 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000444}
445
Zhenyao Mod526f982014-05-13 14:51:19 -0700446void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000447{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000448 assert(getDirective(token) == DIRECTIVE_IF);
449 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000450}
451
Zhenyao Mod526f982014-05-13 14:51:19 -0700452void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000453{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000454 assert(getDirective(token) == DIRECTIVE_IFDEF);
455 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000456}
457
Zhenyao Mod526f982014-05-13 14:51:19 -0700458void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000459{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000460 assert(getDirective(token) == DIRECTIVE_IFNDEF);
461 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000462}
463
Zhenyao Mod526f982014-05-13 14:51:19 -0700464void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000465{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000466 assert(getDirective(token) == DIRECTIVE_ELSE);
467
468 if (mConditionalStack.empty())
469 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500470 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000471 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000472 skipUntilEOD(mTokenizer, token);
473 return;
474 }
475
Zhenyao Mod526f982014-05-13 14:51:19 -0700476 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000477 if (block.skipBlock)
478 {
479 // No diagnostics. Just skip the whole line.
480 skipUntilEOD(mTokenizer, token);
481 return;
482 }
483 if (block.foundElseGroup)
484 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500485 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000486 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000487 skipUntilEOD(mTokenizer, token);
488 return;
489 }
490
491 block.foundElseGroup = true;
492 block.skipGroup = block.foundValidGroup;
493 block.foundValidGroup = true;
494
495 // Warn if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000496 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000497 if (!isEOD(token))
498 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500499 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000500 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000501 skipUntilEOD(mTokenizer, token);
502 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000503}
504
Zhenyao Mod526f982014-05-13 14:51:19 -0700505void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000506{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000507 assert(getDirective(token) == DIRECTIVE_ELIF);
508
509 if (mConditionalStack.empty())
510 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500511 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000512 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000513 skipUntilEOD(mTokenizer, token);
514 return;
515 }
516
Zhenyao Mod526f982014-05-13 14:51:19 -0700517 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000518 if (block.skipBlock)
519 {
520 // No diagnostics. Just skip the whole line.
521 skipUntilEOD(mTokenizer, token);
522 return;
523 }
524 if (block.foundElseGroup)
525 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500526 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000527 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000528 skipUntilEOD(mTokenizer, token);
529 return;
530 }
531 if (block.foundValidGroup)
532 {
533 // Do not parse the expression.
534 // Also be careful not to emit a diagnostic.
535 block.skipGroup = true;
536 skipUntilEOD(mTokenizer, token);
537 return;
538 }
539
540 int expression = parseExpressionIf(token);
541 block.skipGroup = expression == 0;
542 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000543}
544
Zhenyao Mod526f982014-05-13 14:51:19 -0700545void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000546{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000547 assert(getDirective(token) == DIRECTIVE_ENDIF);
548
549 if (mConditionalStack.empty())
550 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500551 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000552 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000553 skipUntilEOD(mTokenizer, token);
554 return;
555 }
556
557 mConditionalStack.pop_back();
558
559 // Warn if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000560 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000561 if (!isEOD(token))
562 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500563 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000564 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000565 skipUntilEOD(mTokenizer, token);
566 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000567}
568
Zhenyao Mod526f982014-05-13 14:51:19 -0700569void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000570{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000571 assert(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000572
alokp@chromium.org2e818912012-06-29 21:26:03 +0000573 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000574 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000575 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000576 {
577 stream << *token;
578 mTokenizer->lex(token);
579 }
580 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000581}
582
alokp@chromium.org36124de82012-05-24 02:17:43 +0000583// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700584void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000585{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000586 assert(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000587
588 enum State
589 {
590 PRAGMA_NAME,
591 LEFT_PAREN,
592 PRAGMA_VALUE,
593 RIGHT_PAREN
594 };
595
596 bool valid = true;
597 std::string name, value;
598 int state = PRAGMA_NAME;
599
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000600 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700601 bool stdgl = token->text == "STDGL";
602 if (stdgl)
603 {
604 mTokenizer->lex(token);
605 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000606 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000607 {
608 switch(state++)
609 {
610 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000611 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000612 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000613 break;
614 case LEFT_PAREN:
615 valid = valid && (token->type == '(');
616 break;
617 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000618 value = token->text;
Geoff Langd3c29f52015-04-28 11:23:02 -0400619 // Pragma value validation is handled in DirectiveHandler::handlePragma
620 // because the proper pragma value is dependent on the pragma name.
alokp@chromium.org36124de82012-05-24 02:17:43 +0000621 break;
622 case RIGHT_PAREN:
623 valid = valid && (token->type == ')');
624 break;
625 default:
626 valid = false;
627 break;
628 }
629 mTokenizer->lex(token);
630 }
631
632 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
633 (state == LEFT_PAREN) || // Without value.
634 (state == RIGHT_PAREN + 1)); // With value.
635 if (!valid)
636 {
Geoff Langd3c29f52015-04-28 11:23:02 -0400637 mDiagnostics->report(Diagnostics::PP_INVALID_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000638 token->location, name);
639 }
640 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
641 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700642 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000643 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000644}
645
Zhenyao Mod526f982014-05-13 14:51:19 -0700646void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000647{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000648 assert(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000649
650 enum State
651 {
652 EXT_NAME,
653 COLON,
654 EXT_BEHAVIOR
655 };
656
657 bool valid = true;
658 std::string name, behavior;
659 int state = EXT_NAME;
660
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000661 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000662 while ((token->type != '\n') && (token->type != Token::LAST))
663 {
664 switch (state++)
665 {
666 case EXT_NAME:
667 if (valid && (token->type != Token::IDENTIFIER))
668 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500669 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000670 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000671 valid = false;
672 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000673 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000674 break;
675 case COLON:
676 if (valid && (token->type != ':'))
677 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500678 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000679 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000680 valid = false;
681 }
682 break;
683 case EXT_BEHAVIOR:
684 if (valid && (token->type != Token::IDENTIFIER))
685 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500686 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000687 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000688 valid = false;
689 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000690 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000691 break;
692 default:
693 if (valid)
694 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500695 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000696 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000697 valid = false;
698 }
699 break;
700 }
701 mTokenizer->lex(token);
702 }
703 if (valid && (state != EXT_BEHAVIOR + 1))
704 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500705 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000706 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000707 valid = false;
708 }
709 if (valid)
710 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000711}
712
Zhenyao Mod526f982014-05-13 14:51:19 -0700713void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000714{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000715 assert(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000716
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000717 if (mPastFirstStatement)
718 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500719 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000720 token->location, token->text);
721 skipUntilEOD(mTokenizer, token);
722 return;
723 }
724
alokp@chromium.org7c884542012-05-24 19:13:03 +0000725 enum State
726 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000727 VERSION_NUMBER,
728 VERSION_PROFILE,
729 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000730 };
731
732 bool valid = true;
733 int version = 0;
734 int state = VERSION_NUMBER;
735
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000736 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000737 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000738 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000739 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000740 {
741 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000742 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000743 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500744 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000745 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000746 valid = false;
747 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000748 if (valid && !token->iValue(&version))
749 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500750 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000751 token->location, token->text);
752 valid = false;
753 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000754 if (valid)
755 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000756 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
757 }
758 break;
759 case VERSION_PROFILE:
760 if (token->type != Token::IDENTIFIER || token->text != "es")
761 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500762 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000763 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000764 valid = false;
765 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000766 state = VERSION_ENDLINE;
767 break;
768 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500769 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000770 token->location, token->text);
771 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000772 break;
773 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000774
alokp@chromium.org7c884542012-05-24 19:13:03 +0000775 mTokenizer->lex(token);
776 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000777
778 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000779 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500780 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000781 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000782 valid = false;
783 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000784
alokp@chromium.org7c884542012-05-24 19:13:03 +0000785 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000786 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000787 mDirectiveHandler->handleVersion(token->location, version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000788 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000789}
790
Zhenyao Mod526f982014-05-13 14:51:19 -0700791void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000792{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000793 assert(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000794
795 enum State
796 {
797 LINE_NUMBER,
798 FILE_NUMBER
799 };
800
801 bool valid = true;
802 int line = 0, file = 0;
803 int state = LINE_NUMBER;
804
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000805 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000806 macroExpander.lex(token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000807 while ((token->type != '\n') && (token->type != Token::LAST))
808 {
809 switch (state++)
810 {
811 case LINE_NUMBER:
812 if (valid && (token->type != Token::CONST_INT))
813 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500814 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000815 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000816 valid = false;
817 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000818 if (valid && !token->iValue(&line))
819 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500820 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000821 token->location, token->text);
822 valid = false;
823 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000824 break;
825 case FILE_NUMBER:
826 if (valid && (token->type != Token::CONST_INT))
827 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500828 mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000829 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000830 valid = false;
831 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000832 if (valid && !token->iValue(&file))
833 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500834 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000835 token->location, token->text);
836 valid = false;
837 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000838 break;
839 default:
840 if (valid)
841 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500842 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000843 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000844 valid = false;
845 }
846 break;
847 }
848 macroExpander.lex(token);
849 }
850
851 if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
852 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500853 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000854 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000855 valid = false;
856 }
857 if (valid)
858 {
859 mTokenizer->setLineNumber(line);
Zhenyao Mod526f982014-05-13 14:51:19 -0700860 if (state == FILE_NUMBER + 1)
861 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000862 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000863}
864
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000865bool DirectiveParser::skipping() const
866{
Zhenyao Mod526f982014-05-13 14:51:19 -0700867 if (mConditionalStack.empty())
868 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000869
870 const ConditionalBlock& block = mConditionalStack.back();
871 return block.skipBlock || block.skipGroup;
872}
873
Zhenyao Mod526f982014-05-13 14:51:19 -0700874void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000875{
876 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000877 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000878 block.location = token->location;
879
880 if (skipping())
881 {
882 // This conditional block is inside another conditional group
883 // which is skipped. As a consequence this whole block is skipped.
884 // Be careful not to parse the conditional expression that might
885 // emit a diagnostic.
886 skipUntilEOD(mTokenizer, token);
887 block.skipBlock = true;
888 }
889 else
890 {
891 DirectiveType directive = getDirective(token);
892
893 int expression = 0;
894 switch (directive)
895 {
896 case DIRECTIVE_IF:
897 expression = parseExpressionIf(token);
898 break;
899 case DIRECTIVE_IFDEF:
900 expression = parseExpressionIfdef(token);
901 break;
902 case DIRECTIVE_IFNDEF:
903 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
904 break;
905 default:
906 assert(false);
907 break;
908 }
909 block.skipGroup = expression == 0;
910 block.foundValidGroup = expression != 0;
911 }
912 mConditionalStack.push_back(block);
913}
914
Zhenyao Mod526f982014-05-13 14:51:19 -0700915int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000916{
917 assert((getDirective(token) == DIRECTIVE_IF) ||
918 (getDirective(token) == DIRECTIVE_ELIF));
919
920 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
921 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
922 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
923
924 int expression = 0;
925 macroExpander.lex(token);
926 expressionParser.parse(token, &expression);
927
928 // Warn if there are tokens after #if expression.
929 if (!isEOD(token))
930 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500931 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000932 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000933 skipUntilEOD(mTokenizer, token);
934 }
935
936 return expression;
937}
938
Zhenyao Mod526f982014-05-13 14:51:19 -0700939int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000940{
941 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
942 (getDirective(token) == DIRECTIVE_IFNDEF));
943
944 mTokenizer->lex(token);
945 if (token->type != Token::IDENTIFIER)
946 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500947 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000948 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000949 skipUntilEOD(mTokenizer, token);
950 return 0;
951 }
952
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000953 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000954 int expression = iter != mMacroSet->end() ? 1 : 0;
955
956 // Warn if there are tokens after #ifdef expression.
957 mTokenizer->lex(token);
958 if (!isEOD(token))
959 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500960 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000961 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000962 skipUntilEOD(mTokenizer, token);
963 }
964 return expression;
965}
966
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000967} // namespace pp