blob: 203630a9cbf52349db061d4e5761afca7726d7bb [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 // Names prefixed with "GL_" are reserved.
Geoff Lang4c8cae62015-05-01 16:46:16 +0000122 if (name.substr(0, 3) == "GL_")
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000123 return true;
Geoff Lang4c8cae62015-05-01 16:46:16 +0000124
125 // Names containing two consecutive underscores are reserved.
126 if (name.find("__") != std::string::npos)
127 return true;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000128
129 return false;
130}
131
Zhenyao Mod526f982014-05-13 14:51:19 -0700132bool isMacroPredefined(const std::string &name,
133 const pp::MacroSet &macroSet)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000134{
135 pp::MacroSet::const_iterator iter = macroSet.find(name);
136 return iter != macroSet.end() ? iter->second.predefined : false;
137}
138
Zhenyao Mod526f982014-05-13 14:51:19 -0700139} // namespace anonymous
140
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000141namespace pp
142{
143
Zhenyao Mod526f982014-05-13 14:51:19 -0700144DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
145 MacroSet *macroSet,
146 Diagnostics *diagnostics,
147 DirectiveHandler *directiveHandler)
148 : mPastFirstStatement(false),
Geoff Lang06e24a72015-04-27 14:48:59 -0400149 mSeenNonPreprocessorToken(false),
Zhenyao Mod526f982014-05-13 14:51:19 -0700150 mTokenizer(tokenizer),
151 mMacroSet(macroSet),
152 mDiagnostics(diagnostics),
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400153 mDirectiveHandler(directiveHandler),
154 mShaderVersion(100)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000155{
156}
157
Zhenyao Mod526f982014-05-13 14:51:19 -0700158void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000159{
160 do
161 {
162 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000163
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000164 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000165 {
166 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000167 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000168 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400169 else if (!isEOD(token))
170 {
171 mSeenNonPreprocessorToken = true;
172 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000173
174 if (token->type == Token::LAST)
175 {
176 if (!mConditionalStack.empty())
177 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700178 const ConditionalBlock &block = mConditionalStack.back();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500179 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000180 block.location, block.type);
181 }
182 break;
183 }
184
Zhenyao Mod526f982014-05-13 14:51:19 -0700185 }
186 while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000187
188 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000189}
190
Zhenyao Mod526f982014-05-13 14:51:19 -0700191void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000192{
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000193 assert(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000194
195 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000196 if (isEOD(token))
197 {
198 // Empty Directive.
199 return;
200 }
201
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000202 DirectiveType directive = getDirective(token);
203
204 // While in an excluded conditional block/group,
205 // we only parse conditional directives.
206 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000207 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000208 skipUntilEOD(mTokenizer, token);
209 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000210 }
211
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000212 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000213 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000214 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500215 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000216 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000217 skipUntilEOD(mTokenizer, token);
218 break;
219 case DIRECTIVE_DEFINE:
220 parseDefine(token);
221 break;
222 case DIRECTIVE_UNDEF:
223 parseUndef(token);
224 break;
225 case DIRECTIVE_IF:
226 parseIf(token);
227 break;
228 case DIRECTIVE_IFDEF:
229 parseIfdef(token);
230 break;
231 case DIRECTIVE_IFNDEF:
232 parseIfndef(token);
233 break;
234 case DIRECTIVE_ELSE:
235 parseElse(token);
236 break;
237 case DIRECTIVE_ELIF:
238 parseElif(token);
239 break;
240 case DIRECTIVE_ENDIF:
241 parseEndif(token);
242 break;
243 case DIRECTIVE_ERROR:
244 parseError(token);
245 break;
246 case DIRECTIVE_PRAGMA:
247 parsePragma(token);
248 break;
249 case DIRECTIVE_EXTENSION:
250 parseExtension(token);
251 break;
252 case DIRECTIVE_VERSION:
253 parseVersion(token);
254 break;
255 case DIRECTIVE_LINE:
256 parseLine(token);
257 break;
258 default:
259 assert(false);
260 break;
261 }
262
263 skipUntilEOD(mTokenizer, token);
264 if (token->type == Token::LAST)
265 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500266 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000267 token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000268 }
269}
270
Zhenyao Mod526f982014-05-13 14:51:19 -0700271void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000272{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000273 assert(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000274
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000275 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000276 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000277 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500278 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000279 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000280 return;
281 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000282 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000283 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500284 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000285 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000286 return;
287 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000288 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000289 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500290 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000291 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000292 return;
293 }
294
295 Macro macro;
296 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000297 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000298
299 mTokenizer->lex(token);
300 if (token->type == '(' && !token->hasLeadingSpace())
301 {
302 // Function-like macro. Collect arguments.
303 macro.type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700304 do
305 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000306 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000307 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000308 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400309
310 if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
311 {
312 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
313 token->location, token->text);
314 return;
315 }
316
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000317 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000318
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000319 mTokenizer->lex(token); // Get ','.
Zhenyao Mod526f982014-05-13 14:51:19 -0700320 }
321 while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000322
323 if (token->type != ')')
324 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500325 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000326 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000327 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000328 return;
329 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000330 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000331 }
332
alokp@chromium.org7c884542012-05-24 19:13:03 +0000333 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000334 {
335 // Reset the token location because it is unnecessary in replacement
336 // list. Resetting it also allows us to reuse Token::equals() to
337 // compare macros.
338 token->location = SourceLocation();
339 macro.replacements.push_back(*token);
340 mTokenizer->lex(token);
341 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000342 if (!macro.replacements.empty())
343 {
344 // Whitespace preceding the replacement list is not considered part of
345 // the replacement list for either form of macro.
346 macro.replacements.front().setHasLeadingSpace(false);
347 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000348
349 // Check for macro redefinition.
350 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
351 if (iter != mMacroSet->end() && !macro.equals(iter->second))
352 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500353 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000354 token->location,
355 macro.name);
356 return;
357 }
358 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000359}
360
Zhenyao Mod526f982014-05-13 14:51:19 -0700361void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000362{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000363 assert(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000364
365 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000366 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000367 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500368 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000369 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000370 return;
371 }
372
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000373 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000374 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000375 {
376 if (iter->second.predefined)
377 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500378 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000379 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000380 }
381 else
382 {
383 mMacroSet->erase(iter);
384 }
385 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000386
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000387 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400388 if (!isEOD(token))
389 {
390 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
391 token->location, token->text);
392 skipUntilEOD(mTokenizer, token);
393 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000394}
395
Zhenyao Mod526f982014-05-13 14:51:19 -0700396void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000397{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000398 assert(getDirective(token) == DIRECTIVE_IF);
399 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000400}
401
Zhenyao Mod526f982014-05-13 14:51:19 -0700402void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000403{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000404 assert(getDirective(token) == DIRECTIVE_IFDEF);
405 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000406}
407
Zhenyao Mod526f982014-05-13 14:51:19 -0700408void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000409{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000410 assert(getDirective(token) == DIRECTIVE_IFNDEF);
411 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000412}
413
Zhenyao Mod526f982014-05-13 14:51:19 -0700414void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000415{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000416 assert(getDirective(token) == DIRECTIVE_ELSE);
417
418 if (mConditionalStack.empty())
419 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500420 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000421 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000422 skipUntilEOD(mTokenizer, token);
423 return;
424 }
425
Zhenyao Mod526f982014-05-13 14:51:19 -0700426 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000427 if (block.skipBlock)
428 {
429 // No diagnostics. Just skip the whole line.
430 skipUntilEOD(mTokenizer, token);
431 return;
432 }
433 if (block.foundElseGroup)
434 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500435 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000436 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000437 skipUntilEOD(mTokenizer, token);
438 return;
439 }
440
441 block.foundElseGroup = true;
442 block.skipGroup = block.foundValidGroup;
443 block.foundValidGroup = true;
444
Geoff Lang95a423d2015-04-28 11:09:45 -0400445 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000446 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000447 if (!isEOD(token))
448 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500449 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000450 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000451 skipUntilEOD(mTokenizer, token);
452 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000453}
454
Zhenyao Mod526f982014-05-13 14:51:19 -0700455void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000456{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000457 assert(getDirective(token) == DIRECTIVE_ELIF);
458
459 if (mConditionalStack.empty())
460 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500461 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000462 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000463 skipUntilEOD(mTokenizer, token);
464 return;
465 }
466
Zhenyao Mod526f982014-05-13 14:51:19 -0700467 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000468 if (block.skipBlock)
469 {
470 // No diagnostics. Just skip the whole line.
471 skipUntilEOD(mTokenizer, token);
472 return;
473 }
474 if (block.foundElseGroup)
475 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500476 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000477 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000478 skipUntilEOD(mTokenizer, token);
479 return;
480 }
481 if (block.foundValidGroup)
482 {
483 // Do not parse the expression.
484 // Also be careful not to emit a diagnostic.
485 block.skipGroup = true;
486 skipUntilEOD(mTokenizer, token);
487 return;
488 }
489
490 int expression = parseExpressionIf(token);
491 block.skipGroup = expression == 0;
492 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000493}
494
Zhenyao Mod526f982014-05-13 14:51:19 -0700495void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000496{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000497 assert(getDirective(token) == DIRECTIVE_ENDIF);
498
499 if (mConditionalStack.empty())
500 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500501 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000502 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000503 skipUntilEOD(mTokenizer, token);
504 return;
505 }
506
507 mConditionalStack.pop_back();
508
Geoff Lang95a423d2015-04-28 11:09:45 -0400509 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000510 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000511 if (!isEOD(token))
512 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500513 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000514 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000515 skipUntilEOD(mTokenizer, token);
516 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000517}
518
Zhenyao Mod526f982014-05-13 14:51:19 -0700519void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000520{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000521 assert(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000522
alokp@chromium.org2e818912012-06-29 21:26:03 +0000523 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000524 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000525 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000526 {
527 stream << *token;
528 mTokenizer->lex(token);
529 }
530 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000531}
532
alokp@chromium.org36124de82012-05-24 02:17:43 +0000533// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700534void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000535{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000536 assert(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000537
538 enum State
539 {
540 PRAGMA_NAME,
541 LEFT_PAREN,
542 PRAGMA_VALUE,
543 RIGHT_PAREN
544 };
545
546 bool valid = true;
547 std::string name, value;
548 int state = PRAGMA_NAME;
549
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000550 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700551 bool stdgl = token->text == "STDGL";
552 if (stdgl)
553 {
554 mTokenizer->lex(token);
555 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000556 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000557 {
558 switch(state++)
559 {
560 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000561 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000562 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000563 break;
564 case LEFT_PAREN:
565 valid = valid && (token->type == '(');
566 break;
567 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000568 value = token->text;
Olli Etuaho391befe2015-08-12 16:30:38 +0300569 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000570 break;
571 case RIGHT_PAREN:
572 valid = valid && (token->type == ')');
573 break;
574 default:
575 valid = false;
576 break;
577 }
578 mTokenizer->lex(token);
579 }
580
581 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
582 (state == LEFT_PAREN) || // Without value.
583 (state == RIGHT_PAREN + 1)); // With value.
584 if (!valid)
585 {
Olli Etuaho391befe2015-08-12 16:30:38 +0300586 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000587 token->location, name);
588 }
589 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
590 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700591 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000592 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000593}
594
Zhenyao Mod526f982014-05-13 14:51:19 -0700595void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000596{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000597 assert(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000598
599 enum State
600 {
601 EXT_NAME,
602 COLON,
603 EXT_BEHAVIOR
604 };
605
606 bool valid = true;
607 std::string name, behavior;
608 int state = EXT_NAME;
609
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000610 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000611 while ((token->type != '\n') && (token->type != Token::LAST))
612 {
613 switch (state++)
614 {
615 case EXT_NAME:
616 if (valid && (token->type != Token::IDENTIFIER))
617 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500618 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000619 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000620 valid = false;
621 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000622 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000623 break;
624 case COLON:
625 if (valid && (token->type != ':'))
626 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500627 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000628 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000629 valid = false;
630 }
631 break;
632 case EXT_BEHAVIOR:
633 if (valid && (token->type != Token::IDENTIFIER))
634 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500635 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000636 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000637 valid = false;
638 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000639 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000640 break;
641 default:
642 if (valid)
643 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500644 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000645 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000646 valid = false;
647 }
648 break;
649 }
650 mTokenizer->lex(token);
651 }
652 if (valid && (state != EXT_BEHAVIOR + 1))
653 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500654 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000655 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000656 valid = false;
657 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400658 if (valid && mSeenNonPreprocessorToken)
659 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400660 if (mShaderVersion >= 300)
661 {
662 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
663 token->location, token->text);
664 valid = false;
665 }
666 else
667 {
668 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
669 token->location, token->text);
670 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400671 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000672 if (valid)
673 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000674}
675
Zhenyao Mod526f982014-05-13 14:51:19 -0700676void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000677{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000678 assert(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000679
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000680 if (mPastFirstStatement)
681 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500682 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000683 token->location, token->text);
684 skipUntilEOD(mTokenizer, token);
685 return;
686 }
687
alokp@chromium.org7c884542012-05-24 19:13:03 +0000688 enum State
689 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000690 VERSION_NUMBER,
691 VERSION_PROFILE,
692 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000693 };
694
695 bool valid = true;
696 int version = 0;
697 int state = VERSION_NUMBER;
698
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000699 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000700 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000701 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000702 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000703 {
704 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000705 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000706 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500707 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000708 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000709 valid = false;
710 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000711 if (valid && !token->iValue(&version))
712 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500713 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000714 token->location, token->text);
715 valid = false;
716 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000717 if (valid)
718 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000719 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
720 }
721 break;
722 case VERSION_PROFILE:
723 if (token->type != Token::IDENTIFIER || token->text != "es")
724 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500725 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000726 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000727 valid = false;
728 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000729 state = VERSION_ENDLINE;
730 break;
731 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500732 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000733 token->location, token->text);
734 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000735 break;
736 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000737
alokp@chromium.org7c884542012-05-24 19:13:03 +0000738 mTokenizer->lex(token);
739 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000740
741 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000742 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500743 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000744 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000745 valid = false;
746 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000747
Olli Etuahoc378cd82015-05-25 15:21:44 +0300748 if (valid && version >= 300 && token->location.line > 1)
749 {
750 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3,
751 token->location, token->text);
752 valid = false;
753 }
754
alokp@chromium.org7c884542012-05-24 19:13:03 +0000755 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000756 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000757 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400758 mShaderVersion = version;
Olli Etuaho6cb4c7f2015-08-13 11:27:17 +0300759 PredefineMacro(mMacroSet, "__VERSION__", version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000760 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000761}
762
Zhenyao Mod526f982014-05-13 14:51:19 -0700763void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000764{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000765 assert(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000766
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000767 bool valid = true;
Olli Etuaho247374c2015-09-09 15:07:24 +0300768 bool parsedFileNumber = false;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000769 int line = 0, file = 0;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000770
Olli Etuaho261f5372015-09-18 10:34:31 +0300771 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);
Olli Etuaho247374c2015-09-09 15:07:24 +0300772
773 // Lex the first token after "#line" so we can check it for EOD.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000774 macroExpander.lex(token);
Olli Etuaho247374c2015-09-09 15:07:24 +0300775
776 if (isEOD(token))
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000777 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300778 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
779 valid = false;
780 }
781 else
782 {
783 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
784 ExpressionParser::ErrorSettings errorSettings;
785
786 // See GLES3 section 12.42
787 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
788
789 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
790 // The first token was lexed earlier to check if it was EOD. Include
791 // the token in parsing for a second time by setting the
792 // parsePresetToken flag to true.
793 expressionParser.parse(token, &line, true, errorSettings, &valid);
794 if (!isEOD(token) && valid)
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000795 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300796 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
797 // After parsing the line expression expressionParser has also
798 // advanced to the first token of the file expression - this is the
799 // token that makes the parser reduce the "input" rule for the line
800 // expression and stop. So we're using parsePresetToken = true here
801 // as well.
802 expressionParser.parse(token, &file, true, errorSettings, &valid);
803 parsedFileNumber = true;
804 }
805 if (!isEOD(token))
806 {
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000807 if (valid)
808 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500809 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000810 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000811 valid = false;
812 }
Olli Etuaho247374c2015-09-09 15:07:24 +0300813 skipUntilEOD(mTokenizer, token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000814 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000815 }
816
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000817 if (valid)
818 {
819 mTokenizer->setLineNumber(line);
Olli Etuaho247374c2015-09-09 15:07:24 +0300820 if (parsedFileNumber)
Zhenyao Mod526f982014-05-13 14:51:19 -0700821 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000822 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000823}
824
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000825bool DirectiveParser::skipping() const
826{
Zhenyao Mod526f982014-05-13 14:51:19 -0700827 if (mConditionalStack.empty())
828 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000829
830 const ConditionalBlock& block = mConditionalStack.back();
831 return block.skipBlock || block.skipGroup;
832}
833
Zhenyao Mod526f982014-05-13 14:51:19 -0700834void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000835{
836 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000837 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000838 block.location = token->location;
839
840 if (skipping())
841 {
842 // This conditional block is inside another conditional group
843 // which is skipped. As a consequence this whole block is skipped.
844 // Be careful not to parse the conditional expression that might
845 // emit a diagnostic.
846 skipUntilEOD(mTokenizer, token);
847 block.skipBlock = true;
848 }
849 else
850 {
851 DirectiveType directive = getDirective(token);
852
853 int expression = 0;
854 switch (directive)
855 {
856 case DIRECTIVE_IF:
857 expression = parseExpressionIf(token);
858 break;
859 case DIRECTIVE_IFDEF:
860 expression = parseExpressionIfdef(token);
861 break;
862 case DIRECTIVE_IFNDEF:
863 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
864 break;
865 default:
866 assert(false);
867 break;
868 }
869 block.skipGroup = expression == 0;
870 block.foundValidGroup = expression != 0;
871 }
872 mConditionalStack.push_back(block);
873}
874
Zhenyao Mod526f982014-05-13 14:51:19 -0700875int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000876{
877 assert((getDirective(token) == DIRECTIVE_IF) ||
878 (getDirective(token) == DIRECTIVE_ELIF));
879
Olli Etuaho261f5372015-09-18 10:34:31 +0300880 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000881 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
882
883 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300884 ExpressionParser::ErrorSettings errorSettings;
885 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
886 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
887
888 bool valid = true;
889 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000890
Geoff Lang95a423d2015-04-28 11:09:45 -0400891 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000892 if (!isEOD(token))
893 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500894 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000895 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000896 skipUntilEOD(mTokenizer, token);
897 }
898
899 return expression;
900}
901
Zhenyao Mod526f982014-05-13 14:51:19 -0700902int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000903{
904 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
905 (getDirective(token) == DIRECTIVE_IFNDEF));
906
907 mTokenizer->lex(token);
908 if (token->type != Token::IDENTIFIER)
909 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500910 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000911 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000912 skipUntilEOD(mTokenizer, token);
913 return 0;
914 }
915
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000916 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000917 int expression = iter != mMacroSet->end() ? 1 : 0;
918
Geoff Lang95a423d2015-04-28 11:09:45 -0400919 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000920 mTokenizer->lex(token);
921 if (!isEOD(token))
922 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500923 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000924 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000925 skipUntilEOD(mTokenizer, token);
926 }
927 return expression;
928}
929
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000930} // namespace pp