/*
//
// 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 "Input.h"
#include "Lexer.h"
#include "Token.h"

typedef std::string YYSTYPE;
typedef pp::Token::Location YYLTYPE;

#define YY_USER_ACTION           \
    do {                         \
        yylloc->line = yylineno; \
        yylloc->string = 0;      \
    } while(0);

#define YY_INPUT(buf, result, maxSize) \
    result = readInput(buf, maxSize, yyscanner);

static int readInput(char* buf, int maxSize, yyscan_t scanner);
%}

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

NEWLINE     "\n"|"\r"|"\r\n"
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]+

DIGIT                [0-9]
EXPONENT_PART        [eE][+-]?{DIGIT}+
FRACTIONAL_CONSTANT  ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")

%%

# { return yytext[0]; }

{IDENTIFIER} {
    yylval->assign(yytext, yyleng);
    return pp::Token::IDENTIFIER;
}

{DECIMAL_CONSTANT}|{OCTAL_CONSTANT}|{HEXADECIMAL_CONSTANT} {
    yylval->assign(yytext, yyleng);
    return pp::Token::CONST_INT;
}

({DIGIT}+{EXPONENT_PART})|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?) {
    yylval->assign(yytext, yyleng);
    return pp::Token::CONST_FLOAT;
}

    /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */
    /* Rule to catch all invalid integers and floats. */
({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) {
    yylval->assign(yytext, yyleng);
    return pp::Token::INVALID_NUMBER;
}

"++"  { return pp::Token::OP_INC; }
"--"  { return pp::Token::OP_DEC; }
"<<"  { return pp::Token::OP_LEFT; }
">>"  { return pp::Token::OP_RIGHT; }
"<="  { return pp::Token::OP_LE; }
">="  { return pp::Token::OP_GE; }
"=="  { return pp::Token::OP_EQ; }
"!="  { return pp::Token::OP_NE; }
"&&"  { return pp::Token::OP_AND; }
"^^"  { return pp::Token::OP_XOR; }
"||"  { return pp::Token::OP_OR; }
"+="  {  return pp::Token::OP_ADD_ASSIGN; }
"-="  {  return pp::Token::OP_SUB_ASSIGN; }
"*="  {  return pp::Token::OP_MUL_ASSIGN; }
"/="  {  return pp::Token::OP_DIV_ASSIGN; }
"%="  {  return pp::Token::OP_MOD_ASSIGN; }
"<<=" {  return pp::Token::OP_LEFT_ASSIGN; }
">>=" {  return pp::Token::OP_RIGHT_ASSIGN; }
"&="  {  return pp::Token::OP_AND_ASSIGN; }
"^="  {  return pp::Token::OP_XOR_ASSIGN; }
"|="  {  return pp::Token::OP_OR_ASSIGN; }

{PUNCTUATOR} { return yytext[0]; }
[ \t\v\f]+   { return ' '; }

{NEWLINE} {
    ++yylineno;
    return '\n';
}

. {
    yylval->push_back(yytext[0]);
    return pp::Token::INVALID_CHARACTER;
}

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

%%

int readInput(char* buf, int maxSize, yyscan_t scanner)
{
    int nread = YY_NULL;
    pp::Input* input = yyget_extra(scanner);
    while (!input->eof() &&
           (input->error() == pp::Input::kErrorNone) &&
           (nread == YY_NULL))
    {
        nread = input->read(buf, maxSize);
    }
    return nread;
}

namespace pp {

int Lexer::lex(Token* token)
{
    token->type = yylex(&token->value, &token->location, mHandle);
    while (token->type == ' ')
    {
        mLeadingSpace = true;
        token->type = yylex(&token->value, &token->location, mHandle);
    }
    token->setHasLeadingSpace(mLeadingSpace);
    mLeadingSpace = false;

    return token->type;
}

bool Lexer::initLexer()
{
    if ((mHandle == NULL) && yylex_init_extra(mInput.get(), &mHandle))
        return false;

    yyrestart(0, mHandle);
    return true;
}

void Lexer::destroyLexer()
{
    if (mHandle == NULL)
        return;

    yylex_destroy(mHandle);
    mHandle = NULL;
}

}  // namespace pp

