%{ /* -*- C -*- */
/*************************************************************************

    rclex.l	1.32
    lex parser for resource compiler

    Copyright 1997 Willows Software, Inc. 

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 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
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

The maintainer of the Willows TWIN Libraries may be reached (Email) 
at the address twin@willows.com	

**************************************************************************/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "buffer.h"
#include "rc.y.tab.h"
#include "rc.z.tab.h"
#include "rc.h"

#define YY_FATAL_ERROR(msg) my_fatal_error( msg )
static void my_fatal_error( yyconst char msg[] );

int hex2dec(char *hex);

int zzparse(void);

/* Preprocessor support: includes */
#define MAX_INCLUDE_DEPTH 32

struct include_item
{
  YY_BUFFER_STATE buff;
  char *filename;
  int line;
  int column;
  int is_define;
  void *ext;
} include_stack[MAX_INCLUDE_DEPTH], *curr_include = include_stack;

int include_depth = 0;
void include_file(char *filename, int lookHere);
void include_string(char *string);
int next_line();
int add_lines(char *);
void set_position(int first_line, int last_line, int first_column, int last_column);

#define YY_USER_ACTION set_position(current_line(), current_line(), \
				    curr_include->column, curr_include->column + strlen(yytext)); \
		       curr_include->column += strlen(yytext);

/* Preprocessor support: defines */
#include "define.h"
DEFINESTRUCT *defineNew;
char *defineValue;

/* Preprocessor support: if/ifdef/ifndef/else/elif/endif */
#define MAX_IF_STACK_DEPTH 64
int ifStack[MAX_IF_STACK_DEPTH];
int ifWasTrue[MAX_IF_STACK_DEPTH];
int ifStackDepth = -1;
int ifYes = 1; /* Does the latest if say it's okay to go on? */
int more_if_stack(void);
int less_if_stack(void);
int reset_if_yes(void);
int ifResult;
int inIf = 0;

/* C/C++ typedef support */
char *last_typedef_keyword = NULL;

/* State support */
#define MAX_STATE_STACK_DEPTH	64
int stateStack[MAX_STATE_STACK_DEPTH];
int stateStackIndex = 0;				/* Indicates next position to push */

static void push_state(int new_state);
static int pop_state(void);
static void duplicate_top_of_stack(void);

#define PSTATE(p,q) (ifYes ? p : q)
#define PBEGINX(p,q) BEGIN(PSTATE(p,q))
#define PBEGIN(p) PBEGINX(p, PREPROCESSOREXCLUDE)

#define FSTATE(p,q) (inIf ? q : p)
#define FBEGINX(p,q) BEGIN(FSTATE(p,q))
#define FBEGIN(p) FBEGINX(p, KEYWORD)

#define IPSTATE(p,pp,f) FSTATE(PSTATE(p,pp),f)
#define IPBEGINX(p,pp,f) BEGIN(IPSTATE(p,pp,f))
#define IPSTANDARDSTATE(p) IPSTATE(p, PREPROCESSOREXCLUDE, KEYWORD)
#define IPBEGIN(p) IPBEGINX(p, PREPROCESSOREXCLUDE, KEYWORD)
%}

%x IGNORECFILE
%x IGNORETILBRACE
%x IGNORETILBRACEORSEMI
%x TYPEDEFMODE
%x COMMENT
%x PREPROCESSOR
%x POSTPREPROCESSOR
%x PREPROCESSOREXCLUDE
%x INCLUDE
%x DEFINE
%x DEFINEMACRO
%x DEFINEVAL
%x UNDEFINE
%x IFDEF
%x IFNDEF
%x KEYWORD
%x KWDEF
%x IFSTART
%x TYPEDEFDISPATCH
%x STRUCTDISPATCH
%x DOERROR
%s HEX

