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
8This file contains the Lex specification for GLSL ES.
9Based on ANSI C grammar, Lex specification:
10http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
11
12IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_glslang_lexer.sh,
13WHICH 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
41static int string_input(char* buf, int max_size, yyscan_t yyscanner);
42static int check_type(yyscan_t yyscanner);
43static 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
52D           [0-9]
53L           [a-zA-Z_]
54H           [a-fA-F0-9]
55E           [Ee][+-]?{D}+
56O           [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
1800[xX]{H}+         { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
1810{O}+             { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
1820{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
249extern "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.
258void CPPDebugLogMsg(const char *msg)
259{
260    SETUP_CONTEXT(cpp);
261    context->infoSink.debug.message(EPrefixNone, msg);
262}
263
264void CPPWarningToInfoLog(const char *msg)
265{
266    SETUP_CONTEXT(cpp);
267    context->warning(yylineno, msg, "", "");
268}
269
270void CPPShInfoLogMsg(const char *msg)
271{
272    SETUP_CONTEXT(cpp);
273    context->error(yylineno, msg, "", "");
274    context->recover();
275}
276
277void CPPErrorToInfoLog(char *msg)
278{
279    SETUP_CONTEXT(cpp);
280    context->error(yylineno, msg, "", "");
281    context->recover();
282}
283
284void SetLineNumber(int line)
285{
286    SETUP_CONTEXT(cpp);
287    int string = 0;
288    DecodeSourceLoc(yylineno, &string, NULL);
289    yylineno = EncodeSourceLoc(string, line);
290}
291
292void SetStringNumber(int string)
293{
294    SETUP_CONTEXT(cpp);
295    int line = 0;
296    DecodeSourceLoc(yylineno, NULL, &line);
297    yylineno = EncodeSourceLoc(string, line);
298}
299
300int GetStringNumber()
301{
302    SETUP_CONTEXT(cpp);
303    int string = 0;
304    DecodeSourceLoc(yylineno, &string, NULL);
305    return string;
306}
307
308int GetLineNumber()
309{
310    SETUP_CONTEXT(cpp);
311    int line = 0;
312    DecodeSourceLoc(yylineno, NULL, &line);
313    return line;
314}
315
316void IncLineNumber()
317{
318    SETUP_CONTEXT(cpp);
319    int string = 0, line = 0;
320    DecodeSourceLoc(yylineno, &string, &line);
321    yylineno = EncodeSourceLoc(string, ++line);
322}
323
324void DecLineNumber()
325{
326    SETUP_CONTEXT(cpp);
327    int string = 0, line = 0;
328    DecodeSourceLoc(yylineno, &string, &line);
329    yylineno = EncodeSourceLoc(string, --line);
330}
331
332void 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
416void StoreStr(char *string)
417{
418    SETUP_CONTEXT(cpp);
419    TString strSrc;
420    strSrc = TString(string);
421
422    context->HashErrMsg = context->HashErrMsg + " " + strSrc;
423}
424
425const char* GetStrfromTStr(void)
426{
427    SETUP_CONTEXT(cpp);
428    cpp->ErrMsg = context->HashErrMsg.c_str();
429    return cpp->ErrMsg;
430}
431
432void ResetTString(void)
433{
434    SETUP_CONTEXT(cpp);
435    context->HashErrMsg = "";
436}
437
438TBehavior 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
454void 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
491int 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
503int 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
519int 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
527void 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
538int 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
547int 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
555void 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