%{

#include <string>
#include <map>
#include <iostream>

#include "declarations.h"
#include "language_y.h"

#ifndef YYSTYPE
#define YYSTYPE yy::parser::semantic_type
#endif

#ifndef YYLTYPE
#define YYLTYPE yy::parser::location_type
#endif

using token = yy::parser::token;

#define YY_USER_ACTION yylloc->step(); yylloc->columns(yyleng);

%}

%option debug

%option yylineno
%option noyywrap
%option nounput
%option noinput
%option reentrant
%option bison-bridge
%option bison-locations

identifier [a-zA-Z][_a-zA-Z0-9]*
size_modifier [+*/-][ +*/\-0-9]*
intvalue (0|[1-9][0-9]*)
hexvalue 0[x|X][0-9a-fA-F]+
string_literal \".*\"

%x COMMENT_STATE

%%
  /* NOTE:
   * Rule ordering is important in order to establist priority. Some
   * rules are a superset of other rules and will cause the sub rules to
   * never match. Ex. Keywords must always go before identifiers, otherwise
   * all keywords will be treated as an identifier.
   */

  /* Block Comment */
"/*"                    { BEGIN(COMMENT_STATE); }
<COMMENT_STATE>"*/"     { BEGIN(INITIAL); }
<COMMENT_STATE>[\n]+    { yylloc->lines(yyleng); }
<COMMENT_STATE>.        { /* do nothing */ }

  /* Line Comment */
"//"[^\r\n]*            { /* do nothing */ }

  /* Begin reserved keyword definitions */
  /* Fields */
"_body_"                { return(token::BODY); }
"_payload_"             { return(token::PAYLOAD); }
"_size_"                { return(token::SIZE); }
"_count_"               { return(token::COUNT); }
"_fixed_"               { return(token::FIXED); }
"_reserved_"            { return(token::RESERVED); }
"_checksum_start_"      { return(token::CHECKSUM_START); }
"_padding_"             { return(token::PADDING); }
  /* Types */
"checksum"              { return(token::CHECKSUM); }
"custom_field"          { return(token::CUSTOM_FIELD); }
"enum"                  { return(token::ENUM); }
"group"                 { return(token::GROUP); }
"packet"                { return(token::PACKET); }
"test"                  { return(token::TEST); }
"struct"                { return(token::STRUCT); }
"little_endian_packets" {
                          yylval->integer = 1;
                          return token::IS_LITTLE_ENDIAN;
                        }

  /* Begin identifier definitions */
{string_literal}        {
                          std::string with_quotes = std::string(yytext);
                          yylval->string = new std::string(with_quotes.begin() + 1, with_quotes.end() - 1);
                          return token::STRING;
                        }

{size_modifier}         {
                          yylval->string = new std::string(yytext);
                          return token::SIZE_MODIFIER;
                        }

{identifier}            {
                          yylval->string = new std::string(yytext);
                          return token::IDENTIFIER;
                        }

{intvalue}              {
                          yylval->integer = std::stoull(std::string(yytext), nullptr, 10);
                          return token::INTEGER;
                        }

{hexvalue}              {
                          yylval->integer = std::stoull(std::string(yytext), nullptr, 16);
                          return token::INTEGER;
                        }

  /* Begin token definitions */
":"            { return(':'); }
"{"            { return('{'); }
"}"            { return('}'); }
"["            { return('['); }
"]"            { return(']'); }
"("            { return('('); }
")"            { return(')'); }
"<"            { return('<'); }
">"            { return('>'); }
"="            { return('='); }
","            { return(','); }

(\n|\r\n)+     { yylloc->lines(yyleng); }
[ \t\f\v]+     { /* Ignore all other whitespace */ }

%%