HORZWHITESPACE[ \t]
WHITESPACE [ \t\r\x1a\n]
TEXT [^ \t\r\x1a\n]
NEWLINE (\r\n)|[\x1a\n\r]
ANY [^\x1a\n\r]
NUMBER [0-9]
LETTER [A-Za-z_]
HEXDIGIT [0-9A-Fa-f]
BRACE [{}]
ANYBUTBRACE [^ \t\r\x1a\n]
BRACEORSEMI [{};]
ANYBUTBRACEORSEMI [^{}; \t\r\x1a\n]
SEMICOLON [;]
ANYBUTSEMICOLON [^; \t\r\x1a\n]

%%

  /* Comments: Discard both C-style and C++-style comments */

<*>\/\* { push_state(COMMENT); }
<COMMENT>{ANY}*\*\/ BEGIN(pop_state());
<COMMENT>{ANY}
<COMMENT>{NEWLINE} next_line();

<KEYWORD,KWDEF,INITIAL,PREPROCESSOREXCLUDE>;{ANY}*{NEWLINE} yyless(yyleng - 1);

<*>\/\/{ANY}*{NEWLINE} yyless(yyleng - 1);

  /* Preprocessor */
<*>^[ \t]*#[ \t]* {
        if (YYSTATE != COMMENT)
	    push_state(PREPROCESSOR);	/* preprocessor excursion */
  }

<PREPROCESSOR>include[ \t]* {
    PBEGINX(INCLUDE,POSTPREPROCESSOR);
  }

<PREPROCESSOR>define[ \t]* {
    PBEGINX(DEFINE,POSTPREPROCESSOR);
  }

<PREPROCESSOR>undef[ \t]* {
    PBEGINX(UNDEFINE,POSTPREPROCESSOR);
  }

<PREPROCESSOR>ifdef[ \t]* {
    BEGIN(IFDEF);
  }

<PREPROCESSOR>ifndef[ \t]* {
    BEGIN(IFNDEF);
  }

<PREPROCESSOR>endif[ \t]* {
    pop_state();			/* discard state saved when '#' found */
    LOG(("endif"));
    less_if_stack();
    reset_if_yes();
    BEGIN(POSTPREPROCESSOR);
  }

<PREPROCESSOR>else[ \t]* {
    pop_state();			/* discard state saved when '#' found */
    ifStackDepth--;
    reset_if_yes();
    ifStackDepth++;
    if (!ifYes)
      {
	reset_if_yes();
	LOG(("else: ignored"));
	duplicate_top_of_stack();
	BEGIN(POSTPREPROCESSOR);
      }
    else
      {
	ifStack[ifStackDepth] = !ifWasTrue[ifStackDepth];
	LOG(("else: %d", ifStack[ifStackDepth]));
	ifWasTrue[ifStackDepth] = 1;
	reset_if_yes();
	if (ifYes)
	{
	  duplicate_top_of_stack();
	  BEGIN(POSTPREPROCESSOR);
	}
	else
	  BEGIN(PREPROCESSOREXCLUDE);
      }
  }

<PREPROCESSOR>if/[ \t]* {
    if (!ifYes)
      {
	LOG(("if: ignored"));
	duplicate_top_of_stack();
	BEGIN(POSTPREPROCESSOR);
	ifStack[more_if_stack()] = 0;
      }
    else
      {
	LOG(("if: ?"));
	ifResult = -17;
	BEGIN(IFSTART);
	zzparse();
	LOG(("if: %d", ifResult));
	ifStack[more_if_stack()] = ifResult;
	ifWasTrue[ifStackDepth] = ifResult;
	reset_if_yes();
	if (ifYes)
	{
	  duplicate_top_of_stack();
	  BEGIN(pop_state());
	}
	else
	  BEGIN(PREPROCESSOREXCLUDE);
      }
  }

