blob: fecfdaeacc70c0065cefb73eccbadfe68e693efb [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
144class DefinedParser : public Lexer
145{
146 public:
Zhenyao Mod526f982014-05-13 14:51:19 -0700147 DefinedParser(Lexer *lexer,
148 const MacroSet *macroSet,
149 Diagnostics *diagnostics)
150 : mLexer(lexer),
151 mMacroSet(macroSet),
152 mDiagnostics(diagnostics)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000153 {
154 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000155
156 protected:
Zhenyao Mod526f982014-05-13 14:51:19 -0700157 virtual void lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000158 {
Zhenyao Mob5e17752014-10-22 10:57:10 -0700159 const char kDefined[] = "defined";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000160
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000161 mLexer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000162 if (token->type != Token::IDENTIFIER)
163 return;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000164 if (token->text != kDefined)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000165 return;
166
167 bool paren = false;
168 mLexer->lex(token);
169 if (token->type == '(')
170 {
171 paren = true;
172 mLexer->lex(token);
173 }
174
175 if (token->type != Token::IDENTIFIER)
176 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500177 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000178 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000179 skipUntilEOD(mLexer, token);
180 return;
181 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000182 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000183 std::string expression = iter != mMacroSet->end() ? "1" : "0";
184
185 if (paren)
186 {
187 mLexer->lex(token);
188 if (token->type != ')')
189 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500190 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000191 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000192 skipUntilEOD(mLexer, token);
193 return;
194 }
195 }
196
197 // We have a valid defined operator.
198 // Convert the current token into a CONST_INT token.
199 token->type = Token::CONST_INT;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000200 token->text = expression;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000201 }
202
203 private:
Zhenyao Mod526f982014-05-13 14:51:19 -0700204 Lexer *mLexer;
205 const MacroSet *mMacroSet;
206 Diagnostics *mDiagnostics;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000207};
208
Zhenyao Mod526f982014-05-13 14:51:19 -0700209DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
210 MacroSet *macroSet,
211 Diagnostics *diagnostics,
212 DirectiveHandler *directiveHandler)
213 : mPastFirstStatement(false),
Geoff Lang06e24a72015-04-27 14:48:59 -0400214 mSeenNonPreprocessorToken(false),
Zhenyao Mod526f982014-05-13 14:51:19 -0700215 mTokenizer(tokenizer),
216 mMacroSet(macroSet),
217 mDiagnostics(diagnostics),
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400218 mDirectiveHandler(directiveHandler),
219 mShaderVersion(100)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000220{
221}
222
Zhenyao Mod526f982014-05-13 14:51:19 -0700223void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000224{
225 do
226 {
227 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000228
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000229 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000230 {
231 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000232 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000233 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400234 else if (!isEOD(token))
235 {
236 mSeenNonPreprocessorToken = true;
237 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000238
239 if (token->type == Token::LAST)
240 {
241 if (!mConditionalStack.empty())
242 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700243 const ConditionalBlock &block = mConditionalStack.back();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500244 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000245 block.location, block.type);
246 }
247 break;
248 }
249
Zhenyao Mod526f982014-05-13 14:51:19 -0700250 }
251 while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000252
253 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000254}
255
Zhenyao Mod526f982014-05-13 14:51:19 -0700256void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000257{
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000258 assert(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000259
260 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000261 if (isEOD(token))
262 {
263 // Empty Directive.
264 return;
265 }
266
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000267 DirectiveType directive = getDirective(token);
268
269 // While in an excluded conditional block/group,
270 // we only parse conditional directives.
271 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000272 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000273 skipUntilEOD(mTokenizer, token);
274 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000275 }
276
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000277 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000278 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000279 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500280 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000281 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000282 skipUntilEOD(mTokenizer, token);
283 break;
284 case DIRECTIVE_DEFINE:
285 parseDefine(token);
286 break;
287 case DIRECTIVE_UNDEF:
288 parseUndef(token);
289 break;
290 case DIRECTIVE_IF:
291 parseIf(token);
292 break;
293 case DIRECTIVE_IFDEF:
294 parseIfdef(token);
295 break;
296 case DIRECTIVE_IFNDEF:
297 parseIfndef(token);
298 break;
299 case DIRECTIVE_ELSE:
300 parseElse(token);
301 break;
302 case DIRECTIVE_ELIF:
303 parseElif(token);
304 break;
305 case DIRECTIVE_ENDIF:
306 parseEndif(token);
307 break;
308 case DIRECTIVE_ERROR:
309 parseError(token);
310 break;
311 case DIRECTIVE_PRAGMA:
312 parsePragma(token);
313 break;
314 case DIRECTIVE_EXTENSION:
315 parseExtension(token);
316 break;
317 case DIRECTIVE_VERSION:
318 parseVersion(token);
319 break;
320 case DIRECTIVE_LINE:
321 parseLine(token);
322 break;
323 default:
324 assert(false);
325 break;
326 }
327
328 skipUntilEOD(mTokenizer, token);
329 if (token->type == Token::LAST)
330 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500331 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000332 token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000333 }
334}
335
Zhenyao Mod526f982014-05-13 14:51:19 -0700336void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000337{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000338 assert(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000339
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000340 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000341 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000342 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500343 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000344 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000345 return;
346 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000347 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000348 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500349 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000350 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000351 return;
352 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000353 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000354 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500355 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000356 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000357 return;
358 }
359
360 Macro macro;
361 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000362 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000363
364 mTokenizer->lex(token);
365 if (token->type == '(' && !token->hasLeadingSpace())
366 {
367 // Function-like macro. Collect arguments.
368 macro.type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700369 do
370 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000371 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000372 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000373 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400374
375 if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
376 {
377 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
378 token->location, token->text);
379 return;
380 }
381
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000382 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000383
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000384 mTokenizer->lex(token); // Get ','.
Zhenyao Mod526f982014-05-13 14:51:19 -0700385 }
386 while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000387
388 if (token->type != ')')
389 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500390 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000391 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000392 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000393 return;
394 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000395 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000396 }
397
alokp@chromium.org7c884542012-05-24 19:13:03 +0000398 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000399 {
400 // Reset the token location because it is unnecessary in replacement
401 // list. Resetting it also allows us to reuse Token::equals() to
402 // compare macros.
403 token->location = SourceLocation();
404 macro.replacements.push_back(*token);
405 mTokenizer->lex(token);
406 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000407 if (!macro.replacements.empty())
408 {
409 // Whitespace preceding the replacement list is not considered part of
410 // the replacement list for either form of macro.
411 macro.replacements.front().setHasLeadingSpace(false);
412 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000413
414 // Check for macro redefinition.
415 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
416 if (iter != mMacroSet->end() && !macro.equals(iter->second))
417 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500418 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000419 token->location,
420 macro.name);
421 return;
422 }
423 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000424}
425
Zhenyao Mod526f982014-05-13 14:51:19 -0700426void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000427{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000428 assert(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000429
430 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000431 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000432 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500433 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000434 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000435 return;
436 }
437
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000438 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000439 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000440 {
441 if (iter->second.predefined)
442 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500443 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000444 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000445 }
446 else
447 {
448 mMacroSet->erase(iter);
449 }
450 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000451
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000452 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400453 if (!isEOD(token))
454 {
455 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
456 token->location, token->text);
457 skipUntilEOD(mTokenizer, token);
458 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000459}
460
Zhenyao Mod526f982014-05-13 14:51:19 -0700461void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000462{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000463 assert(getDirective(token) == DIRECTIVE_IF);
464 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000465}
466
Zhenyao Mod526f982014-05-13 14:51:19 -0700467void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000468{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000469 assert(getDirective(token) == DIRECTIVE_IFDEF);
470 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000471}
472
Zhenyao Mod526f982014-05-13 14:51:19 -0700473void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000474{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000475 assert(getDirective(token) == DIRECTIVE_IFNDEF);
476 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000477}
478
Zhenyao Mod526f982014-05-13 14:51:19 -0700479void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000480{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000481 assert(getDirective(token) == DIRECTIVE_ELSE);
482
483 if (mConditionalStack.empty())
484 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500485 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
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
Zhenyao Mod526f982014-05-13 14:51:19 -0700491 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000492 if (block.skipBlock)
493 {
494 // No diagnostics. Just skip the whole line.
495 skipUntilEOD(mTokenizer, token);
496 return;
497 }
498 if (block.foundElseGroup)
499 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500500 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000501 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000502 skipUntilEOD(mTokenizer, token);
503 return;
504 }
505
506 block.foundElseGroup = true;
507 block.skipGroup = block.foundValidGroup;
508 block.foundValidGroup = true;
509
Geoff Lang95a423d2015-04-28 11:09:45 -0400510 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000511 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000512 if (!isEOD(token))
513 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500514 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000515 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000516 skipUntilEOD(mTokenizer, token);
517 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000518}
519
Zhenyao Mod526f982014-05-13 14:51:19 -0700520void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000521{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000522 assert(getDirective(token) == DIRECTIVE_ELIF);
523
524 if (mConditionalStack.empty())
525 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500526 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
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
Zhenyao Mod526f982014-05-13 14:51:19 -0700532 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000533 if (block.skipBlock)
534 {
535 // No diagnostics. Just skip the whole line.
536 skipUntilEOD(mTokenizer, token);
537 return;
538 }
539 if (block.foundElseGroup)
540 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500541 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000542 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000543 skipUntilEOD(mTokenizer, token);
544 return;
545 }
546 if (block.foundValidGroup)
547 {
548 // Do not parse the expression.
549 // Also be careful not to emit a diagnostic.
550 block.skipGroup = true;
551 skipUntilEOD(mTokenizer, token);
552 return;
553 }
554
555 int expression = parseExpressionIf(token);
556 block.skipGroup = expression == 0;
557 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000558}
559
Zhenyao Mod526f982014-05-13 14:51:19 -0700560void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000561{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000562 assert(getDirective(token) == DIRECTIVE_ENDIF);
563
564 if (mConditionalStack.empty())
565 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500566 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000567 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000568 skipUntilEOD(mTokenizer, token);
569 return;
570 }
571
572 mConditionalStack.pop_back();
573
Geoff Lang95a423d2015-04-28 11:09:45 -0400574 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000575 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000576 if (!isEOD(token))
577 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500578 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000579 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000580 skipUntilEOD(mTokenizer, token);
581 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000582}
583
Zhenyao Mod526f982014-05-13 14:51:19 -0700584void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000585{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000586 assert(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000587
alokp@chromium.org2e818912012-06-29 21:26:03 +0000588 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000589 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000590 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000591 {
592 stream << *token;
593 mTokenizer->lex(token);
594 }
595 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000596}
597
alokp@chromium.org36124de82012-05-24 02:17:43 +0000598// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700599void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000600{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000601 assert(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000602
603 enum State
604 {
605 PRAGMA_NAME,
606 LEFT_PAREN,
607 PRAGMA_VALUE,
608 RIGHT_PAREN
609 };
610
611 bool valid = true;
612 std::string name, value;
613 int state = PRAGMA_NAME;
614
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000615 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700616 bool stdgl = token->text == "STDGL";
617 if (stdgl)
618 {
619 mTokenizer->lex(token);
620 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000621 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000622 {
623 switch(state++)
624 {
625 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000626 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000627 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000628 break;
629 case LEFT_PAREN:
630 valid = valid && (token->type == '(');
631 break;
632 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000633 value = token->text;
Geoff Langd3c29f52015-04-28 11:23:02 -0400634 // Pragma value validation is handled in DirectiveHandler::handlePragma
635 // because the proper pragma value is dependent on the pragma name.
alokp@chromium.org36124de82012-05-24 02:17:43 +0000636 break;
637 case RIGHT_PAREN:
638 valid = valid && (token->type == ')');
639 break;
640 default:
641 valid = false;
642 break;
643 }
644 mTokenizer->lex(token);
645 }
646
647 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
648 (state == LEFT_PAREN) || // Without value.
649 (state == RIGHT_PAREN + 1)); // With value.
650 if (!valid)
651 {
Geoff Langd3c29f52015-04-28 11:23:02 -0400652 mDiagnostics->report(Diagnostics::PP_INVALID_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000653 token->location, name);
654 }
655 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
656 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700657 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000658 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000659}
660
Zhenyao Mod526f982014-05-13 14:51:19 -0700661void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000662{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000663 assert(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000664
665 enum State
666 {
667 EXT_NAME,
668 COLON,
669 EXT_BEHAVIOR
670 };
671
672 bool valid = true;
673 std::string name, behavior;
674 int state = EXT_NAME;
675
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000676 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000677 while ((token->type != '\n') && (token->type != Token::LAST))
678 {
679 switch (state++)
680 {
681 case EXT_NAME:
682 if (valid && (token->type != Token::IDENTIFIER))
683 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500684 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000685 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000686 valid = false;
687 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000688 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000689 break;
690 case COLON:
691 if (valid && (token->type != ':'))
692 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500693 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
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 }
697 break;
698 case EXT_BEHAVIOR:
699 if (valid && (token->type != Token::IDENTIFIER))
700 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500701 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000702 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000703 valid = false;
704 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000705 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000706 break;
707 default:
708 if (valid)
709 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500710 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
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 }
714 break;
715 }
716 mTokenizer->lex(token);
717 }
718 if (valid && (state != EXT_BEHAVIOR + 1))
719 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500720 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000721 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000722 valid = false;
723 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400724 if (valid && mSeenNonPreprocessorToken)
725 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400726 if (mShaderVersion >= 300)
727 {
728 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
729 token->location, token->text);
730 valid = false;
731 }
732 else
733 {
734 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
735 token->location, token->text);
736 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400737 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000738 if (valid)
739 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000740}
741
Zhenyao Mod526f982014-05-13 14:51:19 -0700742void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000743{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000744 assert(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000745
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000746 if (mPastFirstStatement)
747 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500748 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000749 token->location, token->text);
750 skipUntilEOD(mTokenizer, token);
751 return;
752 }
753
alokp@chromium.org7c884542012-05-24 19:13:03 +0000754 enum State
755 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000756 VERSION_NUMBER,
757 VERSION_PROFILE,
758 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000759 };
760
761 bool valid = true;
762 int version = 0;
763 int state = VERSION_NUMBER;
764
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000765 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000766 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000767 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000768 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000769 {
770 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000771 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000772 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500773 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000774 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000775 valid = false;
776 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000777 if (valid && !token->iValue(&version))
778 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500779 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000780 token->location, token->text);
781 valid = false;
782 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000783 if (valid)
784 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000785 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
786 }
787 break;
788 case VERSION_PROFILE:
789 if (token->type != Token::IDENTIFIER || token->text != "es")
790 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500791 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000792 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000793 valid = false;
794 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000795 state = VERSION_ENDLINE;
796 break;
797 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500798 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000799 token->location, token->text);
800 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000801 break;
802 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000803
alokp@chromium.org7c884542012-05-24 19:13:03 +0000804 mTokenizer->lex(token);
805 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000806
807 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000808 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500809 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000810 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000811 valid = false;
812 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000813
Olli Etuahoc378cd82015-05-25 15:21:44 +0300814 if (valid && version >= 300 && token->location.line > 1)
815 {
816 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3,
817 token->location, token->text);
818 valid = false;
819 }
820
alokp@chromium.org7c884542012-05-24 19:13:03 +0000821 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000822 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000823 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400824 mShaderVersion = version;
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000825 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000826}
827
Zhenyao Mod526f982014-05-13 14:51:19 -0700828void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000829{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000830 assert(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000831
832 enum State
833 {
834 LINE_NUMBER,
835 FILE_NUMBER
836 };
837
838 bool valid = true;
839 int line = 0, file = 0;
840 int state = LINE_NUMBER;
841
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000842 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000843 macroExpander.lex(token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000844 while ((token->type != '\n') && (token->type != Token::LAST))
845 {
846 switch (state++)
847 {
848 case LINE_NUMBER:
849 if (valid && (token->type != Token::CONST_INT))
850 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500851 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000852 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000853 valid = false;
854 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000855 if (valid && !token->iValue(&line))
856 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500857 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000858 token->location, token->text);
859 valid = false;
860 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000861 break;
862 case FILE_NUMBER:
863 if (valid && (token->type != Token::CONST_INT))
864 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500865 mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000866 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000867 valid = false;
868 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000869 if (valid && !token->iValue(&file))
870 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500871 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000872 token->location, token->text);
873 valid = false;
874 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000875 break;
876 default:
877 if (valid)
878 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500879 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000880 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000881 valid = false;
882 }
883 break;
884 }
885 macroExpander.lex(token);
886 }
887
888 if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
889 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500890 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000891 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000892 valid = false;
893 }
894 if (valid)
895 {
896 mTokenizer->setLineNumber(line);
Zhenyao Mod526f982014-05-13 14:51:19 -0700897 if (state == FILE_NUMBER + 1)
898 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000899 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000900}
901
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000902bool DirectiveParser::skipping() const
903{
Zhenyao Mod526f982014-05-13 14:51:19 -0700904 if (mConditionalStack.empty())
905 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000906
907 const ConditionalBlock& block = mConditionalStack.back();
908 return block.skipBlock || block.skipGroup;
909}
910
Zhenyao Mod526f982014-05-13 14:51:19 -0700911void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000912{
913 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000914 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000915 block.location = token->location;
916
917 if (skipping())
918 {
919 // This conditional block is inside another conditional group
920 // which is skipped. As a consequence this whole block is skipped.
921 // Be careful not to parse the conditional expression that might
922 // emit a diagnostic.
923 skipUntilEOD(mTokenizer, token);
924 block.skipBlock = true;
925 }
926 else
927 {
928 DirectiveType directive = getDirective(token);
929
930 int expression = 0;
931 switch (directive)
932 {
933 case DIRECTIVE_IF:
934 expression = parseExpressionIf(token);
935 break;
936 case DIRECTIVE_IFDEF:
937 expression = parseExpressionIfdef(token);
938 break;
939 case DIRECTIVE_IFNDEF:
940 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
941 break;
942 default:
943 assert(false);
944 break;
945 }
946 block.skipGroup = expression == 0;
947 block.foundValidGroup = expression != 0;
948 }
949 mConditionalStack.push_back(block);
950}
951
Zhenyao Mod526f982014-05-13 14:51:19 -0700952int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000953{
954 assert((getDirective(token) == DIRECTIVE_IF) ||
955 (getDirective(token) == DIRECTIVE_ELIF));
956
957 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
958 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
959 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
960
961 int expression = 0;
962 macroExpander.lex(token);
963 expressionParser.parse(token, &expression);
964
Geoff Lang95a423d2015-04-28 11:09:45 -0400965 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000966 if (!isEOD(token))
967 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500968 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000969 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000970 skipUntilEOD(mTokenizer, token);
971 }
972
973 return expression;
974}
975
Zhenyao Mod526f982014-05-13 14:51:19 -0700976int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000977{
978 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
979 (getDirective(token) == DIRECTIVE_IFNDEF));
980
981 mTokenizer->lex(token);
982 if (token->type != Token::IDENTIFIER)
983 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500984 mDiagnostics->report(Diagnostics::PP_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 return 0;
988 }
989
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000990 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000991 int expression = iter != mMacroSet->end() ? 1 : 0;
992
Geoff Lang95a423d2015-04-28 11:09:45 -0400993 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000994 mTokenizer->lex(token);
995 if (!isEOD(token))
996 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500997 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000998 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000999 skipUntilEOD(mTokenizer, token);
1000 }
1001 return expression;
1002}
1003
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001004} // namespace pp