| /* | |
| // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| This file contains the Lex specification for GLSL ES. | |
| Based on ANSI C grammar, Lex specification: | |
| http://www.lysator.liu.se/c/ANSI-C-grammar-l.html | |
| IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, | |
| WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). | |
| */ | |
| %top{ | |
| // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // This file is auto-generated by generate_parser.sh. DO NOT EDIT! | |
| // Ignore errors in auto-generated code. | |
| #if defined(__GNUC__) | |
| #pragma GCC diagnostic ignored "-Wunused-function" | |
| #pragma GCC diagnostic ignored "-Wunused-variable" | |
| #pragma GCC diagnostic ignored "-Wswitch-enum" | |
| #elif defined(_MSC_VER) | |
| #pragma warning(disable: 4065) | |
| #pragma warning(disable: 4189) | |
| #pragma warning(disable: 4505) | |
| #pragma warning(disable: 4701) | |
| #endif | |
| } | |
| %{ | |
| #include "glslang.h" | |
| #include "ParseHelper.h" | |
| #include "preprocessor/Token.h" | |
| #include "util.h" | |
| #include "glslang_tab.h" | |
| /* windows only pragma */ | |
| #ifdef _MSC_VER | |
| #pragma warning(disable : 4102) | |
| #endif | |
| #define YY_USER_ACTION \ | |
| yylloc->first_file = yylloc->last_file = yycolumn; \ | |
| yylloc->first_line = yylloc->last_line = yylineno; | |
| #define YY_INPUT(buf, result, max_size) \ | |
| result = string_input(buf, max_size, yyscanner); | |
| static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner); | |
| static int check_type(yyscan_t yyscanner); | |
| static int reserved_word(yyscan_t yyscanner); | |
| static int ES2_reserved_ES3_keyword(TParseContext *context, int token); | |
| static int ES2_keyword_ES3_reserved(TParseContext *context, int token); | |
| static int ES2_identifier_ES3_keyword(TParseContext *context, int token); | |
| static int uint_constant(TParseContext *context); | |
| static int int_constant(yyscan_t yyscanner); | |
| static int float_constant(yyscan_t yyscanner); | |
| static int floatsuffix_check(TParseContext* context); | |
| %} | |
| %option noyywrap nounput never-interactive | |
| %option yylineno reentrant bison-bridge bison-locations | |
| %option stack | |
| %option extra-type="TParseContext*" | |
| %x COMMENT FIELDS | |
| D [0-9] | |
| L [a-zA-Z_] | |
| H [a-fA-F0-9] | |
| E [Ee][+-]?{D}+ | |
| O [0-7] | |
| %% | |
| %{ | |
| TParseContext* context = yyextra; | |
| %} | |
| /* Single-line comments */ | |
| "//"[^\n]* ; | |
| /* Multi-line comments */ | |
| "/*" { yy_push_state(COMMENT, yyscanner); } | |
| <COMMENT>. | | |
| <COMMENT>\n ; | |
| <COMMENT>"*/" { yy_pop_state(yyscanner); } | |
| "invariant" { return(INVARIANT); } | |
| "highp" { return(HIGH_PRECISION); } | |
| "mediump" { return(MEDIUM_PRECISION); } | |
| "lowp" { return(LOW_PRECISION); } | |
| "precision" { return(PRECISION); } | |
| "attribute" { return ES2_keyword_ES3_reserved(context, ATTRIBUTE); } | |
| "const" { return(CONST_QUAL); } | |
| "uniform" { return(UNIFORM); } | |
| "varying" { return ES2_keyword_ES3_reserved(context, VARYING); } | |
| "break" { return(BREAK); } | |
| "continue" { return(CONTINUE); } | |
| "do" { return(DO); } | |
| "for" { return(FOR); } | |
| "while" { return(WHILE); } | |
| "if" { return(IF); } | |
| "else" { return(ELSE); } | |
| "switch" { return ES2_reserved_ES3_keyword(context, SWITCH); } | |
| "case" { return ES2_reserved_ES3_keyword(context, CASE); } | |
| "default" { return ES2_reserved_ES3_keyword(context, DEFAULT); } | |
| "centroid" { return ES2_reserved_ES3_keyword(context, CENTROID); } | |
| "flat" { return ES2_reserved_ES3_keyword(context, FLAT); } | |
| "smooth" { return ES2_reserved_ES3_keyword(context, SMOOTH); } | |
| "in" { return(IN_QUAL); } | |
| "out" { return(OUT_QUAL); } | |
| "inout" { return(INOUT_QUAL); } | |
| "float" { context->lexAfterType = true; return(FLOAT_TYPE); } | |
| "int" { context->lexAfterType = true; return(INT_TYPE); } | |
| "uint" { return ES2_identifier_ES3_keyword(context, UINT_TYPE); } | |
| "void" { context->lexAfterType = true; return(VOID_TYPE); } | |
| "bool" { context->lexAfterType = true; return(BOOL_TYPE); } | |
| "true" { yylval->lex.b = true; return(BOOLCONSTANT); } | |
| "false" { yylval->lex.b = false; return(BOOLCONSTANT); } | |
| "discard" { return(DISCARD); } | |
| "return" { return(RETURN); } | |
| "mat2" { context->lexAfterType = true; return(MATRIX2); } | |
| "mat3" { context->lexAfterType = true; return(MATRIX3); } | |
| "mat4" { context->lexAfterType = true; return(MATRIX4); } | |
| "mat2x2" { return ES2_identifier_ES3_keyword(context, MATRIX2); } | |
| "mat3x3" { return ES2_identifier_ES3_keyword(context, MATRIX3); } | |
| "mat4x4" { return ES2_identifier_ES3_keyword(context, MATRIX4); } | |
| "mat2x3" { return ES2_identifier_ES3_keyword(context, MATRIX2x3); } | |
| "mat3x2" { return ES2_identifier_ES3_keyword(context, MATRIX3x2); } | |
| "mat2x4" { return ES2_identifier_ES3_keyword(context, MATRIX2x4); } | |
| "mat4x2" { return ES2_identifier_ES3_keyword(context, MATRIX4x2); } | |
| "mat3x4" { return ES2_identifier_ES3_keyword(context, MATRIX3x4); } | |
| "mat4x3" { return ES2_identifier_ES3_keyword(context, MATRIX4x3); } | |
| "vec2" { context->lexAfterType = true; return (VEC2); } | |
| "vec3" { context->lexAfterType = true; return (VEC3); } | |
| "vec4" { context->lexAfterType = true; return (VEC4); } | |
| "ivec2" { context->lexAfterType = true; return (IVEC2); } | |
| "ivec3" { context->lexAfterType = true; return (IVEC3); } | |
| "ivec4" { context->lexAfterType = true; return (IVEC4); } | |
| "uvec2" { return ES2_identifier_ES3_keyword(context, UVEC2); } | |
| "uvec3" { return ES2_identifier_ES3_keyword(context, UVEC3); } | |
| "uvec4" { return ES2_identifier_ES3_keyword(context, UVEC4); } | |
| "bvec2" { context->lexAfterType = true; return (BVEC2); } | |
| "bvec3" { context->lexAfterType = true; return (BVEC3); } | |
| "bvec4" { context->lexAfterType = true; return (BVEC4); } | |
| "sampler2D" { context->lexAfterType = true; return SAMPLER2D; } | |
| "samplerCube" { context->lexAfterType = true; return SAMPLERCUBE; } | |
| "samplerExternalOES" { context->lexAfterType = true; return SAMPLER_EXTERNAL_OES; } | |
| "sampler3D" { context->lexAfterType = true; return SAMPLER3D; } | |
| "sampler3DRect" { return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); } | |
| "sampler2DArray" { return ES2_identifier_ES3_keyword(context, SAMPLER2DARRAY); } | |
| "isampler2D" { return ES2_identifier_ES3_keyword(context, ISAMPLER2D); } | |
| "isampler3D" { return ES2_identifier_ES3_keyword(context, ISAMPLER3D); } | |
| "isamplerCube" { return ES2_identifier_ES3_keyword(context, ISAMPLERCUBE); } | |
| "isampler2DArray" { return ES2_identifier_ES3_keyword(context, ISAMPLER2DARRAY); } | |
| "usampler2D" { return ES2_identifier_ES3_keyword(context, USAMPLER2D); } | |
| "usampler3D" { return ES2_identifier_ES3_keyword(context, USAMPLER3D); } | |
| "usamplerCube" { return ES2_identifier_ES3_keyword(context, USAMPLERCUBE); } | |
| "usampler2DArray" { return ES2_identifier_ES3_keyword(context, USAMPLER2DARRAY); } | |
| "sampler2DShadow" { return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); } | |
| "samplerCubeShadow" { return ES2_identifier_ES3_keyword(context, SAMPLERCUBESHADOW); } | |
| "sampler2DArrayShadow" { return ES2_identifier_ES3_keyword(context, SAMPLER2DARRAYSHADOW); } | |
| "struct" { context->lexAfterType = true; return(STRUCT); } | |
| "layout" { return ES2_identifier_ES3_keyword(context, LAYOUT); } | |
| /* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */ | |
| "coherent" | | |
| "restrict" | | |
| "readonly" | | |
| "writeonly" | | |
| "resource" | | |
| "atomic_uint" | | |
| "noperspective" | | |
| "patch" | | |
| "sample" | | |
| "subroutine" | | |
| "common" | | |
| "partition" | | |
| "active" | | |
| "filter" | | |
| "image1D" | | |
| "image2D" | | |
| "image3D" | | |
| "imageCube" | | |
| "iimage1D" | | |
| "iimage2D" | | |
| "iimage3D" | | |
| "iimageCube" | | |
| "uimage1D" | | |
| "uimage2D" | | |
| "uimage3D" | | |
| "uimageCube" | | |
| "image1DArray" | | |
| "image2DArray" | | |
| "iimage1DArray" | | |
| "iimage2DArray" | | |
| "uimage1DArray" | | |
| "uimage2DArray" | | |
| "image1DShadow" | | |
| "image2DShadow" | | |
| "image1DArrayShadow" | | |
| "image2DArrayShadow" | | |
| "imageBuffer" | | |
| "iimageBuffer" | | |
| "uimageBuffer" | | |
| "sampler1DArray" | | |
| "sampler1DArrayShadow" | | |
| "isampler1D" | | |
| "isampler1DArray" | | |
| "usampler1D" | | |
| "usampler1DArray" | | |
| "isampler2DRect" | | |
| "usampler2DRect" | | |
| "samplerBuffer" | | |
| "isamplerBuffer" | | |
| "usamplerBuffer" | | |
| "sampler2DMS" | | |
| "isampler2DMS" | | |
| "usampler2DMS" | | |
| "sampler2DMSArray" | | |
| "isampler2DMSArray" | | |
| "usampler2DMSArray" { | |
| if (context->getShaderVersion() < 300) { | |
| yylval->lex.string = NewPoolTString(yytext); | |
| return check_type(yyscanner); | |
| } | |
| return reserved_word(yyscanner); | |
| } | |
| /* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */ | |
| "packed" { | |
| if (context->getShaderVersion() >= 300) | |
| { | |
| yylval->lex.string = NewPoolTString(yytext); | |
| return check_type(yyscanner); | |
| } | |
| return reserved_word(yyscanner); | |
| } | |
| /* Reserved keywords */ | |
| "asm" | | |
| "class" | | |
| "union" | | |
| "enum" | | |
| "typedef" | | |
| "template" | | |
| "this" | | |
| "goto" | | |
| "inline" | | |
| "noinline" | | |
| "volatile" | | |
| "public" | | |
| "static" | | |
| "extern" | | |
| "external" | | |
| "interface" | | |
| "long" | | |
| "short" | | |
| "double" | | |
| "half" | | |
| "fixed" | | |
| "unsigned" | | |
| "superp" | | |
| "input" | | |
| "output" | | |
| "hvec2" | | |
| "hvec3" | | |
| "hvec4" | | |
| "dvec2" | | |
| "dvec3" | | |
| "dvec4" | | |
| "fvec2" | | |
| "fvec3" | | |
| "fvec4" | | |
| "sampler1D" | | |
| "sampler1DShadow" | | |
| "sampler2DRect" | | |
| "sampler2DRectShadow" | | |
| "sizeof" | | |
| "cast" | | |
| "namespace" | | |
| "using" { return reserved_word(yyscanner); } | |
| {L}({L}|{D})* { | |
| yylval->lex.string = NewPoolTString(yytext); | |
| return check_type(yyscanner); | |
| } | |
| 0[xX]{H}+ { return int_constant(yyscanner); } | |
| 0{O}+ { return int_constant(yyscanner); } | |
| {D}+ { return int_constant(yyscanner); } | |
| 0[xX]{H}+[uU] { return uint_constant(context); } | |
| 0{O}+[uU] { return uint_constant(context); } | |
| {D}+[uU] { return uint_constant(context); } | |
| {D}+{E} { return float_constant(yyscanner); } | |
| {D}+"."{D}*({E})? { return float_constant(yyscanner); } | |
| "."{D}+({E})? { return float_constant(yyscanner); } | |
| {D}+{E}[fF] { return floatsuffix_check(context); } | |
| {D}+"."{D}*({E})?[fF] { return floatsuffix_check(context); } | |
| "."{D}+({E})?[fF] { return floatsuffix_check(context); } | |
| "+=" { return(ADD_ASSIGN); } | |
| "-=" { return(SUB_ASSIGN); } | |
| "*=" { return(MUL_ASSIGN); } | |
| "/=" { return(DIV_ASSIGN); } | |
| "%=" { return(MOD_ASSIGN); } | |
| "<<=" { return(LEFT_ASSIGN); } | |
| ">>=" { return(RIGHT_ASSIGN); } | |
| "&=" { return(AND_ASSIGN); } | |
| "^=" { return(XOR_ASSIGN); } | |
| "|=" { return(OR_ASSIGN); } | |
| "++" { return(INC_OP); } | |
| "--" { return(DEC_OP); } | |
| "&&" { return(AND_OP); } | |
| "||" { return(OR_OP); } | |
| "^^" { return(XOR_OP); } | |
| "<=" { return(LE_OP); } | |
| ">=" { return(GE_OP); } | |
| "==" { return(EQ_OP); } | |
| "!=" { return(NE_OP); } | |
| "<<" { return(LEFT_OP); } | |
| ">>" { return(RIGHT_OP); } | |
| ";" { context->lexAfterType = false; return(SEMICOLON); } | |
| ("{"|"<%") { context->lexAfterType = false; return(LEFT_BRACE); } | |
| ("}"|"%>") { return(RIGHT_BRACE); } | |
| "," { if (context->inTypeParen) context->lexAfterType = false; return(COMMA); } | |
| ":" { return(COLON); } | |
| "=" { context->lexAfterType = false; return(EQUAL); } | |
| "(" { context->lexAfterType = false; context->inTypeParen = true; return(LEFT_PAREN); } | |
| ")" { context->inTypeParen = false; return(RIGHT_PAREN); } | |
| ("["|"<:") { return(LEFT_BRACKET); } | |
| ("]"|":>") { return(RIGHT_BRACKET); } | |
| "." { BEGIN(FIELDS); return(DOT); } | |
| "!" { return(BANG); } | |
| "-" { return(DASH); } | |
| "~" { return(TILDE); } | |
| "+" { return(PLUS); } | |
| "*" { return(STAR); } | |
| "/" { return(SLASH); } | |
| "%" { return(PERCENT); } | |
| "<" { return(LEFT_ANGLE); } | |
| ">" { return(RIGHT_ANGLE); } | |
| "|" { return(VERTICAL_BAR); } | |
| "^" { return(CARET); } | |
| "&" { return(AMPERSAND); } | |
| "?" { return(QUESTION); } | |
| <FIELDS>{L}({L}|{D})* { | |
| BEGIN(INITIAL); | |
| yylval->lex.string = NewPoolTString(yytext); | |
| return FIELD_SELECTION; | |
| } | |
| <FIELDS>[ \t\v\f\r] {} | |
| [ \t\v\n\f\r] { } | |
| <*><<EOF>> { context->AfterEOF = true; yyterminate(); } | |
| <*>. { context->warning(*yylloc, "Unknown char", yytext, ""); return 0; } | |
| %% | |
| yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) { | |
| pp::Token token; | |
| yyget_extra(yyscanner)->getPreprocessor().lex(&token); | |
| yy_size_t len = token.type == pp::Token::LAST ? 0 : token.text.size(); | |
| if (len < max_size) | |
| memcpy(buf, token.text.c_str(), len); | |
| yyset_column(token.location.file, yyscanner); | |
| yyset_lineno(token.location.line, yyscanner); | |
| if (len >= max_size) | |
| YY_FATAL_ERROR("Input buffer overflow"); | |
| else if (len > 0) | |
| buf[len++] = ' '; | |
| return len; | |
| } | |
| int check_type(yyscan_t yyscanner) { | |
| struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; | |
| int token = IDENTIFIER; | |
| TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->getShaderVersion()); | |
| if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) { | |
| TVariable* variable = static_cast<TVariable*>(symbol); | |
| if (variable->isUserType()) { | |
| yyextra->lexAfterType = true; | |
| token = TYPE_NAME; | |
| } | |
| } | |
| yylval->lex.symbol = symbol; | |
| return token; | |
| } | |
| int reserved_word(yyscan_t yyscanner) { | |
| struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; | |
| yyextra->error(*yylloc, "Illegal use of reserved word", yytext, ""); | |
| yyextra->recover(); | |
| return 0; | |
| } | |
| int ES2_reserved_ES3_keyword(TParseContext *context, int token) | |
| { | |
| yyscan_t yyscanner = (yyscan_t) context->getScanner(); | |
| if (context->getShaderVersion() < 300) | |
| { | |
| return reserved_word(yyscanner); | |
| } | |
| return token; | |
| } | |
| int ES2_keyword_ES3_reserved(TParseContext *context, int token) | |
| { | |
| yyscan_t yyscanner = (yyscan_t) context->getScanner(); | |
| if (context->getShaderVersion() >= 300) | |
| { | |
| return reserved_word(yyscanner); | |
| } | |
| return token; | |
| } | |
| int ES2_identifier_ES3_keyword(TParseContext *context, int token) | |
| { | |
| struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); | |
| yyscan_t yyscanner = (yyscan_t) context->getScanner(); | |
| // not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name | |
| if (context->getShaderVersion() < 300) | |
| { | |
| yylval->lex.string = NewPoolTString(yytext); | |
| return check_type(yyscanner); | |
| } | |
| return token; | |
| } | |
| int uint_constant(TParseContext *context) | |
| { | |
| struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); | |
| yyscan_t yyscanner = (yyscan_t) context->getScanner(); | |
| if (context->getShaderVersion() < 300) | |
| { | |
| context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, ""); | |
| context->recover(); | |
| return 0; | |
| } | |
| if (!atoi_clamp(yytext, &(yylval->lex.i))) | |
| yyextra->warning(*yylloc, "Integer overflow", yytext, ""); | |
| return UINTCONSTANT; | |
| } | |
| int floatsuffix_check(TParseContext* context) | |
| { | |
| struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); | |
| if (context->getShaderVersion() < 300) | |
| { | |
| context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext); | |
| context->recover(); | |
| return 0; | |
| } | |
| if (!atof_clamp(yytext, &(yylval->lex.f))) | |
| yyextra->warning(*yylloc, "Float overflow", yytext, ""); | |
| return(FLOATCONSTANT); | |
| } | |
| int int_constant(yyscan_t yyscanner) { | |
| struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; | |
| if (!atoi_clamp(yytext, &(yylval->lex.i))) | |
| yyextra->warning(*yylloc, "Integer overflow", yytext, ""); | |
| return INTCONSTANT; | |
| } | |
| int float_constant(yyscan_t yyscanner) { | |
| struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; | |
| if (!atof_clamp(yytext, &(yylval->lex.f))) | |
| yyextra->warning(*yylloc, "Float overflow", yytext, ""); | |
| return FLOATCONSTANT; | |
| } | |
| void yyerror(YYLTYPE* lloc, TParseContext* context, void* scanner, const char* reason) { | |
| struct yyguts_t* yyg = (struct yyguts_t*) scanner; | |
| if (context->AfterEOF) { | |
| context->error(*lloc, reason, "unexpected EOF"); | |
| } else { | |
| context->error(*lloc, reason, yytext); | |
| } | |
| context->recover(); | |
| } | |
| int glslang_initialize(TParseContext* context) { | |
| yyscan_t scanner = NULL; | |
| if (yylex_init_extra(context, &scanner)) | |
| return 1; | |
| context->setScanner(scanner); | |
| return 0; | |
| } | |
| int glslang_finalize(TParseContext* context) { | |
| yyscan_t scanner = context->getScanner(); | |
| if (scanner == NULL) return 0; | |
| context->setScanner(NULL); | |
| yylex_destroy(scanner); | |
| return 0; | |
| } | |
| int glslang_scan(size_t count, const char* const string[], const int length[], | |
| TParseContext* context) { | |
| yyrestart(NULL, context->getScanner()); | |
| yyset_column(0, context->getScanner()); | |
| yyset_lineno(1, context->getScanner()); | |
| context->AfterEOF = false; | |
| // Initialize preprocessor. | |
| if (!context->getPreprocessor().init(count, string, length)) | |
| return 1; | |
| // Define extension macros. | |
| const TExtensionBehavior& extBehavior = context->extensionBehavior(); | |
| for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); | |
| iter != extBehavior.end(); ++iter) | |
| { | |
| context->getPreprocessor().predefineMacro(iter->first.c_str(), 1); | |
| } | |
| context->getPreprocessor().predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1); | |
| return 0; | |
| } | |