<PREPROCESSOR>elif/[ \t]* {
    pop_state();		/* discard state saved when '#' found */
    ifStackDepth--;
    reset_if_yes();
    ifStackDepth++;
    if (!ifYes)
      {
  	reset_if_yes();
	LOG(("elif: ignored"));
	duplicate_top_of_stack();
	BEGIN(POSTPREPROCESSOR);
      }
    else
      {
	reset_if_yes();
	if (!ifWasTrue[ifStackDepth])
	  {
	    LOG(("elif: ?"));
	    ifResult = -17;
	    BEGIN(IFSTART);
	    zzparse();
	    ifStack[ifStackDepth] = ifResult;
	    ifWasTrue[ifStackDepth] = ifResult;
	    LOG(("elif: %d", ifResult));
	    reset_if_yes();
	    if (ifYes)
	    {
	      duplicate_top_of_stack();
	      BEGIN(pop_state());
	    }
	    else
	      BEGIN(PREPROCESSOREXCLUDE);
	  }
	else
	  {
	    LOG(("elif: was true"));
	    ifStack[ifStackDepth] = 0;
	    reset_if_yes();
	    BEGIN(PREPROCESSOREXCLUDE);
	  }
      }
  }

<PREPROCESSOR>pragma[ \t]*	{
				    LOG(("#pragma directive ignored")); 
				    BEGIN(POSTPREPROCESSOR);
				}

<PREPROCESSOR>error[ \t]* PBEGINX(DOERROR,POSTPREPROCESSOR);

<PREPROCESSOR>{TEXT}*	{
			    CERROR(("unknown preprocessor directive %s", 
				    yytext)); 
			    BEGIN(POSTPREPROCESSOR);
			}

<POSTPREPROCESSOR>{ANY}*\\{NEWLINE} next_line();

<POSTPREPROCESSOR>{ANY}*{NEWLINE} {
				      next_line(); 
				      BEGIN(pop_state()); /* end excursion */
				  }

<PREPROCESSOREXCLUDE>{NEWLINE} next_line();
<PREPROCESSOREXCLUDE>{ANY}
<DOERROR>{ANY}* FATAL(("error directive: %s", yytext));
<DOERROR>{NEWLINE} FATAL(("error directive"));

  /* Include file support */
<INCLUDE>\"[^\"]*\" include_file(str_dup(yytext+1), 1);
<INCLUDE>\<[^\>]*\> include_file(str_dup(yytext+1), 0);
<INCLUDE>{ANY} CERROR(("Malformed #include statement")); BEGIN(POSTPREPROCESSOR);

<<EOF>> {
  int wasDefine;
  if (include_depth <= 0)
    {
      yyterminate();
    }
  else
    {
      int i;
      if ((wasDefine = curr_include->is_define))
	LOG(("End of macro expansion"));
      else
	{
	  LOG(("End of file %s", current_file()));
	  at_end_of_file();
	}
      str_free(curr_include->filename);
      yy_delete_buffer(YY_CURRENT_BUFFER);
      yy_switch_to_buffer(curr_include->buff);
      curr_include--;
      include_depth--;
      LOG((" now in %s (%d)", current_file(), include_depth));

      /* Loop through all levels except for the main level.  The main level
       * is neither an include nor a define.  So, it doesn't make sense to
       * check it.
       */
      update_info();

      pop_state();	/* end excursion, do not change to old state */
      if (YYSTATE == IGNORECFILE)
	BEGIN(INITIAL);	
    }
}

  /* Define support -- see also define.c */
<DEFINE>[A-Za-z_][A-Za-z0-9_]* {
    LOG(("define %s", yytext));
    defineNew = create_define(yytext);
    BEGIN(DEFINEVAL);
  }

