/*
//
// Copyright (c) 2002-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 Lex specification 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_parser.sh.
*/

%top{
//
// 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_parser.sh. DO NOT EDIT!
}

%{
#include "compiler/debug.h"
#include "Context.h"
#include "pp_tab.h"
#include "Preprocessor.h"

#define YY_USER_ACTION                        \
    do {                                      \
        yylloc->first_line = yylineno;        \
        yylloc->first_column = yycolumn + 1;  \
        yycolumn += yyleng;                   \
    } while(0);
    
#define YY_INPUT(buf, result, maxSize) \
    result = readInput(yyextra, buf, maxSize);

static int readInput(pp::Context* context, char* buf, int maxSize);
%}

%option noyywrap nounput never-interactive
%option yylineno reentrant bison-bridge bison-locations
%option stack
%option prefix="pp"
%option extra-type="pp::Context*"

HSPACE      [ \t]
HASH        ^{HSPACE}*#{HSPACE}*
IDENTIFIER  [_a-zA-Z][_a-zA-Z0-9]*
PUNCTUATOR  [][<>(){}.+-/*%^|&~=!:;,?]

DECIMAL_CONSTANT      [1-9][0-9]*
OCTAL_CONSTANT        0[0-7]*
HEXADECIMAL_CONSTANT  0[xX][0-9a-fA-F]+

%%

{HASH} { return HASH; }

{HASH}define { return HASH_DEFINE_OBJ; }
{HASH}define{HSPACE}+/{IDENTIFIER}"(" { return HASH_DEFINE_FUNC; }
{HASH}undef { return HASH_UNDEF; }

{HASH}if { return HASH_IF; }
{HASH}ifdef { return HASH_IFDEF; }
{HASH}ifndef { return HASH_IFNDEF; }
{HASH}else { return HASH_ELSE; }
{HASH}elif { return HASH_ELIF; }
{HASH}endif { return HASH_ENDIF; }
"defined" { return DEFINED; }

{HASH}error { return HASH_ERROR; }
{HASH}pragma { return HASH_PRAGMA; }
{HASH}extension { return HASH_EXTENSION; }
{HASH}version { return HASH_VERSION; }
{HASH}line { return HASH_LINE; }

{IDENTIFIER} {
    yylval->tval = new pp::Token(yylineno, IDENTIFIER, std::string(yytext, yyleng));
    return IDENTIFIER;
}

{DECIMAL_CONSTANT}|{OCTAL_CONSTANT}|{HEXADECIMAL_CONSTANT} {
    yylval->tval = new pp::Token(yylineno, INTEGER_CONSTANT, std::string(yytext, yyleng));
    return INTEGER_CONSTANT;
}

{PUNCTUATOR} { return yytext[0]; }

{HSPACE}+ { return SPACE; }

\n {
    ++yylineno; yycolumn = 0;
    return yytext[0];
}

<*><<EOF>>     { yyterminate(); }

%%

int readInput(pp::Context* context, char* buf, int maxSize)
{
    yyscan_t lexer = context->lexer;
    ASSERT(lexer);

    int nread = YY_NULL;
    while (!context->input.eof() &&
           (context->input.error() == pp::Input::kErrorNone) &&
           (nread == YY_NULL))
    {
        int line = 0, file = 0;
        pp::Token::decodeLocation(yyget_lineno(lexer), &line, &file);
        file = context->input.stringIndex();
        yyset_lineno(pp::Token::encodeLocation(line, file), lexer);

        nread = context->input.read(buf, maxSize);

        if (context->input.error() == pp::Input::kErrorUnexpectedEOF)
        {
            // TODO(alokp): Report error.
        }
    }
    return nread;
}

namespace pp {

bool Preprocessor::initLexer(Context* context)
{
    ASSERT(context->lexer == NULL);

    yyscan_t lexer = 0;
    if (yylex_init_extra(context, &lexer))
        return false;

    context->lexer = lexer;
    yyrestart(0, lexer);
    return true;
}

void Preprocessor::destroyLexer(Context* context)
{
    ASSERT(context->lexer);

    yylex_destroy(context->lexer);
    context->lexer = 0;
}

}  // namespace pp

