/*
//
// Copyright (c) 2011 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 Yacc grammar for GLSL ES preprocessor.
Based on Microsoft Visual Studio 2010 Preprocessor Grammar:
http://msdn.microsoft.com/en-us/library/2scxys89.aspx

IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_glsl_parser.sh,
WHICH GENERATES THE GLSL ES PARSER.
*/

%{
//
// Copyright (c) 2011 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_glslang_parser.sh. DO NOT EDIT!

#include "Context.h"
#include "Preprocessor.h"

#define YYLEX_PARAM context->lexer
#define YYDEBUG 1
%}

%pure-parser
%name-prefix="pp"
%locations
%parse-param {pp::Context* context}

%union {
    int ival;
    pp::Token* tval;
    pp::TokenVector* tlist;
}

%{
extern int yylex(YYSTYPE* lvalp, YYLTYPE* llocp, void* lexer);
static void yyerror(YYLTYPE* llocp,
                    pp::Context* context,
                    const char* reason);

static void defineMacro(pp::Context* context,
                        YYLTYPE* llocp,
                        pp::Macro::Type type,
                        pp::Token* identifier,
                        pp::TokenVector* parameters,
                        pp::TokenVector* replacements);
static void undefineMacro(pp::Context* context, pp::Token* identifier);
static bool isMacroDefined(pp::Context* context, pp::Token* identifier);
static void pushConditionalBlock(pp::Context* context, bool condition);
static void popConditionalBlock(pp::Context* context);
%}

%token HASH HASH_DEFINE_OBJ HASH_DEFINE_FUNC HASH_UNDEF
%token HASH_IF HASH_IFDEF HASH_IFNDEF HASH_ELSE HASH_ELIF HASH_ENDIF DEFINED
%token HASH_ERROR HASH_PRAGMA HASH_EXTENSION HASH_VERSION HASH_LINE
%token SPACE
%token <tval> IDENTIFIER INTEGER_CONSTANT FLOAT_CONSTANT
%type <ival> operator
%type <tval> conditional_token token
%type <tlist> text_line parameter_list replacement_token_list conditional_token_list token_list
%%

input
    : /* empty */
    | input line
;

line
    : text_line
    | control_line
;

text_line
    : '\n' { $$ = NULL; }
    | token_list '\n' { $$ = $1; }
;

control_line
    : HASH '\n'
    | HASH_DEFINE_OBJ IDENTIFIER replacement_token_list '\n' {
        defineMacro(context, & @2, pp::Macro::kTypeObj, $2, NULL, $3);
    }
    | HASH_DEFINE_FUNC IDENTIFIER '(' parameter_list ')' replacement_token_list '\n' {
        defineMacro(context, & @2, pp::Macro::kTypeFunc, $2, $4, $6);
    }
    | HASH_UNDEF IDENTIFIER '\n' {
        undefineMacro(context, $2);
    }
    | HASH_IF conditional_token_list '\n' {
        pushConditionalBlock(context, $2 ? true : false);
    }
    | HASH_IFDEF IDENTIFIER '\n' {
        pushConditionalBlock(context, isMacroDefined(context, $2));
    }
    | HASH_IFNDEF IDENTIFIER '\n' {
        pushConditionalBlock(context, !isMacroDefined(context, $2));
    }
    | HASH_ELIF conditional_token_list '\n' {
    }
    | HASH_ELSE '\n' {
    }
    | HASH_ENDIF '\n' {
        popConditionalBlock(context);
    }
    | HASH_ERROR '\n'
    | HASH_PRAGMA '\n'
    | HASH_EXTENSION '\n'
    | HASH_VERSION '\n'
    | HASH_LINE '\n'
;

replacement_token_list
    : /* empty */ { $$ = NULL }
    | token_list
;

conditional_token_list
    : conditional_token {
        $$ = new pp::TokenVector;
        $$->push_back($1);
    }
    | conditional_token_list conditional_token {
        $$ = $1;
        $$->push_back($2);
    }
;

conditional_token
    : DEFINED IDENTIFIER {
    }
    | DEFINED '(' IDENTIFIER ')' {
    }
    | token
;

parameter_list
    : /* empty */ { $$ = NULL; }
    | IDENTIFIER {
        $$ = new pp::TokenVector;
        $$->push_back($1);
    }
    | parameter_list ',' IDENTIFIER {
        $$ = $1;
        $$->push_back($3);
    }
;

token_list
    : token {
        //context->ppData.skipWS = false;
        $$ = new pp::TokenVector;
        $$->push_back($1);
    }
    | token_list token {
        $$ = $1;
        $$->push_back($2);
    }
;

token
    : IDENTIFIER
    | INTEGER_CONSTANT
    | FLOAT_CONSTANT
    | SPACE { $$ = new pp::Token(@1.first_line, SPACE); }
    | operator { $$ = new pp::Token(@1.first_line, $1); }
;

operator
    : '[' { $$ = '['; }
    | ']' { $$ = ']'; }
    | '<' { $$ = '<'; }
    | '>' { $$ = '>'; }
    | '(' { $$ = '('; }
    | ')' { $$ = ')'; }
    | '{' { $$ = '{'; }
    | '}' { $$ = '}'; }
    | '.' { $$ = '.'; }
    | '+' { $$ = '+'; }
    | '-' { $$ = '-'; }
    | '/' { $$ = '/'; }
    | '*' { $$ = '*'; }
    | '%' { $$ = '%'; }
    | '^' { $$ = '^'; }
    | '|' { $$ = '|'; }
    | '&' { $$ = '&'; }
    | '~' { $$ = '~'; }
    | '=' { $$ = '='; }
    | '!' { $$ = '!'; }
    | ':' { $$ = ':'; }
    | ';' { $$ = ';'; }
    | ',' { $$ = ','; }
    | '?' { $$ = '?'; }
;

%%

void yyerror(YYLTYPE* llocp, pp::Context* context, const char* reason)
{
}

void defineMacro(pp::Context* context,
                 YYLTYPE* llocp,
                 pp::Macro::Type type,
                 pp::Token* identifier,
                 pp::TokenVector* parameters,
                 pp::TokenVector* replacements)
{
}

void undefineMacro(pp::Context* context, pp::Token* identifier)
{
}

bool isMacroDefined(pp::Context* context, pp::Token* identifier)
{
    return false;
}

void pushConditionalBlock(pp::Context* context, bool condition)
{
}

void popConditionalBlock(pp::Context* context)
{
}

namespace pp {
bool Preprocessor::parse(Context* context)
{
    yydebug = 1;
    return yyparse(context) == 0 ? true : false;
}
}  // namespace pp

