1 /*
2 //
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.
6 //
7 
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
11 
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).
14 */
15 
16 %top{
17 //
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.
21 //
22 
23 // This file is auto-generated by generate_glslang_lexer.sh. DO NOT EDIT!
24 }
25 
26 %{
27 #include "compiler/glslang.h"
28 #include "compiler/ParseHelper.h"
29 #include "compiler/util.h"
30 #include "glslang_tab.h"
31 
32 /* windows only pragma */
33 #ifdef _MSC_VER
34 #pragma warning(disable : 4102)
35 #endif
36 
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);
40 
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);
44 %}
45 
46 %option noyywrap nounput never-interactive
47 %option yylineno reentrant bison-bridge
48 %option stack
49 %option extra-type="TParseContext*"
50 %x COMMENT FIELDS
51 
52 D           [0-9]
53 L           [a-zA-Z_]
54 H           [a-fA-F0-9]
55 E           [Ee][+-]?{D}+
56 O           [0-7]
57 
58 %%
59 
60 %{
61     TParseContext* context = yyextra;
62 %}
63 
64     /* Single-line comments */
65 "//"[^\n]* ;
66 
67     /* Multi-line comments */
68 "/*"           { yy_push_state(COMMENT, yyscanner); }
69 <COMMENT>. |
70 <COMMENT>\n ;
71 <COMMENT>"*/"  { yy_pop_state(yyscanner); }
72 
73 "invariant"    { return(INVARIANT); }
74 "highp"        { return(HIGH_PRECISION); }
75 "mediump"      { return(MEDIUM_PRECISION); }
76 "lowp"         { return(LOW_PRECISION); }
77 "precision"    { return(PRECISION); }
78 
79 "attribute"    { return(ATTRIBUTE); }
80 "const"        { return(CONST_QUAL); }
81 "uniform"      { return(UNIFORM); }
82 "varying"      { return(VARYING); }
83 
84 "break"        { return(BREAK); }
85 "continue"     { return(CONTINUE); }
86 "do"           { return(DO); }
87 "for"          { return(FOR); }
88 "while"        { return(WHILE); }
89 
90 "if"           { return(IF); }
91 "else"         { return(ELSE); }
92 
93 "in"           { return(IN_QUAL); }
94 "out"          { return(OUT_QUAL); }
95 "inout"        { return(INOUT_QUAL); }
96 
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); }
103 
104 "discard"      { return(DISCARD); }
105 "return"       { return(RETURN); }
106 
107 "mat2"         { context->lexAfterType = true; return(MATRIX2); }
108 "mat3"         { context->lexAfterType = true; return(MATRIX3); }
109 "mat4"         { context->lexAfterType = true; return(MATRIX4); }
110 
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); }
120 
121 "sampler2D"       { context->lexAfterType = true; return SAMPLER2D; }
122 "samplerCube"     { context->lexAfterType = true; return SAMPLERCUBE; }
123 
124 "struct"       { context->lexAfterType = true; return(STRUCT); }
125 
126 "asm"          { return reserved_word(yyscanner); }
127 
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); }
135 
136 "goto"         { return reserved_word(yyscanner); }
137 "switch"       { return reserved_word(yyscanner); }
138 "default"      { return reserved_word(yyscanner); }
139 
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); }
148 
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); }
155 
156 "input"        { return reserved_word(yyscanner); }
157 "output"       { return reserved_word(yyscanner); }
158 
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); }
168 
169 "sizeof"       { return reserved_word(yyscanner); }
170 "cast"         { return reserved_word(yyscanner); }
171 
172 "namespace"    { return reserved_word(yyscanner); }
173 "using"        { return reserved_word(yyscanner); }
174 
175 {L}({L}|{D})*       {
176    yylval->lex.string = NewPoolTString(yytext);
177    return check_type(yyscanner);
178 }
179 
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); }
184 
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); }
188 
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); }
199 
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); }
235 
236 <FIELDS>{L}({L}|{D})* {
237     BEGIN(INITIAL);
238     yylval->lex.string = NewPoolTString(yytext);
239     return FIELD_SELECTION;
240 }
241 <FIELDS>[ \t\v\f\r] {}
242 
243 [ \t\v\n\f\r]   {  }
244 <*><<EOF>>      { context->AfterEOF = true; yyterminate(); }
245 <*>.            { context->warning(yylineno, "Unknown char", yytext, ""); return 0; }
246 
247 %%
248 
249 extern "C" {
250 // Preprocessor interface.
251 #include "compiler/preprocessor/preprocess.h"
252 
253 #define SETUP_CONTEXT(pp) \
254     TParseContext* context = (TParseContext*) pp->pC; \
255     struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
256 
257 // Preprocessor callbacks.
CPPDebugLogMsg(const char * msg)258 void CPPDebugLogMsg(const char *msg)
259 {
260     SETUP_CONTEXT(cpp);
261     context->infoSink.debug.message(EPrefixNone, msg);
262 }
263 
CPPWarningToInfoLog(const char * msg)264 void CPPWarningToInfoLog(const char *msg)
265 {
266     SETUP_CONTEXT(cpp);
267     context->warning(yylineno, msg, "", "");
268 }
269 
CPPShInfoLogMsg(const char * msg)270 void CPPShInfoLogMsg(const char *msg)
271 {
272     SETUP_CONTEXT(cpp);
273     context->error(yylineno, msg, "", "");
274     context->recover();
275 }
276 
CPPErrorToInfoLog(char * msg)277 void CPPErrorToInfoLog(char *msg)
278 {
279     SETUP_CONTEXT(cpp);
280     context->error(yylineno, msg, "", "");
281     context->recover();
282 }
283 
SetLineNumber(int line)284 void SetLineNumber(int line)
285 {
286     SETUP_CONTEXT(cpp);
287     int string = 0;
288     DecodeSourceLoc(yylineno, &string, NULL);
289     yylineno = EncodeSourceLoc(string, line);
290 }
291 
SetStringNumber(int string)292 void SetStringNumber(int string)
293 {
294     SETUP_CONTEXT(cpp);
295     int line = 0;
296     DecodeSourceLoc(yylineno, NULL, &line);
297     yylineno = EncodeSourceLoc(string, line);
298 }
299 
GetStringNumber()300 int GetStringNumber()
301 {
302     SETUP_CONTEXT(cpp);
303     int string = 0;
304     DecodeSourceLoc(yylineno, &string, NULL);
305     return string;
306 }
307 
GetLineNumber()308 int GetLineNumber()
309 {
310     SETUP_CONTEXT(cpp);
311     int line = 0;
312     DecodeSourceLoc(yylineno, NULL, &line);
313     return line;
314 }
315 
IncLineNumber()316 void IncLineNumber()
317 {
318     SETUP_CONTEXT(cpp);
319     int string = 0, line = 0;
320     DecodeSourceLoc(yylineno, &string, &line);
321     yylineno = EncodeSourceLoc(string, ++line);
322 }
323 
DecLineNumber()324 void DecLineNumber()
325 {
326     SETUP_CONTEXT(cpp);
327     int string = 0, line = 0;
328     DecodeSourceLoc(yylineno, &string, &line);
329     yylineno = EncodeSourceLoc(string, --line);
330 }
331 
HandlePragma(const char ** tokens,int numTokens)332 void HandlePragma(const char **tokens, int numTokens)
333 {
334     SETUP_CONTEXT(cpp);
335     if (!strcmp(tokens[0], "optimize")) {
336         if (numTokens != 4) {
337             CPPShInfoLogMsg("optimize pragma syntax is incorrect");
338             return;
339         }
340 
341         if (strcmp(tokens[1], "(")) {
342             CPPShInfoLogMsg("\"(\" expected after 'optimize' keyword");
343             return;
344         }
345 
346         if (!strcmp(tokens[2], "on"))
347             context->contextPragma.optimize = true;
348         else if (!strcmp(tokens[2], "off"))
349             context->contextPragma.optimize = false;
350         else {
351             CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'optimize' pragma");
352             return;
353         }
354 
355         if (strcmp(tokens[3], ")")) {
356             CPPShInfoLogMsg("\")\" expected to end 'optimize' pragma");
357             return;
358         }
359     } else if (!strcmp(tokens[0], "debug")) {
360         if (numTokens != 4) {
361             CPPShInfoLogMsg("debug pragma syntax is incorrect");
362             return;
363         }
364 
365         if (strcmp(tokens[1], "(")) {
366             CPPShInfoLogMsg("\"(\" expected after 'debug' keyword");
367             return;
368         }
369 
370         if (!strcmp(tokens[2], "on"))
371             context->contextPragma.debug = true;
372         else if (!strcmp(tokens[2], "off"))
373             context->contextPragma.debug = false;
374         else {
375             CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'debug' pragma");
376             return;
377         }
378 
379         if (strcmp(tokens[3], ")")) {
380             CPPShInfoLogMsg("\")\" expected to end 'debug' pragma");
381             return;
382         }
383     } else {
384 #ifdef PRAGMA_TABLE
385         //
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.
392         //
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];
399             } else {
400                 pragmaTable[ tokens[0] ] = tokens[2];
401             }
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];
408             } else {
409                 pragmaTable[ tokens[0] ] = tokens[1];
410             }
411         }
412 #endif // PRAGMA_TABLE
413     }
414 }
415 
StoreStr(char * string)416 void StoreStr(char *string)
417 {
418     SETUP_CONTEXT(cpp);
419     TString strSrc;
420     strSrc = TString(string);
421 
422     context->HashErrMsg = context->HashErrMsg + " " + strSrc;
423 }
424 
GetStrfromTStr(void)425 const char* GetStrfromTStr(void)
426 {
427     SETUP_CONTEXT(cpp);
428     cpp->ErrMsg = context->HashErrMsg.c_str();
429     return cpp->ErrMsg;
430 }
431 
ResetTString(void)432 void ResetTString(void)
433 {
434     SETUP_CONTEXT(cpp);
435     context->HashErrMsg = "";
436 }
437 
GetBehavior(const char * behavior)438 TBehavior GetBehavior(const char* behavior)
439 {
440     if (!strcmp("require", behavior))
441         return EBhRequire;
442     else if (!strcmp("enable", behavior))
443         return EBhEnable;
444     else if (!strcmp("disable", behavior))
445         return EBhDisable;
446     else if (!strcmp("warn", behavior))
447         return EBhWarn;
448     else {
449         CPPShInfoLogMsg((TString("behavior '") + behavior + "' is not supported").c_str());
450         return EBhDisable;
451     }
452 }
453 
updateExtensionBehavior(const char * extName,const char * behavior)454 void updateExtensionBehavior(const char* extName, const char* behavior)
455 {
456     SETUP_CONTEXT(cpp);
457     TBehavior behaviorVal = GetBehavior(behavior);
458     TMap<TString, TBehavior>:: iterator iter;
459     TString msg;
460 
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");
465             return;
466         } else {
467             for (iter = context->extensionBehavior.begin(); iter != context->extensionBehavior.end(); ++iter)
468                 iter->second = behaviorVal;
469         }
470     } else {
471         iter = context->extensionBehavior.find(TString(extName));
472         if (iter == context->extensionBehavior.end()) {
473             switch (behaviorVal) {
474             case EBhRequire:
475                 CPPShInfoLogMsg((TString("extension '") + extName + "' is not supported").c_str());
476                 break;
477             case EBhEnable:
478             case EBhWarn:
479             case EBhDisable:
480                 msg = TString("extension '") + extName + "' is not supported";
481                 context->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno);
482                 break;
483             }
484             return;
485         } else
486             iter->second = behaviorVal;
487     }
488 }
489 }  // extern "C"
490 
string_input(char * buf,int max_size,yyscan_t yyscanner)491 int string_input(char* buf, int max_size, yyscan_t yyscanner) {
492     int len;
493 
494     if ((len = yylex_CPP(buf, max_size)) == 0)
495         return 0;
496     if (len >= max_size)
497         YY_FATAL_ERROR("input buffer overflow, can't enlarge buffer because scanner uses REJECT");
498 
499     buf[len] = ' ';
500     return len+1;
501 }
502 
check_type(yyscan_t yyscanner)503 int check_type(yyscan_t yyscanner) {
504     struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
505 
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;
512             token = TYPE_NAME;
513         }
514     }
515     yylval->lex.symbol = symbol;
516     return token;
517 }
518 
reserved_word(yyscan_t yyscanner)519 int reserved_word(yyscan_t yyscanner) {
520     struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
521 
522     yyextra->error(yylineno, "Illegal use of reserved word", yytext, "");
523     yyextra->recover();
524     return 0;
525 }
526 
yyerror(TParseContext * context,const char * reason)527 void yyerror(TParseContext* context, const char* reason) {
528     struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
529 
530     if (context->AfterEOF) {
531         context->error(yylineno, reason, "unexpected EOF", "");
532     } else {
533         context->error(yylineno, reason, yytext, "");
534     }
535     context->recover();
536 }
537 
glslang_initialize(TParseContext * context)538 int glslang_initialize(TParseContext* context) {
539     yyscan_t scanner = NULL;
540     if (yylex_init_extra(context, &scanner))
541         return 1;
542 
543     context->scanner = scanner;
544     return 0;
545 }
546 
glslang_finalize(TParseContext * context)547 int glslang_finalize(TParseContext* context) {
548     yyscan_t scanner = context->scanner;
549     if (scanner == NULL) return 0;
550 
551     context->scanner = NULL;
552     return yylex_destroy(scanner);
553 }
554 
glslang_scan(int count,const char * const string[],const int length[],TParseContext * context)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;
560 
561     // Init preprocessor.
562     cpp->pC = context;
563     cpp->PaWhichStr = 0;
564     cpp->PaArgv     = string;
565     cpp->PaArgc     = count;
566     cpp->PaStrLen   = length;
567     cpp->pastFirstStatement = 0;
568     ScanFromString(string[0]);
569 }
570 
571