/*
 * HLSL parser
 *
 * Copyright 2008 Stefan Dösinger
 * Copyright 2012 Matteo Bruni for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

%{
#include "wine/debug.h"

#define YY_NO_UNISTD_H
#include "d3dcompiler_private.h"
#include "hlsl.tab.h"

WINE_DEFAULT_DEBUG_CHANNEL(hlsl_parser);

#define YY_USER_ACTION                               \
   do {                                              \
      hlsl_lloc.first_column = hlsl_ctx.column;      \
      hlsl_lloc.first_line = hlsl_ctx.line_no;       \
      hlsl_ctx.column += yyleng;                     \
   } while(0);

%}

%option noyywrap nounput noinput never-interactive
%option prefix="hlsl_"

%x pp pp_line pp_pragma pp_ignore

RESERVED1               auto|case|catch|char|class|const_cast|default|delete|dynamic_cast|enum
RESERVED2               explicit|friend|goto|long|mutable|new|operator|private|protected|public
RESERVED3               reinterpret_cast|short|signed|sizeof|static_cast|template|this|throw|try
RESERVED4               typename|union|unsigned|using|virtual

WS                      [ \t]
NEWLINE                 (\n)|(\r\n)
DOUBLESLASHCOMMENT      "//"[^\n]*
STRING                  \"[^\"]*\"
IDENTIFIER              [A-Za-z_][A-Za-z0-9_]*

ANY                     (.)

%%
{RESERVED1}             {
                            hlsl_message("Line %u: Reserved keyword \"%s\" used.\n", hlsl_ctx.line_no, yytext);
                            set_parse_status(&hlsl_ctx.status, PARSE_ERR);
                        }
{RESERVED2}             {
                            hlsl_message("Line %u: Reserved keyword \"%s\" used.\n", hlsl_ctx.line_no, yytext);
                            set_parse_status(&hlsl_ctx.status, PARSE_ERR);
                        }
{RESERVED3}             {
                            hlsl_message("Line %u: Reserved keyword \"%s\" used.\n", hlsl_ctx.line_no, yytext);
                            set_parse_status(&hlsl_ctx.status, PARSE_ERR);
                        }
{RESERVED4}             {
                            hlsl_message("Line %u: Reserved keyword \"%s\" used.\n", hlsl_ctx.line_no, yytext);
                            set_parse_status(&hlsl_ctx.status, PARSE_ERR);
                        }

BlendState              {return KW_BLENDSTATE;          }
break                   {return KW_BREAK;               }
Buffer                  {return KW_BUFFER;              }
cbuffer                 {return KW_CBUFFER;             }
compile                 {return KW_COMPILE;             }
const                   {return KW_CONST;               }
continue                {return KW_CONTINUE;            }
DepthStencilState       {return KW_DEPTHSTENCILSTATE;   }
DepthStencilView        {return KW_DEPTHSTENCILVIEW;    }
discard                 {return KW_DISCARD;             }
do                      {return KW_DO;                  }
double                  {return KW_DOUBLE;              }
else                    {return KW_ELSE;                }
extern                  {return KW_EXTERN;              }
false                   {return KW_FALSE;               }
for                     {return KW_FOR;                 }
GeometryShader          {return KW_GEOMETRYSHADER;      }
groupshared             {return KW_GROUPSHARED;         }
if                      {return KW_IF;                  }
in                      {return KW_IN;                  }
inline                  {return KW_INLINE;              }
inout                   {return KW_INOUT;               }
matrix                  {return KW_MATRIX;              }
namespace               {return KW_NAMESPACE;           }
nointerpolation         {return KW_NOINTERPOLATION;     }
out                     {return KW_OUT;                 }
pass                    {return KW_PASS;                }
PixelShader             {return KW_PIXELSHADER;         }
precise                 {return KW_PRECISE;             }
RasterizerState         {return KW_RASTERIZERSTATE;     }
RenderTargetView        {return KW_RENDERTARGETVIEW;    }
return                  {return KW_RETURN;              }
register                {return KW_REGISTER;            }
sampler                 {return KW_SAMPLER;             }
sampler1D               {return KW_SAMPLER1D;           }
sampler2D               {return KW_SAMPLER2D;           }
sampler3D               {return KW_SAMPLER3D;           }
samplerCUBE             {return KW_SAMPLERCUBE;         }
sampler_state           {return KW_SAMPLER_STATE;       }
SamplerComparisonState  {return KW_SAMPLERCOMPARISONSTATE;}
shared                  {return KW_SHARED;              }
stateblock              {return KW_STATEBLOCK;          }
stateblock_state        {return KW_STATEBLOCK_STATE;    }
static                  {return KW_STATIC;              }
string                  {return KW_STRING;              }
struct                  {return KW_STRUCT;              }
switch                  {return KW_SWITCH;              }
tbuffer                 {return KW_TBUFFER;             }
technique               {return KW_TECHNIQUE;           }
technique10             {return KW_TECHNIQUE10;         }
texture                 {return KW_TEXTURE;             }
texture1D               {return KW_TEXTURE1D;           }
Texture1DArray          {return KW_TEXTURE1DARRAY;      }
texture2D               {return KW_TEXTURE2D;           }
Texture2DArray          {return KW_TEXTURE2DARRAY;      }
Texture2DMS             {return KW_TEXTURE2DMS;         }
Texture2DMSArray        {return KW_TEXTURE2DMSARRAY;    }
texture3D               {return KW_TEXTURE3D;           }
Texture3DArray          {return KW_TEXTURE3DARRAY;      }
textureCUBE             {return KW_TEXTURECUBE;         }
true                    {return KW_TRUE;                }
typedef                 {return KW_TYPEDEF;             }
uniform                 {return KW_UNIFORM;             }
vector                  {return KW_VECTOR;              }
VertexShader            {return KW_VERTEXSHADER;        }
void                    {return KW_VOID;                }
volatile                {return KW_VOLATILE;            }
while                   {return KW_WHILE;               }

\+\+                    {return OP_INC;                 }
\-\-                    {return OP_DEC;                 }
&&                      {return OP_AND;                 }
\|\|                    {return OP_OR;                  }
==                      {return OP_EQ;                  }
\<\<                    {return OP_LEFTSHIFT;           }
\<\<=                   {return OP_LEFTSHIFTASSIGN;     }
\>\>                    {return OP_RIGHTSHIFT;          }
\>\>=                   {return OP_RIGHTSHIFTASSIGN;    }
\.\.\.                  {return OP_ELLIPSIS;            }
\<=                     {return OP_LE;                  }
\>=                     {return OP_GE;                  }
!=                      {return OP_NE;                  }
\+=                     {return OP_ADDASSIGN;           }
\-=                     {return OP_SUBASSIGN;           }
\*=                     {return OP_MULASSIGN;           }
\/=                     {return OP_DIVASSIGN;           }
%=                      {return OP_MODASSIGN;           }
&=                      {return OP_ANDASSIGN;           }
\|=                     {return OP_ORASSIGN;            }
^=                      {return OP_XORASSIGN;           }
##                      {return OP_UNKNOWN1;            }
#@                      {return OP_UNKNOWN2;            }
::                      {return OP_UNKNOWN3;            }
\-\>                    {return OP_UNKNOWN4;            }

column_major            {return KW_COLUMN_MAJOR;        }
row_major               {return KW_ROW_MAJOR;           }

{IDENTIFIER}            {
                            hlsl_lval.name = d3dcompiler_strdup(yytext);
                            if (get_variable(hlsl_ctx.cur_scope, yytext)
                                    || find_function(yytext))
                                return VAR_IDENTIFIER;
                            else if (get_type(hlsl_ctx.cur_scope, yytext, TRUE))
                                return TYPE_IDENTIFIER;
                            else
                                return NEW_IDENTIFIER;
                        }

[0-9]*\.[0-9]+([eE][+-]?[0-9]+)?[h|H|f|F]? {
                            hlsl_lval.floatval = atof(yytext);
                            return C_FLOAT;
                        }
[0-9]+\.([eE][+-]?[0-9]+)?[h|H|f|F]? {
                            hlsl_lval.floatval = atof(yytext);
                            return C_FLOAT;
                        }
[0-9]+([eE][+-]?[0-9]+)?[h|H|f|F] {
                            hlsl_lval.floatval = atof(yytext);
                            return C_FLOAT;
                        }
0x[0-9a-fA-F]+          {
                            sscanf(yytext, "0x%x", &hlsl_lval.intval);
                            return C_INTEGER;
                        }
0[0-7]+                 {
                            sscanf(yytext, "0%o", &hlsl_lval.intval);
                            return C_INTEGER;
                        }
[0-9]+                  {
                            hlsl_lval.intval = (atoi(yytext));
                            return C_INTEGER;
                        }

{DOUBLESLASHCOMMENT}    {}

{WS}+                   {}
{NEWLINE}               {
                            hlsl_ctx.line_no++;
                            hlsl_ctx.column = 1;
                        }

^#                      {
                            BEGIN pp;
                        }

<pp>pragma{WS}+         {
                            TRACE("Got a #pragma.\n");
                            BEGIN pp_pragma;
                        }
<pp_pragma>pack_matrix{WS}*\({WS}*row_major{WS}*\) {
                            TRACE("#pragma setting row_major mode.\n");
                            hlsl_ctx.matrix_majority = HLSL_ROW_MAJOR;
                            BEGIN pp_ignore;
                        }
<pp_pragma>pack_matrix{WS}*\({WS}*column_major{WS}*\) {
                            TRACE("#pragma setting column_major mode.\n");
                            hlsl_ctx.matrix_majority = HLSL_COLUMN_MAJOR;
                            BEGIN pp_ignore;
                        }
<pp_pragma>{NEWLINE}    {
                            FIXME("Unsupported preprocessor #pragma directive at line %u.\n", hlsl_ctx.line_no);
                            BEGIN INITIAL;
                        }
<pp_pragma>{ANY}        {}
<pp>[0-9]+              {
                            TRACE("Preprocessor line info.\n");
                            BEGIN pp_line;
                            hlsl_lval.intval = (atoi(yytext));
                            return PRE_LINE;
                        }
<pp_line>{STRING}       {
                            char *string = d3dcompiler_strdup(yytext + 1);

                            BEGIN pp_ignore;
                            string[strlen(string) - 1] = 0;
                            hlsl_lval.name = string;
                            return STRING;
                        }
<pp_line>{WS}+          {}
<pp_line>{NEWLINE}      {
                            FIXME("Malformed preprocessor line directive?\n");
                            BEGIN INITIAL;
                        }
<pp_ignore>{NEWLINE}    {
                            BEGIN INITIAL;
                        }
<pp_ignore>{ANY}        {}
<pp>{NEWLINE}           {
                            FIXME("Unexpected preprocessor directive.\n");
                            BEGIN INITIAL;
                        }
<pp>{ANY}               {}

{ANY}                   {
                            return yytext[0];
                        }

%%

HRESULT parse_hlsl(enum shader_type type, DWORD major, DWORD minor,
        const char *entrypoint, ID3D10Blob **shader, char **messages);

HRESULT parse_hlsl_shader(const char *text, enum shader_type type, DWORD major, DWORD minor,
        const char *entrypoint, ID3D10Blob **shader, char **messages)
{
    YY_BUFFER_STATE buffer;
    HRESULT hr;

    buffer = hlsl__scan_string(text);
    hlsl__switch_to_buffer(buffer);

    hr = parse_hlsl(type, major, minor, entrypoint, shader, messages);

    hlsl__delete_buffer(buffer);
    return hr;
}