<DEFINE>[A-Za-z_][A-Za-z0-9_]*/\( {
    defineNew = create_define(yytext);
    BEGIN(DEFINEMACRO);
  }

<DEFINE>{ANY} {
    CERROR(("Defining something other than a keyword, starts with %c", yytext[0]));
    BEGIN(POSTPREPROCESSOR);
  }

<DEFINEMACRO>\(([A-Za-z, _]*(\\{NEWLINE})*)*\) {
    BEGIN(DEFINEVAL);
  }

<DEFINEMACRO>{ANY} {
    CERROR(("Invalid macro parameter list"));
    BEGIN(POSTPREPROCESSOR);
  }

<DEFINEVAL>[ \t]+

<DEFINEVAL>{NEWLINE} {
    defineNew->value = str_dup("");
    yyless(0);
    BEGIN(POSTPREPROCESSOR);
  }

<DEFINEVAL>({ANY}*(\\{NEWLINE})*)* {
    char *p;

    defineNew->value = str_dup(yytext);
    p = strstr(defineNew->value, "//");
    if (p)
        *p = '\0';
    add_lines(yytext);
    BEGIN(POSTPREPROCESSOR);
  }

<UNDEFINE>[A-Za-z_][A-Za-z0-9_]*/{WHITESPACE} {
    undefine_define(yytext);
    BEGIN(POSTPREPROCESSOR);
  }

<UNDEFINE>{ANY} {
    CERROR(("Undefining something other than a keyword"));
    BEGIN(POSTPREPROCESSOR);
  }

  /* Ifdef support */
<IFDEF>[A-Za-z_][A-Za-z0-9_]*/{WHITESPACE} {
    if (!ifYes)
      {
	LOG(("ifdef (ignored)"));
	more_if_stack();
	duplicate_top_of_stack();
	BEGIN(POSTPREPROCESSOR);
      }
    else
      {
	ifStack[more_if_stack()] = (match_define(yytext)) ? 1 : 0;
	ifWasTrue[ifStackDepth] = ifStack[ifStackDepth];
	LOG(("ifdef %s (%d)", yytext, ifStack[ifStackDepth]));
	reset_if_yes();
	if (ifYes)
	{
	  duplicate_top_of_stack();
	  BEGIN(POSTPREPROCESSOR);
	}
	else
	  BEGIN(PREPROCESSOREXCLUDE);
      }
  }

<IFNDEF>[A-Za-z_][A-Za-z0-9_]*/{WHITESPACE} {
    if (!ifYes)
      {
	LOG(("ifndef (ignored)"));
	more_if_stack();
	duplicate_top_of_stack();
	BEGIN(POSTPREPROCESSOR);
      }
    else
      {
	ifStack[more_if_stack()] = (match_define(yytext)) ? 0 : 1;
	ifWasTrue[ifStackDepth] = ifStack[ifStackDepth];
	LOG(("ifndef %s (%d)", yytext, ifStack[ifStackDepth]));
	reset_if_yes();
	if (ifYes)
	{
	  duplicate_top_of_stack();
	  BEGIN(POSTPREPROCESSOR);
	}
	else
	  BEGIN(PREPROCESSOREXCLUDE);
      }
  }

<IFDEF,IFNDEF>{HORZWHITESPACE}+

<IFDEF,IFNDEF>{ANY} {
    if (!ifYes)
      {
	LOG(("ifdef (ignored)"));
	more_if_stack();
	duplicate_top_of_stack();
	BEGIN(POSTPREPROCESSOR);
      }
    else
      CERROR(("#ifdef/#ifndef test on something other than a keyword"));
  }

<IFDEF,IFNDEF>{NEWLINE} {
    if (!ifYes)
      {
	LOG(("ifdef (ignored)"));
	more_if_stack();
      }
    else
      {
        CERROR(("#ifdef/#ifndef test on nothing"));
      }
    next_line();
    duplicate_top_of_stack();
    BEGIN(pop_state());		/* end excursion */
  }

  /* Just plain #if support */
<IFSTART>[ \t]* {
    inIf = 1;
    BEGIN(KEYWORD);
    return ifPREPROCESSORIF;
  }

<KEYWORD>[ \t]+
<KEYWORD>\\{NEWLINE} next_line();

<KEYWORD>-?{NUMBER}+ {
    zzlval.i = atoi(yytext);
    LOG(("IF: INT: %d", zzlval.i));
    return ifINT;
  }

<KEYWORD>0x{HEXDIGIT}+L? {
    zzlval.i = hex2dec(yytext+2);
    LOG(("IF: INT: 0x%X", zzlval.i));
    return ifINT;
  }

<KEYWORD>defined {
    BEGIN(KWDEF);
    LOG(("IF: DEFINED"));
    return ifDEFINED;
  }

<KEYWORD>!defined {
    BEGIN(KWDEF);
    LOG(("IF: !DEFINED"));
    return ifnDEFINED;
} 

<KWDEF>[ \t]

<KWDEF>[A-Za-z_][A-Za-z0-9_]* {
    zzlval.str = str_dup(yytext);
    LOG(("IF: KEYWORD: %s", yytext));
    BEGIN(KEYWORD);
    return ifSTRING;
  }

<KWDEF>{ANY} LOG(("IF: CHAR '%c'", yytext[0])); return yytext[0];

<KEYWORD>{ANY} LOG(("IF: CHAR '%c'", yytext[0])); return yytext[0];

<KEYWORD>{NEWLINE} LOG(("IF: EOL")); inIf = 0; next_line(); BEGIN(INITIAL); return 0;

    /*
     * C/C++ keywords that indicate the beginning of a block.
     */
<INITIAL>struct		|
<INITIAL>union		|
<INITIAL>class		|
<INITIAL>template	return STRUCT;

    /*
     * C/C++ keywords that indicate a type
     */
<INITIAL>HANDLE		|
<INITIAL>UINT		|
<INITIAL>WORD		|
<INITIAL>DWORD		|
<INITIAL>LONG		|
<INITIAL>BYTE		|
<INITIAL>HWND		|
<INITIAL>HGLOBAL	|
<INITIAL>ULONG		|
<INITIAL>LPSTR		|
<INITIAL>inline		|
<INITIAL>_inline	|
<INITIAL>__inline	|
<INITIAL>pascal		|
<INITIAL>_pascal	|
<INITIAL>__pascal	|
<INITIAL>fortran	|
<INITIAL>_fortran	|
<INITIAL>__fortran	|
<INITIAL>cdecl		|
<INITIAL>_cdecl		|
<INITIAL>__cdecl	|
<INITIAL>far		|
<INITIAL>_far		|
<INITIAL>__far		|
<INITIAL>near		|
<INITIAL>_near		|
<INITIAL>__near		|
<INITIAL>huge		|
<INITIAL>_huge		|
<INITIAL>__huge		|

<INITIAL>enum		|
<INITIAL>auto		|
<INITIAL>static		|
<INITIAL>const		|
<INITIAL>volatile	|
<INITIAL>extern		|
<INITIAL>char		|
<INITIAL>short		|
<INITIAL>int		|
<INITIAL>long		|
<INITIAL>signed		|
<INITIAL>unsigned	|
<INITIAL>double		|
<INITIAL>float		|
<INITIAL>void		|
<INITIAL>overload	return CTYPE;

    /*
     * Other C/C++ keywords of interest
     */
<INITIAL>typedef	return TYPEDEF;

    /* 
     * Replace defined values, if necessary 
     */
<INITIAL,KEYWORD>[A-Za-z_][A-Za-z0-9_]* {
  if ((defineValue = match_define(yytext))) 
	{ 
	  LOG(("Expanding %s as %s", yytext, defineValue)); 
	  push_state(YYSTATE);
	  include_string(defineValue); 
	} 
  else 
	REJECT;
}

    /* 
     * Discard all whitespace and newlines 
     */
<INITIAL,TYPEDEFMODE,IGNORETILBRACE,IGNORETILBRACEORSEMI>[ \t]+
<INITIAL,TYPEDEFMODE,IGNORETILBRACE,IGNORETILBRACEORSEMI>{NEWLINE} next_line();

    /*
     * Eat typedefs except for the name of the new type.
     */
<TYPEDEFMODE>{SEMICOLON} { 
			    if (last_typedef_keyword == NULL)
			        return NOTAVALIDTOKEN;

			    yylval.str = last_typedef_keyword;
			    last_typedef_keyword = NULL;
			    return ASTRING; 
			 }

<TYPEDEFMODE>{ANYBUTSEMICOLON}+ {
			    if (last_typedef_keyword)
			        free(last_typedef_keyword);

			    last_typedef_keyword = str_dup(yytext);
			 }

    /*
     * Eat C/C++ code until we hit the special characters that we are
     * interested in.
     */
<IGNORECFILE>{ANY}
<IGNORECFILE>{NEWLINE} next_line();

<IGNORETILBRACE,IGNORETILBRACEORSEMI>\{		return BEGIn;

<IGNORETILBRACE,IGNORETILBRACEORSEMI>\}		return END;

<IGNORETILBRACEORSEMI>{SEMICOLON}		return ';';

<IGNORETILBRACE>{ANYBUTBRACE}
<IGNORETILBRACEORSEMI>{ANYBUTBRACEORSEMI}

<KEYWORD>[A-Za-z_][A-Za-z0-9_]* zzlval.str = yytext; return ifSTRING;

  /* Resource flags */
<INITIAL>PRELOAD yylval.mask.and = ~(0x0040); yylval.mask.or = 0x0040; return FLAG;
<INITIAL>LOADONCALL yylval.mask.and = ~(0x0040); yylval.mask.or = 0; return FLAG;
<INITIAL>MOVEABLE yylval.mask.and = ~(0x0010); yylval.mask.or = 0x0010; return FLAG;
<INITIAL>FIXED yylval.mask.and = ~(0x0010); yylval.mask.or = 0; return FLAG;
<INITIAL>DISCARDABLE yylval.mask.and = -1; yylval.mask.or = 0; return FLAG;
<INITIAL>PURE yylval.mask.and = -1; yylval.mask.or = 0; return FLAG;
<INITIAL>IMPURE yylval.mask.and = -1; yylval.mask.or = 0; return FLAG;

  /* Resource types */
<INITIAL>TABLENAME return TABLENAME;
<INITIAL>ACCELERATORS return ACCELERATORS;
<INITIAL>BITMAP return BITMAP;
<INITIAL>CURSOR return CURSOR;
<INITIAL>DIALOG return DIALOG;
<INITIAL>DIALOGEX return DIALOGEX;
<INITIAL>ICON return ICON;
<INITIAL>MENU return MENU;
<INITIAL>STRINGTABLE return STRINGTABLE;
<INITIAL>VERSIONINFO return VERSIONINFO;

  /* Resource types (MFC 4.x) */
<INITIAL>DLGINIT return DLGINIT;
<INITIAL>TOOLBAR return TOOLBAR;
<INITIAL>BUTTON return BUTTON;

  /* Version info keywords */
<INITIAL>FILEVERSION return FILEVERSION;
<INITIAL>PRODUCTVERSION return PRODUCTVERSION;
<INITIAL>FILEFLAGSMASK return FILEFLAGSMASK;
<INITIAL>FILEFLAGS return FILEFLAGS;
<INITIAL>FILEOS return FILEOS;
<INITIAL>FILETYPE return FILETYPE;
<INITIAL>FILESUBTYPE return FILESUBTYPE;
<INITIAL>BLOCK return BLOCK;
<INITIAL>VALUE return VALUE;

  /* Menu keywords */
<INITIAL>POPUP return POPUP;
<INITIAL>MENUITEM return MENUITEM;
<INITIAL>SEPARATOR return SEPARATOR;
<INITIAL>CHECKED return CHECKED;
<INITIAL>GRAYED return GRAYED;
<INITIAL>HELP return HELP;
<INITIAL>INACTIVE return INACTIVE;

  /* Dialog keywords */
<INITIAL>STYLE return STYLE;
<INITIAL>CAPTION return CAPTION;
<INITIAL>CLASS return CLASS;
<INITIAL>FONT return FONT;
<INITIAL>LANGUAGE return LANGUAGE;
<INITIAL>LTEXT return LTEXT;
<INITIAL>RTEXT return RTEXT;
<INITIAL>CTEXT return CTEXT;
<INITIAL>EDITTEXT return EDITTEXT;
<INITIAL>LISTBOX return LISTBOX;
<INITIAL>COMBOBOX return COMBOBOX;
<INITIAL>GROUPBOX return GROUPBOX;
<INITIAL>PUSHBUTTON return PUSHBUTTON;
<INITIAL>DEFPUSHBUTTON return DEFPUSHBUTTON;
<INITIAL>CHECKBOX return CHECKBOX;
<INITIAL>AUTOCHECKBOX return AUTOCHECKBOX;
<INITIAL>STATE3 return STATE3;
<INITIAL>AUTO3STATE return AUTO3STATE;
<INITIAL>RADIOBUTTON return RADIOBUTTON;
<INITIAL>AUTORADIOBUTTON return AUTORADIOBUTTON;
<INITIAL>SCROLLBAR return SCROLLBAR;
<INITIAL>CONTROL return CONTROL;

<INITIAL>VIRTKEY return VIRTKEY;
<INITIAL>ASCII return ASCII;
<INITIAL>SHIFT return SHIFT;
<INITIAL>ALT return ALT;
<INITIAL>NOINVERT return NOINVERT;

<INITIAL>ALIGN return ALIGN;
<INITIAL>ENDIAN return ENDIAN;

<INITIAL>BEGIN return BEGIn;
<INITIAL>END return END;
<INITIAL>\{ return BEGIn;
<INITIAL>\} return END;
<INITIAL>NOT return NOT;

<HEX>' BEGIN(pop_state()); return *yytext;
<HEX>{HEXDIGIT}{2} yylval.str = str_dup(yytext); return HEXCHARS;
<HEX>[ \t]+
<INITIAL>' push_state(HEX); return *yytext;

<INITIAL>-?{NUMBER}+ {
    yylval.i = atoi(yytext);
    LOG(("INT: %d", yylval.i));
    return (yylval.i > 0xffff) ? LONGINT : SHORTINT;
  }

<INITIAL>-?{NUMBER}+[Ll] {
    yylval.i = atoi(yytext);
    LOG(("INT: %d", yylval.i));
    return LONGINT;
  }

<INITIAL>0x{HEXDIGIT}+ {
    yylval.i = hex2dec(yytext+2);
    LOG(("INT: 0x%X", yylval.i));
    return (yylval.i > 0xffff) ? LONGINT : SHORTINT;
  }

<INITIAL>0x{HEXDIGIT}+[Ll] {
     yylval.i = hex2dec(yytext+2);
     LOG(("INT: 0x%X", yylval.i));
     return LONGINT;
  }

<INITIAL>[A-Za-z0-9\.\_\/\\]+ {
     yylval.str = str_dup(yytext);
     LOG(("ASTRING: %s", yylval.str));
     return ASTRING;
  }

<INITIAL>\"[^\"]*\" {
     yylval.str = str_dup(yytext+1);
     yylval.str[strlen(yylval.str)-1] = '\0';
     LOG(("QSTRING: %s", yylval.str));
     return QSTRING;
  }

