1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2011 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker
7*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/DirectiveParser.h"
8*8975f5c5SAndroid Build Coastguard Worker
9*8975f5c5SAndroid Build Coastguard Worker #include <algorithm>
10*8975f5c5SAndroid Build Coastguard Worker #include <cstdlib>
11*8975f5c5SAndroid Build Coastguard Worker #include <sstream>
12*8975f5c5SAndroid Build Coastguard Worker
13*8975f5c5SAndroid Build Coastguard Worker #include "GLSLANG/ShaderLang.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/DiagnosticsBase.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/DirectiveHandlerBase.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/ExpressionParser.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/MacroExpander.h"
19*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/Token.h"
20*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/Tokenizer.h"
21*8975f5c5SAndroid Build Coastguard Worker
22*8975f5c5SAndroid Build Coastguard Worker namespace angle
23*8975f5c5SAndroid Build Coastguard Worker {
24*8975f5c5SAndroid Build Coastguard Worker
25*8975f5c5SAndroid Build Coastguard Worker namespace
26*8975f5c5SAndroid Build Coastguard Worker {
27*8975f5c5SAndroid Build Coastguard Worker enum DirectiveType
28*8975f5c5SAndroid Build Coastguard Worker {
29*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_NONE,
30*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_DEFINE,
31*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_UNDEF,
32*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_IF,
33*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_IFDEF,
34*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_IFNDEF,
35*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_ELSE,
36*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_ELIF,
37*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_ENDIF,
38*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_ERROR,
39*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_PRAGMA,
40*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_EXTENSION,
41*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_VERSION,
42*8975f5c5SAndroid Build Coastguard Worker DIRECTIVE_LINE
43*8975f5c5SAndroid Build Coastguard Worker };
44*8975f5c5SAndroid Build Coastguard Worker
getDirective(const pp::Token * token)45*8975f5c5SAndroid Build Coastguard Worker DirectiveType getDirective(const pp::Token *token)
46*8975f5c5SAndroid Build Coastguard Worker {
47*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveDefine[] = "define";
48*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveUndef[] = "undef";
49*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveIf[] = "if";
50*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveIfdef[] = "ifdef";
51*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveIfndef[] = "ifndef";
52*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveElse[] = "else";
53*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveElif[] = "elif";
54*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveEndif[] = "endif";
55*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveError[] = "error";
56*8975f5c5SAndroid Build Coastguard Worker const char kDirectivePragma[] = "pragma";
57*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveExtension[] = "extension";
58*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveVersion[] = "version";
59*8975f5c5SAndroid Build Coastguard Worker const char kDirectiveLine[] = "line";
60*8975f5c5SAndroid Build Coastguard Worker
61*8975f5c5SAndroid Build Coastguard Worker if (token->type != pp::Token::IDENTIFIER)
62*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_NONE;
63*8975f5c5SAndroid Build Coastguard Worker
64*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveDefine)
65*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_DEFINE;
66*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveUndef)
67*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_UNDEF;
68*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveIf)
69*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_IF;
70*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveIfdef)
71*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_IFDEF;
72*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveIfndef)
73*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_IFNDEF;
74*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveElse)
75*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_ELSE;
76*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveElif)
77*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_ELIF;
78*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveEndif)
79*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_ENDIF;
80*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveError)
81*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_ERROR;
82*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectivePragma)
83*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_PRAGMA;
84*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveExtension)
85*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_EXTENSION;
86*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveVersion)
87*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_VERSION;
88*8975f5c5SAndroid Build Coastguard Worker if (token->text == kDirectiveLine)
89*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_LINE;
90*8975f5c5SAndroid Build Coastguard Worker
91*8975f5c5SAndroid Build Coastguard Worker return DIRECTIVE_NONE;
92*8975f5c5SAndroid Build Coastguard Worker }
93*8975f5c5SAndroid Build Coastguard Worker
isConditionalDirective(DirectiveType directive)94*8975f5c5SAndroid Build Coastguard Worker bool isConditionalDirective(DirectiveType directive)
95*8975f5c5SAndroid Build Coastguard Worker {
96*8975f5c5SAndroid Build Coastguard Worker switch (directive)
97*8975f5c5SAndroid Build Coastguard Worker {
98*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_IF:
99*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_IFDEF:
100*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_IFNDEF:
101*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_ELSE:
102*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_ELIF:
103*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_ENDIF:
104*8975f5c5SAndroid Build Coastguard Worker return true;
105*8975f5c5SAndroid Build Coastguard Worker default:
106*8975f5c5SAndroid Build Coastguard Worker return false;
107*8975f5c5SAndroid Build Coastguard Worker }
108*8975f5c5SAndroid Build Coastguard Worker }
109*8975f5c5SAndroid Build Coastguard Worker
110*8975f5c5SAndroid Build Coastguard Worker // Returns true if the token represents End Of Directive.
isEOD(const pp::Token * token)111*8975f5c5SAndroid Build Coastguard Worker bool isEOD(const pp::Token *token)
112*8975f5c5SAndroid Build Coastguard Worker {
113*8975f5c5SAndroid Build Coastguard Worker return (token->type == '\n') || (token->type == pp::Token::LAST);
114*8975f5c5SAndroid Build Coastguard Worker }
115*8975f5c5SAndroid Build Coastguard Worker
skipUntilEOD(pp::Lexer * lexer,pp::Token * token)116*8975f5c5SAndroid Build Coastguard Worker void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
117*8975f5c5SAndroid Build Coastguard Worker {
118*8975f5c5SAndroid Build Coastguard Worker while (!isEOD(token))
119*8975f5c5SAndroid Build Coastguard Worker {
120*8975f5c5SAndroid Build Coastguard Worker lexer->lex(token);
121*8975f5c5SAndroid Build Coastguard Worker }
122*8975f5c5SAndroid Build Coastguard Worker }
123*8975f5c5SAndroid Build Coastguard Worker
isMacroNameReserved(const std::string & name)124*8975f5c5SAndroid Build Coastguard Worker bool isMacroNameReserved(const std::string &name)
125*8975f5c5SAndroid Build Coastguard Worker {
126*8975f5c5SAndroid Build Coastguard Worker // Names prefixed with "GL_" and the name "defined" are reserved.
127*8975f5c5SAndroid Build Coastguard Worker return name == "defined" || (name.substr(0, 3) == "GL_");
128*8975f5c5SAndroid Build Coastguard Worker }
129*8975f5c5SAndroid Build Coastguard Worker
hasDoubleUnderscores(const std::string & name)130*8975f5c5SAndroid Build Coastguard Worker bool hasDoubleUnderscores(const std::string &name)
131*8975f5c5SAndroid Build Coastguard Worker {
132*8975f5c5SAndroid Build Coastguard Worker return (name.find("__") != std::string::npos);
133*8975f5c5SAndroid Build Coastguard Worker }
134*8975f5c5SAndroid Build Coastguard Worker
isMacroPredefined(const std::string & name,const pp::MacroSet & macroSet)135*8975f5c5SAndroid Build Coastguard Worker bool isMacroPredefined(const std::string &name, const pp::MacroSet ¯oSet)
136*8975f5c5SAndroid Build Coastguard Worker {
137*8975f5c5SAndroid Build Coastguard Worker pp::MacroSet::const_iterator iter = macroSet.find(name);
138*8975f5c5SAndroid Build Coastguard Worker return iter != macroSet.end() ? iter->second->predefined : false;
139*8975f5c5SAndroid Build Coastguard Worker }
140*8975f5c5SAndroid Build Coastguard Worker
141*8975f5c5SAndroid Build Coastguard Worker } // namespace
142*8975f5c5SAndroid Build Coastguard Worker
143*8975f5c5SAndroid Build Coastguard Worker namespace pp
144*8975f5c5SAndroid Build Coastguard Worker {
DirectiveParser(Tokenizer * tokenizer,MacroSet * macroSet,Diagnostics * diagnostics,DirectiveHandler * directiveHandler,const PreprocessorSettings & settings)145*8975f5c5SAndroid Build Coastguard Worker DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
146*8975f5c5SAndroid Build Coastguard Worker MacroSet *macroSet,
147*8975f5c5SAndroid Build Coastguard Worker Diagnostics *diagnostics,
148*8975f5c5SAndroid Build Coastguard Worker DirectiveHandler *directiveHandler,
149*8975f5c5SAndroid Build Coastguard Worker const PreprocessorSettings &settings)
150*8975f5c5SAndroid Build Coastguard Worker : mHandledVersion(false),
151*8975f5c5SAndroid Build Coastguard Worker mPastFirstStatement(false),
152*8975f5c5SAndroid Build Coastguard Worker mSeenNonPreprocessorToken(false),
153*8975f5c5SAndroid Build Coastguard Worker mTokenizer(tokenizer),
154*8975f5c5SAndroid Build Coastguard Worker mMacroSet(macroSet),
155*8975f5c5SAndroid Build Coastguard Worker mDiagnostics(diagnostics),
156*8975f5c5SAndroid Build Coastguard Worker mDirectiveHandler(directiveHandler),
157*8975f5c5SAndroid Build Coastguard Worker mShaderVersion(100),
158*8975f5c5SAndroid Build Coastguard Worker mSettings(settings)
159*8975f5c5SAndroid Build Coastguard Worker {}
160*8975f5c5SAndroid Build Coastguard Worker
~DirectiveParser()161*8975f5c5SAndroid Build Coastguard Worker DirectiveParser::~DirectiveParser() {}
162*8975f5c5SAndroid Build Coastguard Worker
lex(Token * token)163*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::lex(Token *token)
164*8975f5c5SAndroid Build Coastguard Worker {
165*8975f5c5SAndroid Build Coastguard Worker do
166*8975f5c5SAndroid Build Coastguard Worker {
167*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
168*8975f5c5SAndroid Build Coastguard Worker
169*8975f5c5SAndroid Build Coastguard Worker if (token->type == Token::PP_HASH)
170*8975f5c5SAndroid Build Coastguard Worker {
171*8975f5c5SAndroid Build Coastguard Worker parseDirective(token);
172*8975f5c5SAndroid Build Coastguard Worker mPastFirstStatement = true;
173*8975f5c5SAndroid Build Coastguard Worker }
174*8975f5c5SAndroid Build Coastguard Worker else if (!isEOD(token) && !skipping())
175*8975f5c5SAndroid Build Coastguard Worker {
176*8975f5c5SAndroid Build Coastguard Worker mSeenNonPreprocessorToken = true;
177*8975f5c5SAndroid Build Coastguard Worker if (!mHandledVersion)
178*8975f5c5SAndroid Build Coastguard Worker {
179*8975f5c5SAndroid Build Coastguard Worker // If #version does not appear before first token, then this is
180*8975f5c5SAndroid Build Coastguard Worker // an ESSL1 shader without a version directive
181*8975f5c5SAndroid Build Coastguard Worker handleVersion(token->location);
182*8975f5c5SAndroid Build Coastguard Worker }
183*8975f5c5SAndroid Build Coastguard Worker }
184*8975f5c5SAndroid Build Coastguard Worker
185*8975f5c5SAndroid Build Coastguard Worker if (token->type == Token::LAST)
186*8975f5c5SAndroid Build Coastguard Worker {
187*8975f5c5SAndroid Build Coastguard Worker if (!mConditionalStack.empty())
188*8975f5c5SAndroid Build Coastguard Worker {
189*8975f5c5SAndroid Build Coastguard Worker const ConditionalBlock &block = mConditionalStack.back();
190*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location,
191*8975f5c5SAndroid Build Coastguard Worker block.type);
192*8975f5c5SAndroid Build Coastguard Worker }
193*8975f5c5SAndroid Build Coastguard Worker break;
194*8975f5c5SAndroid Build Coastguard Worker }
195*8975f5c5SAndroid Build Coastguard Worker
196*8975f5c5SAndroid Build Coastguard Worker } while (skipping() || (token->type == '\n'));
197*8975f5c5SAndroid Build Coastguard Worker
198*8975f5c5SAndroid Build Coastguard Worker mPastFirstStatement = true;
199*8975f5c5SAndroid Build Coastguard Worker }
200*8975f5c5SAndroid Build Coastguard Worker
parseDirective(Token * token)201*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseDirective(Token *token)
202*8975f5c5SAndroid Build Coastguard Worker {
203*8975f5c5SAndroid Build Coastguard Worker ASSERT(token->type == Token::PP_HASH);
204*8975f5c5SAndroid Build Coastguard Worker
205*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
206*8975f5c5SAndroid Build Coastguard Worker if (isEOD(token))
207*8975f5c5SAndroid Build Coastguard Worker {
208*8975f5c5SAndroid Build Coastguard Worker // Empty Directive.
209*8975f5c5SAndroid Build Coastguard Worker return;
210*8975f5c5SAndroid Build Coastguard Worker }
211*8975f5c5SAndroid Build Coastguard Worker
212*8975f5c5SAndroid Build Coastguard Worker DirectiveType directive = getDirective(token);
213*8975f5c5SAndroid Build Coastguard Worker
214*8975f5c5SAndroid Build Coastguard Worker if (!mHandledVersion && directive != DIRECTIVE_VERSION)
215*8975f5c5SAndroid Build Coastguard Worker {
216*8975f5c5SAndroid Build Coastguard Worker // If first directive is not #version, then this is an ESSL1 shader
217*8975f5c5SAndroid Build Coastguard Worker // without a version directive
218*8975f5c5SAndroid Build Coastguard Worker handleVersion(token->location);
219*8975f5c5SAndroid Build Coastguard Worker }
220*8975f5c5SAndroid Build Coastguard Worker
221*8975f5c5SAndroid Build Coastguard Worker // While in an excluded conditional block/group,
222*8975f5c5SAndroid Build Coastguard Worker // we only parse conditional directives.
223*8975f5c5SAndroid Build Coastguard Worker if (skipping() && !isConditionalDirective(directive))
224*8975f5c5SAndroid Build Coastguard Worker {
225*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
226*8975f5c5SAndroid Build Coastguard Worker return;
227*8975f5c5SAndroid Build Coastguard Worker }
228*8975f5c5SAndroid Build Coastguard Worker
229*8975f5c5SAndroid Build Coastguard Worker switch (directive)
230*8975f5c5SAndroid Build Coastguard Worker {
231*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_NONE:
232*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location,
233*8975f5c5SAndroid Build Coastguard Worker token->text);
234*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
235*8975f5c5SAndroid Build Coastguard Worker break;
236*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_DEFINE:
237*8975f5c5SAndroid Build Coastguard Worker parseDefine(token);
238*8975f5c5SAndroid Build Coastguard Worker break;
239*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_UNDEF:
240*8975f5c5SAndroid Build Coastguard Worker parseUndef(token);
241*8975f5c5SAndroid Build Coastguard Worker break;
242*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_IF:
243*8975f5c5SAndroid Build Coastguard Worker parseIf(token);
244*8975f5c5SAndroid Build Coastguard Worker break;
245*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_IFDEF:
246*8975f5c5SAndroid Build Coastguard Worker parseIfdef(token);
247*8975f5c5SAndroid Build Coastguard Worker break;
248*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_IFNDEF:
249*8975f5c5SAndroid Build Coastguard Worker parseIfndef(token);
250*8975f5c5SAndroid Build Coastguard Worker break;
251*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_ELSE:
252*8975f5c5SAndroid Build Coastguard Worker parseElse(token);
253*8975f5c5SAndroid Build Coastguard Worker break;
254*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_ELIF:
255*8975f5c5SAndroid Build Coastguard Worker parseElif(token);
256*8975f5c5SAndroid Build Coastguard Worker break;
257*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_ENDIF:
258*8975f5c5SAndroid Build Coastguard Worker parseEndif(token);
259*8975f5c5SAndroid Build Coastguard Worker break;
260*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_ERROR:
261*8975f5c5SAndroid Build Coastguard Worker parseError(token);
262*8975f5c5SAndroid Build Coastguard Worker break;
263*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_PRAGMA:
264*8975f5c5SAndroid Build Coastguard Worker parsePragma(token);
265*8975f5c5SAndroid Build Coastguard Worker break;
266*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_EXTENSION:
267*8975f5c5SAndroid Build Coastguard Worker parseExtension(token);
268*8975f5c5SAndroid Build Coastguard Worker break;
269*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_VERSION:
270*8975f5c5SAndroid Build Coastguard Worker parseVersion(token);
271*8975f5c5SAndroid Build Coastguard Worker break;
272*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_LINE:
273*8975f5c5SAndroid Build Coastguard Worker parseLine(token);
274*8975f5c5SAndroid Build Coastguard Worker break;
275*8975f5c5SAndroid Build Coastguard Worker default:
276*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE();
277*8975f5c5SAndroid Build Coastguard Worker break;
278*8975f5c5SAndroid Build Coastguard Worker }
279*8975f5c5SAndroid Build Coastguard Worker
280*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
281*8975f5c5SAndroid Build Coastguard Worker if (token->type == Token::LAST)
282*8975f5c5SAndroid Build Coastguard Worker {
283*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text);
284*8975f5c5SAndroid Build Coastguard Worker }
285*8975f5c5SAndroid Build Coastguard Worker }
286*8975f5c5SAndroid Build Coastguard Worker
parseDefine(Token * token)287*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseDefine(Token *token)
288*8975f5c5SAndroid Build Coastguard Worker {
289*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
290*8975f5c5SAndroid Build Coastguard Worker
291*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
292*8975f5c5SAndroid Build Coastguard Worker if (token->type != Token::IDENTIFIER)
293*8975f5c5SAndroid Build Coastguard Worker {
294*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
295*8975f5c5SAndroid Build Coastguard Worker return;
296*8975f5c5SAndroid Build Coastguard Worker }
297*8975f5c5SAndroid Build Coastguard Worker if (isMacroPredefined(token->text, *mMacroSet))
298*8975f5c5SAndroid Build Coastguard Worker {
299*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location,
300*8975f5c5SAndroid Build Coastguard Worker token->text);
301*8975f5c5SAndroid Build Coastguard Worker return;
302*8975f5c5SAndroid Build Coastguard Worker }
303*8975f5c5SAndroid Build Coastguard Worker if (isMacroNameReserved(token->text))
304*8975f5c5SAndroid Build Coastguard Worker {
305*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text);
306*8975f5c5SAndroid Build Coastguard Worker return;
307*8975f5c5SAndroid Build Coastguard Worker }
308*8975f5c5SAndroid Build Coastguard Worker // Using double underscores is allowed, but may result in unintended
309*8975f5c5SAndroid Build Coastguard Worker // behavior, so a warning is issued. At the time of writing this was
310*8975f5c5SAndroid Build Coastguard Worker // specified in ESSL 3.10, but the intent judging from Khronos
311*8975f5c5SAndroid Build Coastguard Worker // discussions and dEQP tests was that double underscores should be
312*8975f5c5SAndroid Build Coastguard Worker // allowed in earlier ESSL versions too.
313*8975f5c5SAndroid Build Coastguard Worker if (hasDoubleUnderscores(token->text))
314*8975f5c5SAndroid Build Coastguard Worker {
315*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
316*8975f5c5SAndroid Build Coastguard Worker token->text);
317*8975f5c5SAndroid Build Coastguard Worker }
318*8975f5c5SAndroid Build Coastguard Worker
319*8975f5c5SAndroid Build Coastguard Worker std::shared_ptr<Macro> macro = std::make_shared<Macro>();
320*8975f5c5SAndroid Build Coastguard Worker macro->type = Macro::kTypeObj;
321*8975f5c5SAndroid Build Coastguard Worker macro->name = token->text;
322*8975f5c5SAndroid Build Coastguard Worker
323*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
324*8975f5c5SAndroid Build Coastguard Worker if (token->type == '(' && !token->hasLeadingSpace())
325*8975f5c5SAndroid Build Coastguard Worker {
326*8975f5c5SAndroid Build Coastguard Worker // Function-like macro. Collect arguments.
327*8975f5c5SAndroid Build Coastguard Worker macro->type = Macro::kTypeFunc;
328*8975f5c5SAndroid Build Coastguard Worker do
329*8975f5c5SAndroid Build Coastguard Worker {
330*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
331*8975f5c5SAndroid Build Coastguard Worker if (token->type != Token::IDENTIFIER)
332*8975f5c5SAndroid Build Coastguard Worker break;
333*8975f5c5SAndroid Build Coastguard Worker
334*8975f5c5SAndroid Build Coastguard Worker if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) !=
335*8975f5c5SAndroid Build Coastguard Worker macro->parameters.end())
336*8975f5c5SAndroid Build Coastguard Worker {
337*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
338*8975f5c5SAndroid Build Coastguard Worker token->location, token->text);
339*8975f5c5SAndroid Build Coastguard Worker return;
340*8975f5c5SAndroid Build Coastguard Worker }
341*8975f5c5SAndroid Build Coastguard Worker
342*8975f5c5SAndroid Build Coastguard Worker macro->parameters.push_back(token->text);
343*8975f5c5SAndroid Build Coastguard Worker
344*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token); // Get ','.
345*8975f5c5SAndroid Build Coastguard Worker } while (token->type == ',');
346*8975f5c5SAndroid Build Coastguard Worker
347*8975f5c5SAndroid Build Coastguard Worker if (token->type != ')')
348*8975f5c5SAndroid Build Coastguard Worker {
349*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
350*8975f5c5SAndroid Build Coastguard Worker return;
351*8975f5c5SAndroid Build Coastguard Worker }
352*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token); // Get ')'.
353*8975f5c5SAndroid Build Coastguard Worker }
354*8975f5c5SAndroid Build Coastguard Worker
355*8975f5c5SAndroid Build Coastguard Worker while ((token->type != '\n') && (token->type != Token::LAST))
356*8975f5c5SAndroid Build Coastguard Worker {
357*8975f5c5SAndroid Build Coastguard Worker // Reset the token location because it is unnecessary in replacement
358*8975f5c5SAndroid Build Coastguard Worker // list. Resetting it also allows us to reuse Token::equals() to
359*8975f5c5SAndroid Build Coastguard Worker // compare macros.
360*8975f5c5SAndroid Build Coastguard Worker token->location = SourceLocation();
361*8975f5c5SAndroid Build Coastguard Worker macro->replacements.push_back(*token);
362*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
363*8975f5c5SAndroid Build Coastguard Worker }
364*8975f5c5SAndroid Build Coastguard Worker if (!macro->replacements.empty())
365*8975f5c5SAndroid Build Coastguard Worker {
366*8975f5c5SAndroid Build Coastguard Worker // Whitespace preceding the replacement list is not considered part of
367*8975f5c5SAndroid Build Coastguard Worker // the replacement list for either form of macro.
368*8975f5c5SAndroid Build Coastguard Worker macro->replacements.front().setHasLeadingSpace(false);
369*8975f5c5SAndroid Build Coastguard Worker }
370*8975f5c5SAndroid Build Coastguard Worker
371*8975f5c5SAndroid Build Coastguard Worker // Check for macro redefinition.
372*8975f5c5SAndroid Build Coastguard Worker MacroSet::const_iterator iter = mMacroSet->find(macro->name);
373*8975f5c5SAndroid Build Coastguard Worker if (iter != mMacroSet->end() && !macro->equals(*iter->second))
374*8975f5c5SAndroid Build Coastguard Worker {
375*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);
376*8975f5c5SAndroid Build Coastguard Worker return;
377*8975f5c5SAndroid Build Coastguard Worker }
378*8975f5c5SAndroid Build Coastguard Worker mMacroSet->insert(std::make_pair(macro->name, macro));
379*8975f5c5SAndroid Build Coastguard Worker }
380*8975f5c5SAndroid Build Coastguard Worker
parseUndef(Token * token)381*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseUndef(Token *token)
382*8975f5c5SAndroid Build Coastguard Worker {
383*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
384*8975f5c5SAndroid Build Coastguard Worker
385*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
386*8975f5c5SAndroid Build Coastguard Worker if (token->type != Token::IDENTIFIER)
387*8975f5c5SAndroid Build Coastguard Worker {
388*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
389*8975f5c5SAndroid Build Coastguard Worker return;
390*8975f5c5SAndroid Build Coastguard Worker }
391*8975f5c5SAndroid Build Coastguard Worker
392*8975f5c5SAndroid Build Coastguard Worker MacroSet::iterator iter = mMacroSet->find(token->text);
393*8975f5c5SAndroid Build Coastguard Worker if (iter != mMacroSet->end())
394*8975f5c5SAndroid Build Coastguard Worker {
395*8975f5c5SAndroid Build Coastguard Worker if (iter->second->predefined)
396*8975f5c5SAndroid Build Coastguard Worker {
397*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location,
398*8975f5c5SAndroid Build Coastguard Worker token->text);
399*8975f5c5SAndroid Build Coastguard Worker return;
400*8975f5c5SAndroid Build Coastguard Worker }
401*8975f5c5SAndroid Build Coastguard Worker else if (iter->second->expansionCount > 0)
402*8975f5c5SAndroid Build Coastguard Worker {
403*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
404*8975f5c5SAndroid Build Coastguard Worker token->text);
405*8975f5c5SAndroid Build Coastguard Worker return;
406*8975f5c5SAndroid Build Coastguard Worker }
407*8975f5c5SAndroid Build Coastguard Worker else
408*8975f5c5SAndroid Build Coastguard Worker {
409*8975f5c5SAndroid Build Coastguard Worker mMacroSet->erase(iter);
410*8975f5c5SAndroid Build Coastguard Worker }
411*8975f5c5SAndroid Build Coastguard Worker }
412*8975f5c5SAndroid Build Coastguard Worker
413*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
414*8975f5c5SAndroid Build Coastguard Worker if (!isEOD(token))
415*8975f5c5SAndroid Build Coastguard Worker {
416*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
417*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
418*8975f5c5SAndroid Build Coastguard Worker }
419*8975f5c5SAndroid Build Coastguard Worker }
420*8975f5c5SAndroid Build Coastguard Worker
parseIf(Token * token)421*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseIf(Token *token)
422*8975f5c5SAndroid Build Coastguard Worker {
423*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_IF);
424*8975f5c5SAndroid Build Coastguard Worker parseConditionalIf(token);
425*8975f5c5SAndroid Build Coastguard Worker }
426*8975f5c5SAndroid Build Coastguard Worker
parseIfdef(Token * token)427*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseIfdef(Token *token)
428*8975f5c5SAndroid Build Coastguard Worker {
429*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
430*8975f5c5SAndroid Build Coastguard Worker parseConditionalIf(token);
431*8975f5c5SAndroid Build Coastguard Worker }
432*8975f5c5SAndroid Build Coastguard Worker
parseIfndef(Token * token)433*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseIfndef(Token *token)
434*8975f5c5SAndroid Build Coastguard Worker {
435*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
436*8975f5c5SAndroid Build Coastguard Worker parseConditionalIf(token);
437*8975f5c5SAndroid Build Coastguard Worker }
438*8975f5c5SAndroid Build Coastguard Worker
parseElse(Token * token)439*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseElse(Token *token)
440*8975f5c5SAndroid Build Coastguard Worker {
441*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_ELSE);
442*8975f5c5SAndroid Build Coastguard Worker
443*8975f5c5SAndroid Build Coastguard Worker if (mConditionalStack.empty())
444*8975f5c5SAndroid Build Coastguard Worker {
445*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location,
446*8975f5c5SAndroid Build Coastguard Worker token->text);
447*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
448*8975f5c5SAndroid Build Coastguard Worker return;
449*8975f5c5SAndroid Build Coastguard Worker }
450*8975f5c5SAndroid Build Coastguard Worker
451*8975f5c5SAndroid Build Coastguard Worker ConditionalBlock &block = mConditionalStack.back();
452*8975f5c5SAndroid Build Coastguard Worker if (block.skipBlock)
453*8975f5c5SAndroid Build Coastguard Worker {
454*8975f5c5SAndroid Build Coastguard Worker // No diagnostics. Just skip the whole line.
455*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
456*8975f5c5SAndroid Build Coastguard Worker return;
457*8975f5c5SAndroid Build Coastguard Worker }
458*8975f5c5SAndroid Build Coastguard Worker if (block.foundElseGroup)
459*8975f5c5SAndroid Build Coastguard Worker {
460*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location,
461*8975f5c5SAndroid Build Coastguard Worker token->text);
462*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
463*8975f5c5SAndroid Build Coastguard Worker return;
464*8975f5c5SAndroid Build Coastguard Worker }
465*8975f5c5SAndroid Build Coastguard Worker
466*8975f5c5SAndroid Build Coastguard Worker block.foundElseGroup = true;
467*8975f5c5SAndroid Build Coastguard Worker block.skipGroup = block.foundValidGroup;
468*8975f5c5SAndroid Build Coastguard Worker block.foundValidGroup = true;
469*8975f5c5SAndroid Build Coastguard Worker
470*8975f5c5SAndroid Build Coastguard Worker // Check if there are extra tokens after #else.
471*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
472*8975f5c5SAndroid Build Coastguard Worker if (!isEOD(token))
473*8975f5c5SAndroid Build Coastguard Worker {
474*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
475*8975f5c5SAndroid Build Coastguard Worker token->text);
476*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
477*8975f5c5SAndroid Build Coastguard Worker }
478*8975f5c5SAndroid Build Coastguard Worker }
479*8975f5c5SAndroid Build Coastguard Worker
parseElif(Token * token)480*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseElif(Token *token)
481*8975f5c5SAndroid Build Coastguard Worker {
482*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_ELIF);
483*8975f5c5SAndroid Build Coastguard Worker
484*8975f5c5SAndroid Build Coastguard Worker if (mConditionalStack.empty())
485*8975f5c5SAndroid Build Coastguard Worker {
486*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location,
487*8975f5c5SAndroid Build Coastguard Worker token->text);
488*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
489*8975f5c5SAndroid Build Coastguard Worker return;
490*8975f5c5SAndroid Build Coastguard Worker }
491*8975f5c5SAndroid Build Coastguard Worker
492*8975f5c5SAndroid Build Coastguard Worker ConditionalBlock &block = mConditionalStack.back();
493*8975f5c5SAndroid Build Coastguard Worker if (block.skipBlock)
494*8975f5c5SAndroid Build Coastguard Worker {
495*8975f5c5SAndroid Build Coastguard Worker // No diagnostics. Just skip the whole line.
496*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
497*8975f5c5SAndroid Build Coastguard Worker return;
498*8975f5c5SAndroid Build Coastguard Worker }
499*8975f5c5SAndroid Build Coastguard Worker if (block.foundElseGroup)
500*8975f5c5SAndroid Build Coastguard Worker {
501*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location,
502*8975f5c5SAndroid Build Coastguard Worker token->text);
503*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
504*8975f5c5SAndroid Build Coastguard Worker return;
505*8975f5c5SAndroid Build Coastguard Worker }
506*8975f5c5SAndroid Build Coastguard Worker if (block.foundValidGroup)
507*8975f5c5SAndroid Build Coastguard Worker {
508*8975f5c5SAndroid Build Coastguard Worker // Do not parse the expression.
509*8975f5c5SAndroid Build Coastguard Worker // Also be careful not to emit a diagnostic.
510*8975f5c5SAndroid Build Coastguard Worker block.skipGroup = true;
511*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
512*8975f5c5SAndroid Build Coastguard Worker return;
513*8975f5c5SAndroid Build Coastguard Worker }
514*8975f5c5SAndroid Build Coastguard Worker
515*8975f5c5SAndroid Build Coastguard Worker int expression = parseExpressionIf(token);
516*8975f5c5SAndroid Build Coastguard Worker block.skipGroup = expression == 0;
517*8975f5c5SAndroid Build Coastguard Worker block.foundValidGroup = expression != 0;
518*8975f5c5SAndroid Build Coastguard Worker }
519*8975f5c5SAndroid Build Coastguard Worker
parseEndif(Token * token)520*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseEndif(Token *token)
521*8975f5c5SAndroid Build Coastguard Worker {
522*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
523*8975f5c5SAndroid Build Coastguard Worker
524*8975f5c5SAndroid Build Coastguard Worker if (mConditionalStack.empty())
525*8975f5c5SAndroid Build Coastguard Worker {
526*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location,
527*8975f5c5SAndroid Build Coastguard Worker token->text);
528*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
529*8975f5c5SAndroid Build Coastguard Worker return;
530*8975f5c5SAndroid Build Coastguard Worker }
531*8975f5c5SAndroid Build Coastguard Worker
532*8975f5c5SAndroid Build Coastguard Worker mConditionalStack.pop_back();
533*8975f5c5SAndroid Build Coastguard Worker
534*8975f5c5SAndroid Build Coastguard Worker // Check if there are tokens after #endif.
535*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
536*8975f5c5SAndroid Build Coastguard Worker if (!isEOD(token))
537*8975f5c5SAndroid Build Coastguard Worker {
538*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
539*8975f5c5SAndroid Build Coastguard Worker token->text);
540*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
541*8975f5c5SAndroid Build Coastguard Worker }
542*8975f5c5SAndroid Build Coastguard Worker }
543*8975f5c5SAndroid Build Coastguard Worker
parseError(Token * token)544*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseError(Token *token)
545*8975f5c5SAndroid Build Coastguard Worker {
546*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_ERROR);
547*8975f5c5SAndroid Build Coastguard Worker
548*8975f5c5SAndroid Build Coastguard Worker std::ostringstream stream;
549*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
550*8975f5c5SAndroid Build Coastguard Worker while ((token->type != '\n') && (token->type != Token::LAST))
551*8975f5c5SAndroid Build Coastguard Worker {
552*8975f5c5SAndroid Build Coastguard Worker stream << *token;
553*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
554*8975f5c5SAndroid Build Coastguard Worker }
555*8975f5c5SAndroid Build Coastguard Worker mDirectiveHandler->handleError(token->location, stream.str());
556*8975f5c5SAndroid Build Coastguard Worker }
557*8975f5c5SAndroid Build Coastguard Worker
558*8975f5c5SAndroid Build Coastguard Worker // Parses pragma of form: #pragma name[(value)].
parsePragma(Token * token)559*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parsePragma(Token *token)
560*8975f5c5SAndroid Build Coastguard Worker {
561*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
562*8975f5c5SAndroid Build Coastguard Worker
563*8975f5c5SAndroid Build Coastguard Worker enum State
564*8975f5c5SAndroid Build Coastguard Worker {
565*8975f5c5SAndroid Build Coastguard Worker PRAGMA_NAME,
566*8975f5c5SAndroid Build Coastguard Worker LEFT_PAREN,
567*8975f5c5SAndroid Build Coastguard Worker PRAGMA_VALUE,
568*8975f5c5SAndroid Build Coastguard Worker RIGHT_PAREN
569*8975f5c5SAndroid Build Coastguard Worker };
570*8975f5c5SAndroid Build Coastguard Worker
571*8975f5c5SAndroid Build Coastguard Worker bool valid = true;
572*8975f5c5SAndroid Build Coastguard Worker std::string name, value;
573*8975f5c5SAndroid Build Coastguard Worker int state = PRAGMA_NAME;
574*8975f5c5SAndroid Build Coastguard Worker
575*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
576*8975f5c5SAndroid Build Coastguard Worker bool stdgl = token->text == "STDGL";
577*8975f5c5SAndroid Build Coastguard Worker if (stdgl)
578*8975f5c5SAndroid Build Coastguard Worker {
579*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
580*8975f5c5SAndroid Build Coastguard Worker }
581*8975f5c5SAndroid Build Coastguard Worker while ((token->type != '\n') && (token->type != Token::LAST))
582*8975f5c5SAndroid Build Coastguard Worker {
583*8975f5c5SAndroid Build Coastguard Worker switch (state++)
584*8975f5c5SAndroid Build Coastguard Worker {
585*8975f5c5SAndroid Build Coastguard Worker case PRAGMA_NAME:
586*8975f5c5SAndroid Build Coastguard Worker name = token->text;
587*8975f5c5SAndroid Build Coastguard Worker valid = valid && (token->type == Token::IDENTIFIER);
588*8975f5c5SAndroid Build Coastguard Worker break;
589*8975f5c5SAndroid Build Coastguard Worker case LEFT_PAREN:
590*8975f5c5SAndroid Build Coastguard Worker valid = valid && (token->type == '(');
591*8975f5c5SAndroid Build Coastguard Worker break;
592*8975f5c5SAndroid Build Coastguard Worker case PRAGMA_VALUE:
593*8975f5c5SAndroid Build Coastguard Worker value = token->text;
594*8975f5c5SAndroid Build Coastguard Worker valid = valid && (token->type == Token::IDENTIFIER);
595*8975f5c5SAndroid Build Coastguard Worker break;
596*8975f5c5SAndroid Build Coastguard Worker case RIGHT_PAREN:
597*8975f5c5SAndroid Build Coastguard Worker valid = valid && (token->type == ')');
598*8975f5c5SAndroid Build Coastguard Worker break;
599*8975f5c5SAndroid Build Coastguard Worker default:
600*8975f5c5SAndroid Build Coastguard Worker valid = false;
601*8975f5c5SAndroid Build Coastguard Worker break;
602*8975f5c5SAndroid Build Coastguard Worker }
603*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
604*8975f5c5SAndroid Build Coastguard Worker }
605*8975f5c5SAndroid Build Coastguard Worker
606*8975f5c5SAndroid Build Coastguard Worker valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
607*8975f5c5SAndroid Build Coastguard Worker (state == LEFT_PAREN) || // Without value.
608*8975f5c5SAndroid Build Coastguard Worker (state == RIGHT_PAREN + 1)); // With value.
609*8975f5c5SAndroid Build Coastguard Worker if (!valid)
610*8975f5c5SAndroid Build Coastguard Worker {
611*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
612*8975f5c5SAndroid Build Coastguard Worker }
613*8975f5c5SAndroid Build Coastguard Worker else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
614*8975f5c5SAndroid Build Coastguard Worker {
615*8975f5c5SAndroid Build Coastguard Worker mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
616*8975f5c5SAndroid Build Coastguard Worker }
617*8975f5c5SAndroid Build Coastguard Worker }
618*8975f5c5SAndroid Build Coastguard Worker
parseExtension(Token * token)619*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseExtension(Token *token)
620*8975f5c5SAndroid Build Coastguard Worker {
621*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
622*8975f5c5SAndroid Build Coastguard Worker
623*8975f5c5SAndroid Build Coastguard Worker enum State
624*8975f5c5SAndroid Build Coastguard Worker {
625*8975f5c5SAndroid Build Coastguard Worker EXT_NAME,
626*8975f5c5SAndroid Build Coastguard Worker COLON,
627*8975f5c5SAndroid Build Coastguard Worker EXT_BEHAVIOR
628*8975f5c5SAndroid Build Coastguard Worker };
629*8975f5c5SAndroid Build Coastguard Worker
630*8975f5c5SAndroid Build Coastguard Worker bool valid = true;
631*8975f5c5SAndroid Build Coastguard Worker std::string name, behavior;
632*8975f5c5SAndroid Build Coastguard Worker int state = EXT_NAME;
633*8975f5c5SAndroid Build Coastguard Worker
634*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
635*8975f5c5SAndroid Build Coastguard Worker while ((token->type != '\n') && (token->type != Token::LAST))
636*8975f5c5SAndroid Build Coastguard Worker {
637*8975f5c5SAndroid Build Coastguard Worker switch (state++)
638*8975f5c5SAndroid Build Coastguard Worker {
639*8975f5c5SAndroid Build Coastguard Worker case EXT_NAME:
640*8975f5c5SAndroid Build Coastguard Worker if (valid && (token->type != Token::IDENTIFIER))
641*8975f5c5SAndroid Build Coastguard Worker {
642*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
643*8975f5c5SAndroid Build Coastguard Worker token->text);
644*8975f5c5SAndroid Build Coastguard Worker valid = false;
645*8975f5c5SAndroid Build Coastguard Worker }
646*8975f5c5SAndroid Build Coastguard Worker if (valid)
647*8975f5c5SAndroid Build Coastguard Worker name = token->text;
648*8975f5c5SAndroid Build Coastguard Worker break;
649*8975f5c5SAndroid Build Coastguard Worker case COLON:
650*8975f5c5SAndroid Build Coastguard Worker if (valid && (token->type != ':'))
651*8975f5c5SAndroid Build Coastguard Worker {
652*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
653*8975f5c5SAndroid Build Coastguard Worker token->text);
654*8975f5c5SAndroid Build Coastguard Worker valid = false;
655*8975f5c5SAndroid Build Coastguard Worker }
656*8975f5c5SAndroid Build Coastguard Worker break;
657*8975f5c5SAndroid Build Coastguard Worker case EXT_BEHAVIOR:
658*8975f5c5SAndroid Build Coastguard Worker if (valid && (token->type != Token::IDENTIFIER))
659*8975f5c5SAndroid Build Coastguard Worker {
660*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
661*8975f5c5SAndroid Build Coastguard Worker token->location, token->text);
662*8975f5c5SAndroid Build Coastguard Worker valid = false;
663*8975f5c5SAndroid Build Coastguard Worker }
664*8975f5c5SAndroid Build Coastguard Worker if (valid)
665*8975f5c5SAndroid Build Coastguard Worker behavior = token->text;
666*8975f5c5SAndroid Build Coastguard Worker break;
667*8975f5c5SAndroid Build Coastguard Worker default:
668*8975f5c5SAndroid Build Coastguard Worker if (valid)
669*8975f5c5SAndroid Build Coastguard Worker {
670*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
671*8975f5c5SAndroid Build Coastguard Worker token->text);
672*8975f5c5SAndroid Build Coastguard Worker valid = false;
673*8975f5c5SAndroid Build Coastguard Worker }
674*8975f5c5SAndroid Build Coastguard Worker break;
675*8975f5c5SAndroid Build Coastguard Worker }
676*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
677*8975f5c5SAndroid Build Coastguard Worker }
678*8975f5c5SAndroid Build Coastguard Worker if (valid && (state != EXT_BEHAVIOR + 1))
679*8975f5c5SAndroid Build Coastguard Worker {
680*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
681*8975f5c5SAndroid Build Coastguard Worker token->text);
682*8975f5c5SAndroid Build Coastguard Worker valid = false;
683*8975f5c5SAndroid Build Coastguard Worker }
684*8975f5c5SAndroid Build Coastguard Worker if (valid && mSeenNonPreprocessorToken)
685*8975f5c5SAndroid Build Coastguard Worker {
686*8975f5c5SAndroid Build Coastguard Worker if (mShaderVersion >= 300)
687*8975f5c5SAndroid Build Coastguard Worker {
688*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
689*8975f5c5SAndroid Build Coastguard Worker token->location, token->text);
690*8975f5c5SAndroid Build Coastguard Worker valid = false;
691*8975f5c5SAndroid Build Coastguard Worker }
692*8975f5c5SAndroid Build Coastguard Worker else
693*8975f5c5SAndroid Build Coastguard Worker {
694*8975f5c5SAndroid Build Coastguard Worker if (mSettings.shaderSpec == SH_WEBGL_SPEC)
695*8975f5c5SAndroid Build Coastguard Worker {
696*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_WEBGL,
697*8975f5c5SAndroid Build Coastguard Worker token->location, token->text);
698*8975f5c5SAndroid Build Coastguard Worker }
699*8975f5c5SAndroid Build Coastguard Worker else
700*8975f5c5SAndroid Build Coastguard Worker {
701*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
702*8975f5c5SAndroid Build Coastguard Worker token->location, token->text);
703*8975f5c5SAndroid Build Coastguard Worker // This is just a warning on CHROME OS http://anglebug.com/42262661
704*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_PLATFORM_CHROMEOS)
705*8975f5c5SAndroid Build Coastguard Worker valid = false;
706*8975f5c5SAndroid Build Coastguard Worker #endif
707*8975f5c5SAndroid Build Coastguard Worker }
708*8975f5c5SAndroid Build Coastguard Worker }
709*8975f5c5SAndroid Build Coastguard Worker }
710*8975f5c5SAndroid Build Coastguard Worker if (valid)
711*8975f5c5SAndroid Build Coastguard Worker mDirectiveHandler->handleExtension(token->location, name, behavior);
712*8975f5c5SAndroid Build Coastguard Worker }
713*8975f5c5SAndroid Build Coastguard Worker
parseVersion(Token * token)714*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseVersion(Token *token)
715*8975f5c5SAndroid Build Coastguard Worker {
716*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_VERSION);
717*8975f5c5SAndroid Build Coastguard Worker
718*8975f5c5SAndroid Build Coastguard Worker if (mPastFirstStatement)
719*8975f5c5SAndroid Build Coastguard Worker {
720*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
721*8975f5c5SAndroid Build Coastguard Worker token->text);
722*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
723*8975f5c5SAndroid Build Coastguard Worker return;
724*8975f5c5SAndroid Build Coastguard Worker }
725*8975f5c5SAndroid Build Coastguard Worker
726*8975f5c5SAndroid Build Coastguard Worker enum State
727*8975f5c5SAndroid Build Coastguard Worker {
728*8975f5c5SAndroid Build Coastguard Worker VERSION_NUMBER,
729*8975f5c5SAndroid Build Coastguard Worker VERSION_PROFILE_ES,
730*8975f5c5SAndroid Build Coastguard Worker VERSION_ENDLINE
731*8975f5c5SAndroid Build Coastguard Worker };
732*8975f5c5SAndroid Build Coastguard Worker
733*8975f5c5SAndroid Build Coastguard Worker bool valid = true;
734*8975f5c5SAndroid Build Coastguard Worker int version = 0;
735*8975f5c5SAndroid Build Coastguard Worker int state = VERSION_NUMBER;
736*8975f5c5SAndroid Build Coastguard Worker
737*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
738*8975f5c5SAndroid Build Coastguard Worker while (valid && (token->type != '\n') && (token->type != Token::LAST))
739*8975f5c5SAndroid Build Coastguard Worker {
740*8975f5c5SAndroid Build Coastguard Worker switch (state)
741*8975f5c5SAndroid Build Coastguard Worker {
742*8975f5c5SAndroid Build Coastguard Worker case VERSION_NUMBER:
743*8975f5c5SAndroid Build Coastguard Worker if (token->type != Token::CONST_INT)
744*8975f5c5SAndroid Build Coastguard Worker {
745*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location,
746*8975f5c5SAndroid Build Coastguard Worker token->text);
747*8975f5c5SAndroid Build Coastguard Worker valid = false;
748*8975f5c5SAndroid Build Coastguard Worker }
749*8975f5c5SAndroid Build Coastguard Worker if (valid && !token->iValue(&version))
750*8975f5c5SAndroid Build Coastguard Worker {
751*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location,
752*8975f5c5SAndroid Build Coastguard Worker token->text);
753*8975f5c5SAndroid Build Coastguard Worker valid = false;
754*8975f5c5SAndroid Build Coastguard Worker }
755*8975f5c5SAndroid Build Coastguard Worker if (valid)
756*8975f5c5SAndroid Build Coastguard Worker {
757*8975f5c5SAndroid Build Coastguard Worker if (version < 300)
758*8975f5c5SAndroid Build Coastguard Worker {
759*8975f5c5SAndroid Build Coastguard Worker state = VERSION_ENDLINE;
760*8975f5c5SAndroid Build Coastguard Worker }
761*8975f5c5SAndroid Build Coastguard Worker else
762*8975f5c5SAndroid Build Coastguard Worker {
763*8975f5c5SAndroid Build Coastguard Worker state = VERSION_PROFILE_ES;
764*8975f5c5SAndroid Build Coastguard Worker }
765*8975f5c5SAndroid Build Coastguard Worker }
766*8975f5c5SAndroid Build Coastguard Worker break;
767*8975f5c5SAndroid Build Coastguard Worker case VERSION_PROFILE_ES:
768*8975f5c5SAndroid Build Coastguard Worker if (token->type != Token::IDENTIFIER || token->text != "es")
769*8975f5c5SAndroid Build Coastguard Worker {
770*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
771*8975f5c5SAndroid Build Coastguard Worker token->text);
772*8975f5c5SAndroid Build Coastguard Worker valid = false;
773*8975f5c5SAndroid Build Coastguard Worker }
774*8975f5c5SAndroid Build Coastguard Worker state = VERSION_ENDLINE;
775*8975f5c5SAndroid Build Coastguard Worker break;
776*8975f5c5SAndroid Build Coastguard Worker default:
777*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
778*8975f5c5SAndroid Build Coastguard Worker token->text);
779*8975f5c5SAndroid Build Coastguard Worker valid = false;
780*8975f5c5SAndroid Build Coastguard Worker break;
781*8975f5c5SAndroid Build Coastguard Worker }
782*8975f5c5SAndroid Build Coastguard Worker
783*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
784*8975f5c5SAndroid Build Coastguard Worker }
785*8975f5c5SAndroid Build Coastguard Worker
786*8975f5c5SAndroid Build Coastguard Worker if (valid && (state != VERSION_ENDLINE))
787*8975f5c5SAndroid Build Coastguard Worker {
788*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
789*8975f5c5SAndroid Build Coastguard Worker token->text);
790*8975f5c5SAndroid Build Coastguard Worker valid = false;
791*8975f5c5SAndroid Build Coastguard Worker }
792*8975f5c5SAndroid Build Coastguard Worker
793*8975f5c5SAndroid Build Coastguard Worker if (valid && version >= 300 && token->location.line > 1)
794*8975f5c5SAndroid Build Coastguard Worker {
795*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
796*8975f5c5SAndroid Build Coastguard Worker token->text);
797*8975f5c5SAndroid Build Coastguard Worker valid = false;
798*8975f5c5SAndroid Build Coastguard Worker }
799*8975f5c5SAndroid Build Coastguard Worker
800*8975f5c5SAndroid Build Coastguard Worker if (valid)
801*8975f5c5SAndroid Build Coastguard Worker {
802*8975f5c5SAndroid Build Coastguard Worker mShaderVersion = version;
803*8975f5c5SAndroid Build Coastguard Worker handleVersion(token->location);
804*8975f5c5SAndroid Build Coastguard Worker }
805*8975f5c5SAndroid Build Coastguard Worker }
806*8975f5c5SAndroid Build Coastguard Worker
parseLine(Token * token)807*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseLine(Token *token)
808*8975f5c5SAndroid Build Coastguard Worker {
809*8975f5c5SAndroid Build Coastguard Worker ASSERT(getDirective(token) == DIRECTIVE_LINE);
810*8975f5c5SAndroid Build Coastguard Worker
811*8975f5c5SAndroid Build Coastguard Worker bool valid = true;
812*8975f5c5SAndroid Build Coastguard Worker bool parsedFileNumber = false;
813*8975f5c5SAndroid Build Coastguard Worker int line = 0, file = 0;
814*8975f5c5SAndroid Build Coastguard Worker
815*8975f5c5SAndroid Build Coastguard Worker MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, false);
816*8975f5c5SAndroid Build Coastguard Worker
817*8975f5c5SAndroid Build Coastguard Worker // Lex the first token after "#line" so we can check it for EOD.
818*8975f5c5SAndroid Build Coastguard Worker macroExpander.lex(token);
819*8975f5c5SAndroid Build Coastguard Worker
820*8975f5c5SAndroid Build Coastguard Worker if (isEOD(token))
821*8975f5c5SAndroid Build Coastguard Worker {
822*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
823*8975f5c5SAndroid Build Coastguard Worker valid = false;
824*8975f5c5SAndroid Build Coastguard Worker }
825*8975f5c5SAndroid Build Coastguard Worker else
826*8975f5c5SAndroid Build Coastguard Worker {
827*8975f5c5SAndroid Build Coastguard Worker ExpressionParser expressionParser(¯oExpander, mDiagnostics);
828*8975f5c5SAndroid Build Coastguard Worker ExpressionParser::ErrorSettings errorSettings;
829*8975f5c5SAndroid Build Coastguard Worker
830*8975f5c5SAndroid Build Coastguard Worker // See GLES3 section 12.42
831*8975f5c5SAndroid Build Coastguard Worker errorSettings.integerLiteralsMustFit32BitSignedRange = true;
832*8975f5c5SAndroid Build Coastguard Worker
833*8975f5c5SAndroid Build Coastguard Worker errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
834*8975f5c5SAndroid Build Coastguard Worker // The first token was lexed earlier to check if it was EOD. Include
835*8975f5c5SAndroid Build Coastguard Worker // the token in parsing for a second time by setting the
836*8975f5c5SAndroid Build Coastguard Worker // parsePresetToken flag to true.
837*8975f5c5SAndroid Build Coastguard Worker expressionParser.parse(token, &line, true, errorSettings, &valid);
838*8975f5c5SAndroid Build Coastguard Worker if (!isEOD(token) && valid)
839*8975f5c5SAndroid Build Coastguard Worker {
840*8975f5c5SAndroid Build Coastguard Worker errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
841*8975f5c5SAndroid Build Coastguard Worker // After parsing the line expression expressionParser has also
842*8975f5c5SAndroid Build Coastguard Worker // advanced to the first token of the file expression - this is the
843*8975f5c5SAndroid Build Coastguard Worker // token that makes the parser reduce the "input" rule for the line
844*8975f5c5SAndroid Build Coastguard Worker // expression and stop. So we're using parsePresetToken = true here
845*8975f5c5SAndroid Build Coastguard Worker // as well.
846*8975f5c5SAndroid Build Coastguard Worker expressionParser.parse(token, &file, true, errorSettings, &valid);
847*8975f5c5SAndroid Build Coastguard Worker parsedFileNumber = true;
848*8975f5c5SAndroid Build Coastguard Worker }
849*8975f5c5SAndroid Build Coastguard Worker if (!isEOD(token))
850*8975f5c5SAndroid Build Coastguard Worker {
851*8975f5c5SAndroid Build Coastguard Worker if (valid)
852*8975f5c5SAndroid Build Coastguard Worker {
853*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
854*8975f5c5SAndroid Build Coastguard Worker token->text);
855*8975f5c5SAndroid Build Coastguard Worker valid = false;
856*8975f5c5SAndroid Build Coastguard Worker }
857*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
858*8975f5c5SAndroid Build Coastguard Worker }
859*8975f5c5SAndroid Build Coastguard Worker }
860*8975f5c5SAndroid Build Coastguard Worker
861*8975f5c5SAndroid Build Coastguard Worker if (valid)
862*8975f5c5SAndroid Build Coastguard Worker {
863*8975f5c5SAndroid Build Coastguard Worker mTokenizer->setLineNumber(line);
864*8975f5c5SAndroid Build Coastguard Worker if (parsedFileNumber)
865*8975f5c5SAndroid Build Coastguard Worker mTokenizer->setFileNumber(file);
866*8975f5c5SAndroid Build Coastguard Worker }
867*8975f5c5SAndroid Build Coastguard Worker }
868*8975f5c5SAndroid Build Coastguard Worker
skipping() const869*8975f5c5SAndroid Build Coastguard Worker bool DirectiveParser::skipping() const
870*8975f5c5SAndroid Build Coastguard Worker {
871*8975f5c5SAndroid Build Coastguard Worker if (mConditionalStack.empty())
872*8975f5c5SAndroid Build Coastguard Worker return false;
873*8975f5c5SAndroid Build Coastguard Worker
874*8975f5c5SAndroid Build Coastguard Worker const ConditionalBlock &block = mConditionalStack.back();
875*8975f5c5SAndroid Build Coastguard Worker return block.skipBlock || block.skipGroup;
876*8975f5c5SAndroid Build Coastguard Worker }
877*8975f5c5SAndroid Build Coastguard Worker
parseConditionalIf(Token * token)878*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseConditionalIf(Token *token)
879*8975f5c5SAndroid Build Coastguard Worker {
880*8975f5c5SAndroid Build Coastguard Worker ConditionalBlock block;
881*8975f5c5SAndroid Build Coastguard Worker block.type = token->text;
882*8975f5c5SAndroid Build Coastguard Worker block.location = token->location;
883*8975f5c5SAndroid Build Coastguard Worker
884*8975f5c5SAndroid Build Coastguard Worker if (skipping())
885*8975f5c5SAndroid Build Coastguard Worker {
886*8975f5c5SAndroid Build Coastguard Worker // This conditional block is inside another conditional group
887*8975f5c5SAndroid Build Coastguard Worker // which is skipped. As a consequence this whole block is skipped.
888*8975f5c5SAndroid Build Coastguard Worker // Be careful not to parse the conditional expression that might
889*8975f5c5SAndroid Build Coastguard Worker // emit a diagnostic.
890*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
891*8975f5c5SAndroid Build Coastguard Worker block.skipBlock = true;
892*8975f5c5SAndroid Build Coastguard Worker }
893*8975f5c5SAndroid Build Coastguard Worker else
894*8975f5c5SAndroid Build Coastguard Worker {
895*8975f5c5SAndroid Build Coastguard Worker DirectiveType directive = getDirective(token);
896*8975f5c5SAndroid Build Coastguard Worker
897*8975f5c5SAndroid Build Coastguard Worker int expression = 0;
898*8975f5c5SAndroid Build Coastguard Worker switch (directive)
899*8975f5c5SAndroid Build Coastguard Worker {
900*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_IF:
901*8975f5c5SAndroid Build Coastguard Worker expression = parseExpressionIf(token);
902*8975f5c5SAndroid Build Coastguard Worker break;
903*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_IFDEF:
904*8975f5c5SAndroid Build Coastguard Worker expression = parseExpressionIfdef(token);
905*8975f5c5SAndroid Build Coastguard Worker break;
906*8975f5c5SAndroid Build Coastguard Worker case DIRECTIVE_IFNDEF:
907*8975f5c5SAndroid Build Coastguard Worker expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
908*8975f5c5SAndroid Build Coastguard Worker break;
909*8975f5c5SAndroid Build Coastguard Worker default:
910*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE();
911*8975f5c5SAndroid Build Coastguard Worker break;
912*8975f5c5SAndroid Build Coastguard Worker }
913*8975f5c5SAndroid Build Coastguard Worker block.skipGroup = expression == 0;
914*8975f5c5SAndroid Build Coastguard Worker block.foundValidGroup = expression != 0;
915*8975f5c5SAndroid Build Coastguard Worker }
916*8975f5c5SAndroid Build Coastguard Worker mConditionalStack.push_back(block);
917*8975f5c5SAndroid Build Coastguard Worker }
918*8975f5c5SAndroid Build Coastguard Worker
parseExpressionIf(Token * token)919*8975f5c5SAndroid Build Coastguard Worker int DirectiveParser::parseExpressionIf(Token *token)
920*8975f5c5SAndroid Build Coastguard Worker {
921*8975f5c5SAndroid Build Coastguard Worker ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
922*8975f5c5SAndroid Build Coastguard Worker
923*8975f5c5SAndroid Build Coastguard Worker MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, true);
924*8975f5c5SAndroid Build Coastguard Worker ExpressionParser expressionParser(¯oExpander, mDiagnostics);
925*8975f5c5SAndroid Build Coastguard Worker
926*8975f5c5SAndroid Build Coastguard Worker int expression = 0;
927*8975f5c5SAndroid Build Coastguard Worker ExpressionParser::ErrorSettings errorSettings;
928*8975f5c5SAndroid Build Coastguard Worker errorSettings.integerLiteralsMustFit32BitSignedRange = false;
929*8975f5c5SAndroid Build Coastguard Worker errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
930*8975f5c5SAndroid Build Coastguard Worker
931*8975f5c5SAndroid Build Coastguard Worker bool valid = true;
932*8975f5c5SAndroid Build Coastguard Worker expressionParser.parse(token, &expression, false, errorSettings, &valid);
933*8975f5c5SAndroid Build Coastguard Worker
934*8975f5c5SAndroid Build Coastguard Worker // Check if there are tokens after #if expression.
935*8975f5c5SAndroid Build Coastguard Worker if (!isEOD(token))
936*8975f5c5SAndroid Build Coastguard Worker {
937*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
938*8975f5c5SAndroid Build Coastguard Worker token->text);
939*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
940*8975f5c5SAndroid Build Coastguard Worker }
941*8975f5c5SAndroid Build Coastguard Worker
942*8975f5c5SAndroid Build Coastguard Worker return expression;
943*8975f5c5SAndroid Build Coastguard Worker }
944*8975f5c5SAndroid Build Coastguard Worker
parseExpressionIfdef(Token * token)945*8975f5c5SAndroid Build Coastguard Worker int DirectiveParser::parseExpressionIfdef(Token *token)
946*8975f5c5SAndroid Build Coastguard Worker {
947*8975f5c5SAndroid Build Coastguard Worker ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
948*8975f5c5SAndroid Build Coastguard Worker
949*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
950*8975f5c5SAndroid Build Coastguard Worker if (token->type != Token::IDENTIFIER)
951*8975f5c5SAndroid Build Coastguard Worker {
952*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
953*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
954*8975f5c5SAndroid Build Coastguard Worker return 0;
955*8975f5c5SAndroid Build Coastguard Worker }
956*8975f5c5SAndroid Build Coastguard Worker
957*8975f5c5SAndroid Build Coastguard Worker MacroSet::const_iterator iter = mMacroSet->find(token->text);
958*8975f5c5SAndroid Build Coastguard Worker int expression = iter != mMacroSet->end() ? 1 : 0;
959*8975f5c5SAndroid Build Coastguard Worker
960*8975f5c5SAndroid Build Coastguard Worker // Check if there are tokens after #ifdef expression.
961*8975f5c5SAndroid Build Coastguard Worker mTokenizer->lex(token);
962*8975f5c5SAndroid Build Coastguard Worker if (!isEOD(token))
963*8975f5c5SAndroid Build Coastguard Worker {
964*8975f5c5SAndroid Build Coastguard Worker mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
965*8975f5c5SAndroid Build Coastguard Worker token->text);
966*8975f5c5SAndroid Build Coastguard Worker skipUntilEOD(mTokenizer, token);
967*8975f5c5SAndroid Build Coastguard Worker }
968*8975f5c5SAndroid Build Coastguard Worker return expression;
969*8975f5c5SAndroid Build Coastguard Worker }
970*8975f5c5SAndroid Build Coastguard Worker
handleVersion(const SourceLocation & location)971*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::handleVersion(const SourceLocation &location)
972*8975f5c5SAndroid Build Coastguard Worker {
973*8975f5c5SAndroid Build Coastguard Worker PredefineMacro(mMacroSet, "__VERSION__", mShaderVersion);
974*8975f5c5SAndroid Build Coastguard Worker mDirectiveHandler->handleVersion(location, mShaderVersion, mSettings.shaderSpec, mMacroSet);
975*8975f5c5SAndroid Build Coastguard Worker mHandledVersion = true;
976*8975f5c5SAndroid Build Coastguard Worker }
977*8975f5c5SAndroid Build Coastguard Worker
978*8975f5c5SAndroid Build Coastguard Worker } // namespace pp
979*8975f5c5SAndroid Build Coastguard Worker
980*8975f5c5SAndroid Build Coastguard Worker } // namespace angle
981