Edit

kc3-lang/angle/src/compiler/glslang.l

Branch :

  • Show log

    Commit

  • Author : alokp@chromium.org
    Date : 2012-04-05 15:54:43
    Hash : 408c45e7
    Message : Added an alternate lexer for the existing preprocessor. It is still behind a compile-time flag. Review URL: https://codereview.appspot.com/5976072 git-svn-id: https://angleproject.googlecode.com/svn/trunk@1019 736b8ea6-26fd-11df-bfd4-992fa37f6226

  • src/compiler/glslang.l
  • /*
    //
    // 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); }
    <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(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<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
    {D}+"."{D}*({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
    "."{D}+({E})?     { yylval->lex.f = static_cast<float>(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); }
    
    <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(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<TString, TBehavior>:: 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<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(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);
    }
    
    int 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->pastFirstStatement = 0;
        return InitScannerInput(cpp, count, string, length);
    }