<INITIAL>{ANY} LOG(("CHAR: '%c'", *yytext)); return *yytext;

%%

int zzlex(void)
{
  return yylex();
}

int yywrap(void)
{
  return 1;
}

int more_if_stack(void)
{
  if (++ifStackDepth >= MAX_IF_STACK_DEPTH)
    FATAL(("Too many #ifs or #ifdefs"));
  ifWasTrue[ifStackDepth] = 0;
  return ifStackDepth;
}

int less_if_stack(void)
{
  if (ifStackDepth < 0)
    FATAL(("Too many #endifs"));
  ifStackDepth--;
  reset_if_yes();
  return ifStackDepth;
}

int reset_if_yes(void)
{
  int i;
  ifYes = 1;
  for (i = 0; i <= ifStackDepth; i++)
    ifYes &= ifStack[i];
  return ifYes;
}

void add_include(void)
{
  if (++include_depth >= MAX_INCLUDE_DEPTH)
    FATAL(("Includes/macros nested too deeply"));

  curr_include++;
  curr_include->buff = YY_CURRENT_BUFFER;
  LOG(("add_include (%d)", include_depth));
}

void include_string(char *string)
{
  add_include();
  yy_scan_string(string);
  curr_include->filename = str_dup((curr_include - 1)->filename);
  curr_include->line = (curr_include - 1)->line;
  curr_include->column = (curr_include - 1)->column;
  curr_include->is_define = 1;
  at_start_of_macro();
}

