/* // // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // 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 (c) 2010 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // 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 "compiler/glslang.h" #include "compiler/ParseHelper.h" #include "compiler/util.h" #include "glslang_tab.h" /* windows only pragma */ #ifdef _MSC_VER #pragma warning(disable : 4102) #endif #define YY_USER_ACTION yylval->lex.line = yylineno; #define YY_INPUT(buf, result, max_size) \ result = string_input(buf, max_size, yyscanner); static int string_input(char* buf, int max_size, yyscan_t yyscanner); static int check_type(yyscan_t yyscanner); static int reserved_word(yyscan_t yyscanner); %} %option noyywrap nounput never-interactive %option yylineno reentrant bison-bridge %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); } . | \n ; "*/" { yy_pop_state(yyscanner); } "invariant" { return(INVARIANT); } "highp" { return(HIGH_PRECISION); } "mediump" { return(MEDIUM_PRECISION); } "lowp" { return(LOW_PRECISION); } "precision" { return(PRECISION); } "attribute" { return(ATTRIBUTE); } "const" { return(CONST_QUAL); } "uniform" { return(UNIFORM); } "varying" { return(VARYING); } "break" { return(BREAK); } "continue" { return(CONTINUE); } "do" { return(DO); } "for" { return(FOR); } "while" { return(WHILE); } "if" { return(IF); } "else" { return(ELSE); } "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); } "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); } "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); } "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; } "sampler2DRect" { context->lexAfterType = true; return SAMPLER2DRECT; } "struct" { context->lexAfterType = true; return(STRUCT); } "asm" { return reserved_word(yyscanner); } "class" { return reserved_word(yyscanner); } "union" { return reserved_word(yyscanner); } "enum" { return reserved_word(yyscanner); } "typedef" { return reserved_word(yyscanner); } "template" { return reserved_word(yyscanner); } "this" { return reserved_word(yyscanner); } "packed" { return reserved_word(yyscanner); } "goto" { return reserved_word(yyscanner); } "switch" { return reserved_word(yyscanner); } "default" { return reserved_word(yyscanner); } "inline" { return reserved_word(yyscanner); } "noinline" { return reserved_word(yyscanner); } "volatile" { return reserved_word(yyscanner); } "public" { return reserved_word(yyscanner); } "static" { return reserved_word(yyscanner); } "extern" { return reserved_word(yyscanner); } "external" { return reserved_word(yyscanner); } "interface" { return reserved_word(yyscanner); } "long" { return reserved_word(yyscanner); } "short" { return reserved_word(yyscanner); } "double" { return reserved_word(yyscanner); } "half" { return reserved_word(yyscanner); } "fixed" { return reserved_word(yyscanner); } "unsigned" { return reserved_word(yyscanner); } "input" { return reserved_word(yyscanner); } "output" { return reserved_word(yyscanner); } "hvec2" { return reserved_word(yyscanner); } "hvec3" { return reserved_word(yyscanner); } "hvec4" { return reserved_word(yyscanner); } "fvec2" { return reserved_word(yyscanner); } "fvec3" { return reserved_word(yyscanner); } "fvec4" { return reserved_word(yyscanner); } "dvec2" { return reserved_word(yyscanner); } "dvec3" { return reserved_word(yyscanner); } "dvec4" { return reserved_word(yyscanner); } "sizeof" { return reserved_word(yyscanner); } "cast" { return reserved_word(yyscanner); } "namespace" { return reserved_word(yyscanner); } "using" { return reserved_word(yyscanner); } {L}({L}|{D})* { yylval->lex.string = NewPoolTString(yytext); return check_type(yyscanner); } 0[xX]{H}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } 0{O}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } 0{D}+ { context->error(yylineno, "Invalid Octal number.", yytext, "", ""); context->recover(); return 0;} {D}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } {D}+{E} { yylval->lex.f = static_cast(atof_dot(yytext)); return(FLOATCONSTANT); } {D}+"."{D}*({E})? { yylval->lex.f = static_cast(atof_dot(yytext)); return(FLOATCONSTANT); } "."{D}+({E})? { yylval->lex.f = static_cast(atof_dot(yytext)); return(FLOATCONSTANT); } "+=" { 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); } {L}({L}|{D})* { BEGIN(INITIAL); yylval->lex.string = NewPoolTString(yytext); return FIELD_SELECTION; } [ \t\v\f\r] {} [ \t\v\n\f\r] { } <*><> { context->AfterEOF = true; yyterminate(); } <*>. { context->warning(yylineno, "Unknown char", yytext, ""); return 0; } %% extern "C" { // Preprocessor interface. #include "compiler/preprocessor/preprocess.h" #define SETUP_CONTEXT(pp) \ TParseContext* context = (TParseContext*) pp->pC; \ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; // Preprocessor callbacks. void CPPDebugLogMsg(const char *msg) { SETUP_CONTEXT(cpp); context->infoSink.debug.message(EPrefixNone, msg); } void CPPWarningToInfoLog(const char *msg) { SETUP_CONTEXT(cpp); context->warning(yylineno, msg, "", ""); } void CPPShInfoLogMsg(const char *msg) { SETUP_CONTEXT(cpp); context->error(yylineno, msg, "", ""); context->recover(); } void CPPErrorToInfoLog(char *msg) { SETUP_CONTEXT(cpp); context->error(yylineno, msg, "", ""); context->recover(); } void SetLineNumber(int line) { SETUP_CONTEXT(cpp); int string = 0; DecodeSourceLoc(yylineno, &string, NULL); yylineno = EncodeSourceLoc(string, line); } void SetStringNumber(int string) { SETUP_CONTEXT(cpp); int line = 0; DecodeSourceLoc(yylineno, NULL, &line); yylineno = EncodeSourceLoc(string, line); } int GetStringNumber() { SETUP_CONTEXT(cpp); int string = 0; DecodeSourceLoc(yylineno, &string, NULL); return string; } int GetLineNumber() { SETUP_CONTEXT(cpp); int line = 0; DecodeSourceLoc(yylineno, NULL, &line); return line; } void IncLineNumber() { SETUP_CONTEXT(cpp); int string = 0, line = 0; DecodeSourceLoc(yylineno, &string, &line); yylineno = EncodeSourceLoc(string, ++line); } void DecLineNumber() { SETUP_CONTEXT(cpp); int string = 0, line = 0; DecodeSourceLoc(yylineno, &string, &line); yylineno = EncodeSourceLoc(string, --line); } void HandlePragma(const char **tokens, int numTokens) { SETUP_CONTEXT(cpp); if (!strcmp(tokens[0], "optimize")) { if (numTokens != 4) { CPPShInfoLogMsg("optimize pragma syntax is incorrect"); return; } if (strcmp(tokens[1], "(")) { CPPShInfoLogMsg("\"(\" expected after 'optimize' keyword"); return; } if (!strcmp(tokens[2], "on")) context->contextPragma.optimize = true; else if (!strcmp(tokens[2], "off")) context->contextPragma.optimize = false; else { CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'optimize' pragma"); return; } if (strcmp(tokens[3], ")")) { CPPShInfoLogMsg("\")\" expected to end 'optimize' pragma"); return; } } else if (!strcmp(tokens[0], "debug")) { if (numTokens != 4) { CPPShInfoLogMsg("debug pragma syntax is incorrect"); return; } if (strcmp(tokens[1], "(")) { CPPShInfoLogMsg("\"(\" expected after 'debug' keyword"); return; } if (!strcmp(tokens[2], "on")) context->contextPragma.debug = true; else if (!strcmp(tokens[2], "off")) context->contextPragma.debug = false; else { CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'debug' pragma"); return; } if (strcmp(tokens[3], ")")) { CPPShInfoLogMsg("\")\" expected to end 'debug' pragma"); return; } } else { #ifdef PRAGMA_TABLE // // implementation specific pragma // use ((TParseContext *)cpp->pC)->contextPragma.pragmaTable to store the information about pragma // For now, just ignore the pragma that the implementation cannot recognize // An Example of one such implementation for a pragma that has a syntax like // #pragma pragmaname(pragmavalue) // This implementation stores the current pragmavalue against the pragma name in pragmaTable. // if (numTokens == 4 && !strcmp(tokens[1], "(") && !strcmp(tokens[3], ")")) { TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable; TPragmaTable::iterator iter; iter = pragmaTable.find(TString(tokens[0])); if (iter != pragmaTable.end()) { iter->second = tokens[2]; } else { pragmaTable[ tokens[0] ] = tokens[2]; } } else if (numTokens >= 2) { TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable; TPragmaTable::iterator iter; iter = pragmaTable.find(TString(tokens[0])); if (iter != pragmaTable.end()) { iter->second = tokens[1]; } else { pragmaTable[ tokens[0] ] = tokens[1]; } } #endif // PRAGMA_TABLE } } void StoreStr(char *string) { SETUP_CONTEXT(cpp); TString strSrc; strSrc = TString(string); context->HashErrMsg = context->HashErrMsg + " " + strSrc; } const char* GetStrfromTStr(void) { SETUP_CONTEXT(cpp); cpp->ErrMsg = context->HashErrMsg.c_str(); return cpp->ErrMsg; } void ResetTString(void) { SETUP_CONTEXT(cpp); context->HashErrMsg = ""; } TBehavior GetBehavior(const char* behavior) { if (!strcmp("require", behavior)) return EBhRequire; else if (!strcmp("enable", behavior)) return EBhEnable; else if (!strcmp("disable", behavior)) return EBhDisable; else if (!strcmp("warn", behavior)) return EBhWarn; else { CPPShInfoLogMsg((TString("behavior '") + behavior + "' is not supported").c_str()); return EBhDisable; } } void updateExtensionBehavior(const char* extName, const char* behavior) { SETUP_CONTEXT(cpp); TBehavior behaviorVal = GetBehavior(behavior); TMap:: iterator iter; TString msg; // special cased for all extension if (!strcmp(extName, "all")) { if (behaviorVal == EBhRequire || behaviorVal == EBhEnable) { CPPShInfoLogMsg("extension 'all' cannot have 'require' or 'enable' behavior"); return; } else { for (iter = context->extensionBehavior.begin(); iter != context->extensionBehavior.end(); ++iter) iter->second = behaviorVal; } } else { iter = context->extensionBehavior.find(TString(extName)); if (iter == context->extensionBehavior.end()) { switch (behaviorVal) { case EBhRequire: CPPShInfoLogMsg((TString("extension '") + extName + "' is not supported").c_str()); break; case EBhEnable: case EBhWarn: case EBhDisable: msg = TString("extension '") + extName + "' is not supported"; context->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno); break; default: break; } return; } else iter->second = behaviorVal; } } } // extern "C" int string_input(char* buf, int max_size, yyscan_t yyscanner) { int len; if ((len = yylex_CPP(buf, max_size)) == 0) return 0; if (len >= max_size) YY_FATAL_ERROR("input buffer overflow, can't enlarge buffer because scanner uses REJECT"); buf[len] = ' '; return len+1; } int check_type(yyscan_t yyscanner) { struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; int token = IDENTIFIER; TSymbol* symbol = yyextra->symbolTable.find(yytext); if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) { TVariable* variable = static_cast(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(yylineno, "Illegal use of reserved word", yytext, ""); yyextra->recover(); return 0; } void yyerror(TParseContext* context, const char* reason) { struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; if (context->AfterEOF) { context->error(yylineno, reason, "unexpected EOF", ""); } else { context->error(yylineno, reason, yytext, ""); } context->recover(); } int glslang_initialize(TParseContext* context) { yyscan_t scanner = NULL; if (yylex_init_extra(context, &scanner)) return 1; context->scanner = scanner; return 0; } int glslang_finalize(TParseContext* context) { yyscan_t scanner = context->scanner; if (scanner == NULL) return 0; context->scanner = NULL; return yylex_destroy(scanner); } void glslang_scan(int count, const char* const string[], const int length[], TParseContext* context) { yyrestart(NULL, context->scanner); yyset_lineno(EncodeSourceLoc(0, 1), context->scanner); context->AfterEOF = false; // Init preprocessor. cpp->pC = context; cpp->PaWhichStr = 0; cpp->PaArgv = string; cpp->PaArgc = count; cpp->PaStrLen = length; cpp->pastFirstStatement = 0; ScanFromString(string[0]); }