3 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
8 This file contains the Lex specification for GLSL ES.
9 Based on ANSI C grammar, Lex specification:
10 http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
12 IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_glslang_lexer.sh,
13 WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
18 // Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
19 // Use of this source code is governed by a BSD-style license that can be
20 // found in the LICENSE file.
23 // This file is auto-generated by generate_glslang_lexer.sh. DO NOT EDIT!
27 #include "compiler/glslang.h"
28 #include "compiler/ParseHelper.h"
29 #include "compiler/util.h"
30 #include "glslang_tab.h"
32 /* windows only pragma */
34 #pragma warning(disable : 4102)
37 #define YY_USER_ACTION yylval->lex.line = yylineno;
38 #define YY_INPUT(buf, result, max_size) \
39 result = string_input(buf, max_size, yyscanner);
41 static int string_input(char* buf, int max_size, yyscan_t yyscanner);
42 static int check_type(yyscan_t yyscanner);
43 static int reserved_word(yyscan_t yyscanner);
46 %option noyywrap nounput never-interactive
47 %option yylineno reentrant bison-bridge
49 %option extra-type="TParseContext*"
61 TParseContext* context = yyextra;
64 /* Single-line comments */
67 /* Multi-line comments */
68 "/*" { yy_push_state(COMMENT, yyscanner); }
71 <COMMENT>"*/" { yy_pop_state(yyscanner); }
73 "invariant" { return(INVARIANT); }
74 "highp" { return(HIGH_PRECISION); }
75 "mediump" { return(MEDIUM_PRECISION); }
76 "lowp" { return(LOW_PRECISION); }
77 "precision" { return(PRECISION); }
79 "attribute" { return(ATTRIBUTE); }
80 "const" { return(CONST_QUAL); }
81 "uniform" { return(UNIFORM); }
82 "varying" { return(VARYING); }
84 "break" { return(BREAK); }
85 "continue" { return(CONTINUE); }
87 "for" { return(FOR); }
88 "while" { return(WHILE); }
91 "else" { return(ELSE); }
93 "in" { return(IN_QUAL); }
94 "out" { return(OUT_QUAL); }
95 "inout" { return(INOUT_QUAL); }
97 "float" { context->lexAfterType = true; return(FLOAT_TYPE); }
98 "int" { context->lexAfterType = true; return(INT_TYPE); }
99 "void" { context->lexAfterType = true; return(VOID_TYPE); }
100 "bool" { context->lexAfterType = true; return(BOOL_TYPE); }
101 "true" { yylval->lex.b = true; return(BOOLCONSTANT); }
102 "false" { yylval->lex.b = false; return(BOOLCONSTANT); }
104 "discard" { return(DISCARD); }
105 "return" { return(RETURN); }
107 "mat2" { context->lexAfterType = true; return(MATRIX2); }
108 "mat3" { context->lexAfterType = true; return(MATRIX3); }
109 "mat4" { context->lexAfterType = true; return(MATRIX4); }
111 "vec2" { context->lexAfterType = true; return (VEC2); }
112 "vec3" { context->lexAfterType = true; return (VEC3); }
113 "vec4" { context->lexAfterType = true; return (VEC4); }
114 "ivec2" { context->lexAfterType = true; return (IVEC2); }
115 "ivec3" { context->lexAfterType = true; return (IVEC3); }
116 "ivec4" { context->lexAfterType = true; return (IVEC4); }
117 "bvec2" { context->lexAfterType = true; return (BVEC2); }
118 "bvec3" { context->lexAfterType = true; return (BVEC3); }
119 "bvec4" { context->lexAfterType = true; return (BVEC4); }
121 "sampler2D" { context->lexAfterType = true; return SAMPLER2D; }
122 "samplerCube" { context->lexAfterType = true; return SAMPLERCUBE; }
124 "struct" { context->lexAfterType = true; return(STRUCT); }
126 "asm" { return reserved_word(yyscanner); }
128 "class" { return reserved_word(yyscanner); }
129 "union" { return reserved_word(yyscanner); }
130 "enum" { return reserved_word(yyscanner); }
131 "typedef" { return reserved_word(yyscanner); }
132 "template" { return reserved_word(yyscanner); }
133 "this" { return reserved_word(yyscanner); }
134 "packed" { return reserved_word(yyscanner); }
136 "goto" { return reserved_word(yyscanner); }
137 "switch" { return reserved_word(yyscanner); }
138 "default" { return reserved_word(yyscanner); }
140 "inline" { return reserved_word(yyscanner); }
141 "noinline" { return reserved_word(yyscanner); }
142 "volatile" { return reserved_word(yyscanner); }
143 "public" { return reserved_word(yyscanner); }
144 "static" { return reserved_word(yyscanner); }
145 "extern" { return reserved_word(yyscanner); }
146 "external" { return reserved_word(yyscanner); }
147 "interface" { return reserved_word(yyscanner); }
149 "long" { return reserved_word(yyscanner); }
150 "short" { return reserved_word(yyscanner); }
151 "double" { return reserved_word(yyscanner); }
152 "half" { return reserved_word(yyscanner); }
153 "fixed" { return reserved_word(yyscanner); }
154 "unsigned" { return reserved_word(yyscanner); }
156 "input" { return reserved_word(yyscanner); }
157 "output" { return reserved_word(yyscanner); }
159 "hvec2" { return reserved_word(yyscanner); }
160 "hvec3" { return reserved_word(yyscanner); }
161 "hvec4" { return reserved_word(yyscanner); }
162 "fvec2" { return reserved_word(yyscanner); }
163 "fvec3" { return reserved_word(yyscanner); }
164 "fvec4" { return reserved_word(yyscanner); }
165 "dvec2" { return reserved_word(yyscanner); }
166 "dvec3" { return reserved_word(yyscanner); }
167 "dvec4" { return reserved_word(yyscanner); }
169 "sizeof" { return reserved_word(yyscanner); }
170 "cast" { return reserved_word(yyscanner); }
172 "namespace" { return reserved_word(yyscanner); }
173 "using" { return reserved_word(yyscanner); }
176 yylval->lex.string = NewPoolTString(yytext);
177 return check_type(yyscanner);
180 0[xX]{H}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
181 0{O}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
182 0{D}+ { context->error(yylineno, "Invalid Octal number.", yytext, "", ""); context->recover(); return 0;}
183 {D}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
185 {D}+{E} { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
186 {D}+"."{D}*({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
187 "."{D}+({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
189 "+=" { return(ADD_ASSIGN); }
190 "-=" { return(SUB_ASSIGN); }
191 "*=" { return(MUL_ASSIGN); }
192 "/=" { return(DIV_ASSIGN); }
193 "%=" { return(MOD_ASSIGN); }
194 "<<=" { return(LEFT_ASSIGN); }
195 ">>=" { return(RIGHT_ASSIGN); }
196 "&=" { return(AND_ASSIGN); }
197 "^=" { return(XOR_ASSIGN); }
198 "|=" { return(OR_ASSIGN); }
200 "++" { return(INC_OP); }
201 "--" { return(DEC_OP); }
202 "&&" { return(AND_OP); }
203 "||" { return(OR_OP); }
204 "^^" { return(XOR_OP); }
205 "<=" { return(LE_OP); }
206 ">=" { return(GE_OP); }
207 "==" { return(EQ_OP); }
208 "!=" { return(NE_OP); }
209 "<<" { return(LEFT_OP); }
210 ">>" { return(RIGHT_OP); }
211 ";" { context->lexAfterType = false; return(SEMICOLON); }
212 ("{"|"<%") { context->lexAfterType = false; return(LEFT_BRACE); }
213 ("}"|"%>") { return(RIGHT_BRACE); }
214 "," { if (context->inTypeParen) context->lexAfterType = false; return(COMMA); }
215 ":" { return(COLON); }
216 "=" { context->lexAfterType = false; return(EQUAL); }
217 "(" { context->lexAfterType = false; context->inTypeParen = true; return(LEFT_PAREN); }
218 ")" { context->inTypeParen = false; return(RIGHT_PAREN); }
219 ("["|"<:") { return(LEFT_BRACKET); }
220 ("]"|":>") { return(RIGHT_BRACKET); }
221 "." { BEGIN(FIELDS); return(DOT); }
222 "!" { return(BANG); }
223 "-" { return(DASH); }
224 "~" { return(TILDE); }
225 "+" { return(PLUS); }
226 "*" { return(STAR); }
227 "/" { return(SLASH); }
228 "%" { return(PERCENT); }
229 "<" { return(LEFT_ANGLE); }
230 ">" { return(RIGHT_ANGLE); }
231 "|" { return(VERTICAL_BAR); }
232 "^" { return(CARET); }
233 "&" { return(AMPERSAND); }
234 "?" { return(QUESTION); }
236 <FIELDS>{L}({L}|{D})* {
238 yylval->lex.string = NewPoolTString(yytext);
239 return FIELD_SELECTION;
241 <FIELDS>[ \t\v\f\r] {}
244 <*><<EOF>> { context->AfterEOF = true; yyterminate(); }
245 <*>. { context->warning(yylineno, "Unknown char", yytext, ""); return 0; }
250 // Preprocessor interface.
251 #include "compiler/preprocessor/preprocess.h"
253 #define SETUP_CONTEXT(pp) \
254 TParseContext* context = (TParseContext*) pp->pC; \
255 struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
257 // Preprocessor callbacks.
258 void CPPDebugLogMsg(const char *msg)
261 context->infoSink.debug.message(EPrefixNone, msg);
264 void CPPWarningToInfoLog(const char *msg)
267 context->warning(yylineno, msg, "", "");
270 void CPPShInfoLogMsg(const char *msg)
273 context->error(yylineno, msg, "", "");
277 void CPPErrorToInfoLog(char *msg)
280 context->error(yylineno, msg, "", "");
284 void SetLineNumber(int line)
288 DecodeSourceLoc(yylineno, &string, NULL);
289 yylineno = EncodeSourceLoc(string, line);
292 void SetStringNumber(int string)
296 DecodeSourceLoc(yylineno, NULL, &line);
297 yylineno = EncodeSourceLoc(string, line);
300 int GetStringNumber()
304 DecodeSourceLoc(yylineno, &string, NULL);
312 DecodeSourceLoc(yylineno, NULL, &line);
319 int string = 0, line = 0;
320 DecodeSourceLoc(yylineno, &string, &line);
321 yylineno = EncodeSourceLoc(string, ++line);
327 int string = 0, line = 0;
328 DecodeSourceLoc(yylineno, &string, &line);
329 yylineno = EncodeSourceLoc(string, --line);
332 void HandlePragma(const char **tokens, int numTokens)
335 if (!strcmp(tokens[0], "optimize")) {
336 if (numTokens != 4) {
337 CPPShInfoLogMsg("optimize pragma syntax is incorrect");
341 if (strcmp(tokens[1], "(")) {
342 CPPShInfoLogMsg("\"(\" expected after 'optimize' keyword");
346 if (!strcmp(tokens[2], "on"))
347 context->contextPragma.optimize = true;
348 else if (!strcmp(tokens[2], "off"))
349 context->contextPragma.optimize = false;
351 CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'optimize' pragma");
355 if (strcmp(tokens[3], ")")) {
356 CPPShInfoLogMsg("\")\" expected to end 'optimize' pragma");
359 } else if (!strcmp(tokens[0], "debug")) {
360 if (numTokens != 4) {
361 CPPShInfoLogMsg("debug pragma syntax is incorrect");
365 if (strcmp(tokens[1], "(")) {
366 CPPShInfoLogMsg("\"(\" expected after 'debug' keyword");
370 if (!strcmp(tokens[2], "on"))
371 context->contextPragma.debug = true;
372 else if (!strcmp(tokens[2], "off"))
373 context->contextPragma.debug = false;
375 CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'debug' pragma");
379 if (strcmp(tokens[3], ")")) {
380 CPPShInfoLogMsg("\")\" expected to end 'debug' pragma");
386 // implementation specific pragma
387 // use ((TParseContext *)cpp->pC)->contextPragma.pragmaTable to store the information about pragma
388 // For now, just ignore the pragma that the implementation cannot recognize
389 // An Example of one such implementation for a pragma that has a syntax like
390 // #pragma pragmaname(pragmavalue)
391 // This implementation stores the current pragmavalue against the pragma name in pragmaTable.
393 if (numTokens == 4 && !strcmp(tokens[1], "(") && !strcmp(tokens[3], ")")) {
394 TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable;
395 TPragmaTable::iterator iter;
396 iter = pragmaTable.find(TString(tokens[0]));
397 if (iter != pragmaTable.end()) {
398 iter->second = tokens[2];
400 pragmaTable[ tokens[0] ] = tokens[2];
402 } else if (numTokens >= 2) {
403 TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable;
404 TPragmaTable::iterator iter;
405 iter = pragmaTable.find(TString(tokens[0]));
406 if (iter != pragmaTable.end()) {
407 iter->second = tokens[1];
409 pragmaTable[ tokens[0] ] = tokens[1];
412 #endif // PRAGMA_TABLE
416 void StoreStr(char *string)
420 strSrc = TString(string);
422 context->HashErrMsg = context->HashErrMsg + " " + strSrc;
425 const char* GetStrfromTStr(void)
428 cpp->ErrMsg = context->HashErrMsg.c_str();
432 void ResetTString(void)
435 context->HashErrMsg = "";
438 TBehavior GetBehavior(const char* behavior)
440 if (!strcmp("require", behavior))
442 else if (!strcmp("enable", behavior))
444 else if (!strcmp("disable", behavior))
446 else if (!strcmp("warn", behavior))
449 CPPShInfoLogMsg((TString("behavior '") + behavior + "' is not supported").c_str());
454 void updateExtensionBehavior(const char* extName, const char* behavior)
457 TBehavior behaviorVal = GetBehavior(behavior);
458 TMap<TString, TBehavior>:: iterator iter;
461 // special cased for all extension
462 if (!strcmp(extName, "all")) {
463 if (behaviorVal == EBhRequire || behaviorVal == EBhEnable) {
464 CPPShInfoLogMsg("extension 'all' cannot have 'require' or 'enable' behavior");
467 for (iter = context->extensionBehavior.begin(); iter != context->extensionBehavior.end(); ++iter)
468 iter->second = behaviorVal;
471 iter = context->extensionBehavior.find(TString(extName));
472 if (iter == context->extensionBehavior.end()) {
473 switch (behaviorVal) {
475 CPPShInfoLogMsg((TString("extension '") + extName + "' is not supported").c_str());
480 msg = TString("extension '") + extName + "' is not supported";
481 context->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno);
486 iter->second = behaviorVal;
491 int string_input(char* buf, int max_size, yyscan_t yyscanner) {
494 if ((len = yylex_CPP(buf, max_size)) == 0)
497 YY_FATAL_ERROR("input buffer overflow, can't enlarge buffer because scanner uses REJECT");
503 int check_type(yyscan_t yyscanner) {
504 struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
506 int token = IDENTIFIER;
507 TSymbol* symbol = yyextra->symbolTable.find(yytext);
508 if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) {
509 TVariable* variable = static_cast<TVariable*>(symbol);
510 if (variable->isUserType()) {
511 yyextra->lexAfterType = true;
515 yylval->lex.symbol = symbol;
519 int reserved_word(yyscan_t yyscanner) {
520 struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
522 yyextra->error(yylineno, "Illegal use of reserved word", yytext, "");
527 void yyerror(TParseContext* context, const char* reason) {
528 struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
530 if (context->AfterEOF) {
531 context->error(yylineno, reason, "unexpected EOF", "");
533 context->error(yylineno, reason, yytext, "");
538 int glslang_initialize(TParseContext* context) {
539 yyscan_t scanner = NULL;
540 if (yylex_init_extra(context, &scanner))
543 context->scanner = scanner;
547 int glslang_finalize(TParseContext* context) {
548 yyscan_t scanner = context->scanner;
549 if (scanner == NULL) return 0;
551 context->scanner = NULL;
552 return yylex_destroy(scanner);
555 void glslang_scan(int count, const char* const string[], const int length[],
556 TParseContext* context) {
557 yyrestart(NULL, context->scanner);
558 yyset_lineno(EncodeSourceLoc(0, 1), context->scanner);
559 context->AfterEOF = false;
561 // Init preprocessor.
564 cpp->PaArgv = string;
566 cpp->PaStrLen = length;
567 cpp->pastFirstStatement = 0;
568 ScanFromString(string[0]);