void include_file(char *filename, int lookHere)
{
  char *pFile = str_dup(filename);
  char *pString;

  pFile[strlen(pFile)-1] = '\0';
  pString = load_file(str_dup(pFile), lookHere);
  if (!pString)
    {
      str_free(pFile);
      return;
    }
  add_include();
  yy_scan_string(pString);
  str_free(pString);
  curr_include->filename = pFile;
  curr_include->line = 1;
  curr_include->column = 1;
  curr_include->is_define = 0;
  at_start_of_file();

  LOG(("Now in file %s", pFile));

  IPBEGIN(INITIAL);
}

int hex2dec(char *hex)
{
  int result = 0, len, i;
	
  len = strlen(hex);
  
  for (i=0; i < len; i++)
    if (isxdigit(hex[i]))
      {
	result <<= 4;
	if ((hex[i] >= '0') && (hex[i] <= '9'))
	  result += hex[i] - '0';
	else if ((hex[i] >= 'A') && (hex[i] <= 'F'))
	  result += hex[i] - 'A' + 10;
	else if ((hex[i] >= 'a') && (hex[i] <= 'f'))
	  result += hex[i] - 'a' + 10;
	else
	  FATAL(("isxdigit() returned true on '%c', not a hex digit", hex[i]));
      }
  return result;
}

extern char in_name[];

void include_init(void)
{
  curr_include->filename = in_name;
  curr_include->line = 1;
  curr_include->column = 1;
  curr_include->is_define = 0;
}

void include_init_string(char *str)
{
  yy_scan_string(str);
  at_start_of_file();
}

char *current_file(void)
{
  return curr_include->filename;
}

int current_line(void)
{
  return curr_include->line;
}

int next_line(void)
{
  curr_include->column = 1;
  if (!(++(curr_include->line) % 50))
    update_info();
  yy_set_bol(1);
  return curr_include->line;
}

int add_lines(char *s)
{
  while (*s)
    if ((*s++ == '\n') || (*s == '\r'))
	next_line();
    else
      yy_set_bol(0);
  return current_line();
}

int extra_lines(void)
{
  int i, c;
  for (c = i = 0; i <= include_depth; i++)
    if (!include_stack[i].is_define)
      c += include_stack[i].line;
  return c;
}

void *get_ext(void)
{
  return curr_include->ext;
}

void *set_ext(void *v)
{
  return curr_include->ext = v;
}

void ignore_until_brace()
{
    LOG(("STATE: IGNORETILBRACE"));
    BEGIN(IGNORETILBRACE);
}

void ignore_until_semicolon()
{
    LOG(("STATE: IGNORETILBRACEORSEMI"));
    BEGIN(IGNORETILBRACEORSEMI);
}

void typedef_mode()
{
    LOG(("STATE: TYPEDEF"));
    BEGIN(TYPEDEFMODE);
}

void initial_mode()
{
    LOG(("STATE: INITIAL"));
    BEGIN(INITIAL);
}

void ignore_rest_of_file()
{
    LOG(("STATE: IGNORECFILE"));
    BEGIN(IGNORECFILE);
}

static void push_state(int new_state)
{
    if (stateStackIndex == MAX_STATE_STACK_DEPTH)
	FATAL(("Max state stack depth exceeded"));

    LOG(("(%d) PUSH from %d to %d", stateStackIndex, YYSTATE, new_state));

    stateStack[stateStackIndex++] = YYSTATE;
    BEGIN(new_state);
}

static int pop_state(void)
{
    if (--stateStackIndex < 0)
    	FATAL(("Stack underflow"));

    LOG(("(%d) POP from %d to %d", 
	 stateStackIndex, YYSTATE, stateStack[stateStackIndex]));

    return(stateStack[stateStackIndex]);
}

static void duplicate_top_of_stack(void)
{
    int top_value;

    if (stateStackIndex == MAX_STATE_STACK_DEPTH)
	FATAL(("Max state stack depth exceeded"));

    top_value = stateStack[stateStackIndex-1];

    LOG(("(%d) PUSH from %d to %d", stateStackIndex, top_value, top_value));

    stateStack[stateStackIndex++] = top_value;
}    

static void my_fatal_error( yyconst char msg[] )
{
	(void) fprintf( stderr, "%s\n", msg );
	exitfunc();
	exit( YY_EXIT_FAILURE );
}
