%{
/* ########################################################################

			      BR_Lexer.l

   ########################################################################

   Copyright (c) : Dominique Leveque

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

   ######################################################################## */


#include <string.h>
#include <sys/param.h>

#include "proto_decl.h"

#include "BR_Global.h"
#include "BR_Lexer.h"
#include "BR_Parser.h"
#include "BR_Interface.h"

   /*-----------------------------------------------------------------------*/
   /*                          External lex interface                       */
   /*-----------------------------------------------------------------------*/


#ifndef yylex
#define yylex          BR_yylex
#endif

BR_TokenPt             BR_lex_prolog;


extern BR_InfoHandler  BR_info_handler;


   /*-----------------------------------------------------------------------*/
   /*                        Internal lex variables                         */
   /*-----------------------------------------------------------------------*/

static BR_Int          fname_len;
static BR_Str          fname[MAXPATHLEN];

static BR_Int          lname_len;
static BR_Str          lname[MAXPATHLEN];

static BR_Int          template_level;
static BR_Int          bhole_par_level;
static BR_Int          block_level;

static BR_Boolean      line_named;

static BR_Int          line_num       = 1;

static BR_Boolean      bracket_ignore = BR_FALSE;
static BR_Boolean      colon_ignore   = BR_FALSE;

static BR_TokenPt      token_frame    = BR_Null;
static BR_TokenPt      token_const    = BR_Null;

static BR_Int          str_error_cnt  = 0;


   /*-----------------------------------------------------------------------*/
   /*                        Internal lex buffers                           */
   /*-----------------------------------------------------------------------*/
 
#define MAX_TOKEN_COUNT   256
#define MAX_VAL_LEN       64 
#define VAL_BUF_SIZE      (MAX_TOKEN_COUNT * MAX_VAL_LEN)

static BR_Str       val_buf[MAX_TOKEN_COUNT * MAX_VAL_LEN];
static BR_Str*      val_next = val_buf;
static BR_Str*      val_max  = &(val_buf[VAL_BUF_SIZE - 2]);

static BR_TokenRec  token_buf[MAX_TOKEN_COUNT];
static BR_TokenPt   token_next = token_buf;
static BR_TokenPt   token_max  = &(token_buf[MAX_TOKEN_COUNT - 33]);


   /*-----------------------------------------------------------------------*/
   /*                        Lex states management                          */
   /*-----------------------------------------------------------------------*/

#define MAX_STATE      64

static BR_Int state_stack[MAX_STATE];
static BR_Int top_state = 0;


#define PUSH_STATE(state) \
    {                                         \
      if (top_state < (MAX_STATE - 1))        \
        top_state++;                          \
      state_stack[top_state] = state;         \
      BEGIN(state);                           \
    }

#define POP_STATE() \
    {                                         \
      if (top_state > ((BR_Int) token_frame->_line_num)) \
        --top_state;                          \
      BEGIN(state_stack[top_state]);          \
    }

#define SET_STATE(state) \
    {                                         \
      state_stack[top_state] = state;         \
      BEGIN(state);                           \
    }

#define TOP_STATE()         state_stack[top_state]


   /*-----------------------------------------------------------------------*/
   /*                      Related Token Constants                          */
   /*-----------------------------------------------------------------------*/

#define STR_COMMA             ", "
#define STR_LPARENTH          "( "
#define STR_RPARENTH          ") "
#define STR_STAR              "* "
#define STR_AND               "& "
#define STR_TILDE             "~ "
#define STR_PREFIX            ":: "
#define STR_ARRAY             "[] "
#define STR_ELLIPSIS          "... "
#define STR_ENUM              "enum "
#define STR_CLASS             "class "
#define STR_UNION             "union "
#define STR_STRUCT            "struct "
#define STR_OPERATOR          "operator "
#define STR_PUBLIC            "public "
#define STR_PRIVATE           "private "
#define STR_PROTECTED         "protected "
#define STR_PARENTHS          "() "
#define STR_EQUAL             "= "

#define T_COMMA               ','
#define T_LPARENTH            '('
#define T_RPARENTH            ')'
#define T_STAR                '*'
#define T_AND                 '&'
#define T_TILDE               '~'
#define T_LBRACKET            '{'
#define T_RBRACKET            '}'
#define T_SEMICOLON           ';'
#define T_COLON               ':'
#define T_EQUAL               '='
#define T_SUP                 '>'

#define BASIC_INT             ((BR_ULong) 0x00000000)
#define BASIC_CHAR            ((BR_ULong) 0x00000001)
#define BASIC_SHORT           ((BR_ULong) 0x00000002)
#define BASIC_LONG            ((BR_ULong) 0X00000003)
#define BASIC_SIGNED          ((BR_ULong) 0x00000000)
#define BASIC_UNSIGNED        ((BR_ULong) 0x00000004)
#define BASIC_CONST           ((BR_ULong) 0x00000008)


   /*-----------------------------------------------------------------------*/
   /*                         Related Token Macros                          */
   /*-----------------------------------------------------------------------*/

#define GET_FREE_TOKEN(t)           \
  if (token_next > token_max)                                 \
  {                                                           \
    fprintf(stderr, ">>>> Lexer Tokens buffer exhausted\n");  \
    return(T_LEXER_ERROR);                                    \
  }                                                           \
  t = token_next++;

#define GET_FREE_STR(val, len)      \
  val       = val_next;                                       \
  val_next += len;                                            \
  if (val_next > val_max)                                     \
  {                                                           \
    fprintf(stderr, ">>>> Lexer Strings buffer exhausted\n"); \
    return(T_LEXER_ERROR);                                    \
  }                                                           \
  *(val_next)++ = ' ';


#define TOP_TOKEN()                (token_next - 1)


#define RETURN_FRAME(info)         (token_frame->_bits |= info)

#define RETURN_CODE(key)           return(key);

#define RETURN_BIT(key, bit)       \
{                                              \
  GET_FREE_TOKEN(yylval);                      \
  yylval->_code     = key;                     \
  yylval->_bits     = bit;                     \
  yylval->_next     = BR_Null;                 \
  yylval->_last     = yylval;                  \
  yylval->_prefix   = BR_Null;                 \
  return(key);                                 \
}

#define RETURN_KEYWORD(key, str)   \
{                                              \
  GET_FREE_TOKEN(yylval);                      \
  yylval->_code     = key;                     \
  yylval->_val      = str;                     \
  yylval->_val_len  = sizeof(str) - 2;         \
  yylval->_line_num = line_num;                \
  yylval->_next     = BR_Null;                 \
  yylval->_last     = yylval;                  \
  yylval->_prefix   = BR_Null;                 \
  yylval->_bits     = BR_INFO_EMPTY;           \
  return(key);                                 \
}

#define RETURN_TOKEN(key)          \
{                                              \
  GET_FREE_TOKEN(yylval);                      \
  GET_FREE_STR(yylval->_val, yyleng);          \
  strncpy(yylval->_val, yytext, yyleng);       \
  yylval->_code     = key;                     \
  yylval->_val_len  = yyleng;                  \
  yylval->_line_num = line_num;                \
  yylval->_next     = BR_Null;                 \
  yylval->_last     = yylval;                  \
  yylval->_prefix   = BR_Null;                 \
  yylval->_bits     = BR_INFO_EMPTY;           \
  return(key);                                 \
}  


   /*-----------------------------------------------------------------------*/
   /*                         Black Hole Bits                               */
   /*-----------------------------------------------------------------------*/

typedef BR_ULong              BhExitBits;

#define BHEB_SEMI             ((BhExitBits) 0x00000001)
#define BHEB_COMMA            ((BhExitBits) 0x00000002)
#define BHEB_BRACKET          ((BhExitBits) 0x00000004)
#define BHEB_SQUARE           ((BhExitBits) 0x00000008)
#define BHEB_PARENTH          ((BhExitBits) 0x00000010)

#define BHEB_UN_SEMI          ((BhExitBits) 0x00000020)
#define BHEB_UN_COMMA         ((BhExitBits) 0x00000040)
#define BHEB_UN_BRACKET       ((BhExitBits) 0x00000080)
#define BHEB_UN_SQUARE        ((BhExitBits) 0x00000100)
#define BHEB_UN_PARENTH       ((BhExitBits) 0x00000200)


static BhExitBits             bhole_exit;


   /*-----------------------------------------------------------------------*/
   /*                         Miscellaneous macros                          */
   /*-----------------------------------------------------------------------*/

#define NEW_LINE()            line_num++


   /*-----------------------------------------------------------------------*/
%}

TWS             [ \v\t\r\f]

IDENT           [_a-zA-Z][_a-zA-Z0-9]*

TAG             [^ \v\t\r\f\n*$]+

FILE_NAME       [-_./a-zA-Z0-9]+


BLOCK_CNTS      [^#{}'"/\n]


INTEGER         [0-9]+


OP1             ("+"|"-"|"/"|"%"|"^"|"|"|"~"|"!"|">")

OP2             ("+="|"-="|"*="|"/="|"%="|"^="|"&="|"|=")

OP3             ("<<"|">>"|">>="|"<<="|"=="|"!="|"<="|">="|"&&"|"||"|"++"|"--")

OP4             ("->*"|"->")

OPERATOR        ({OP1}|{OP2}|{OP3}|{OP4})


   /*-----------------------------------------------------------------------*/

%option noyywrap 

%x COMMENT1
%x COMMENT2
%x STR_IGN
%x MACRO_LINE
%x MACRO_START
%x MACRO_IGN

%s FILE_MAIN
%s TEMPLATE_DECL
%s TEMPLATE_ARG
%s TEMPLATE_INST
%s BLACK_HOLE
%s BLOCK_IGN
%s FILE_IGN

%%

   /*-----------------------------------------------------------------------*/

<FILE_MAIN>"register"

<FILE_MAIN>"auto"

<FILE_MAIN>"volatile"


   /*-----------------------------------------------------------------------*/

<FILE_MAIN>"extern"            { RETURN_FRAME(BR_INFO_EXTERN);        }

<FILE_MAIN>"inline"            { RETURN_FRAME(BR_INFO_INLINE);        }

<FILE_MAIN>"static"            { RETURN_FRAME(BR_INFO_STATIC);        }

<FILE_MAIN>"virtual"           { RETURN_FRAME(BR_INFO_VIRTUAL);       }

<FILE_MAIN>"typedef"           { RETURN_FRAME(BR_INFO_TYPEDEF);       }


   /*-----------------------------------------------------------------------*/

<FILE_MAIN>"class"             { RETURN_CODE(T_CLASS);                }

<FILE_MAIN>"struct"            { RETURN_CODE(T_STRUCT);               }

<FILE_MAIN>"union"             { RETURN_CODE(T_UNION);                }

<FILE_MAIN>"enum"              { RETURN_CODE(T_ENUM);                 }

<FILE_MAIN>"friend"            { RETURN_CODE(T_FRIEND);               }

<FILE_MAIN>";"                 { RETURN_CODE(T_SEMICOLON);            }

<FILE_MAIN>"}"                 { RETURN_CODE(T_RBRACKET);             }


   /*-----------------------------------------------------------------------*/

<FILE_MAIN>"int"               { RETURN_BIT(T_BASIC, BASIC_INT);      }

<FILE_MAIN>"char"              { RETURN_BIT(T_BASIC, BASIC_CHAR);     }

<FILE_MAIN>"long"              { RETURN_BIT(T_BASIC, BASIC_LONG);     }

<FILE_MAIN>"short"             { RETURN_BIT(T_BASIC, BASIC_SHORT);    }

<FILE_MAIN>"signed"            { RETURN_BIT(T_BASIC, BASIC_SIGNED);   }

<FILE_MAIN>"unsigned"          { RETURN_BIT(T_BASIC, BASIC_UNSIGNED); }


   /*-----------------------------------------------------------------------*/

<FILE_MAIN>"("                 {
                                 token_const = token_next;
                                 if (TOP_TOKEN()->_code == T_OPERATOR)
                                 {
                                   if (input() == ')')
                                     RETURN_KEYWORD(T_IDENT, STR_PARENTHS)
                                   else
                                     RETURN_TOKEN(T_LEXER_ERROR);
                                 }
                                 else
                                   RETURN_KEYWORD(T_LPARENTH, STR_LPARENTH);
                               }

<FILE_MAIN>")"                 {
                                 token_const = token_next;
                                 RETURN_KEYWORD(T_RPARENTH, STR_RPARENTH);
                               }

<FILE_MAIN>","                 {
                                 token_const = token_next;
                                 if (TOP_TOKEN()->_code == T_OPERATOR)
                                   RETURN_KEYWORD(T_IDENT, STR_COMMA)
				 else
                                   RETURN_KEYWORD(T_COMMA, STR_COMMA);
                               }

<FILE_MAIN>"*"                 {
                                 token_const = token_next;
                                 if (TOP_TOKEN()->_code == T_OPERATOR)
                                   RETURN_KEYWORD(T_IDENT, STR_STAR)
				 else
                                   RETURN_KEYWORD(T_STAR, STR_STAR);
                               }

<FILE_MAIN>"&"                 {
                                 token_const = token_next;
                                 if (TOP_TOKEN()->_code == T_OPERATOR)
                                   RETURN_KEYWORD(T_IDENT, STR_AND)
				 else
                                   RETURN_KEYWORD(T_AND, STR_AND);
                               }


<FILE_MAIN>"private"           { RETURN_KEYWORD(T_PRIVATE, STR_PRIVATE);     }

<FILE_MAIN>"protected"         { RETURN_KEYWORD(T_PROTECTED, STR_PROTECTED); }

<FILE_MAIN>"public"            { RETURN_KEYWORD(T_PUBLIC, STR_PUBLIC);       }


<FILE_MAIN>"~"                 { RETURN_KEYWORD(T_TILDE, STR_TILDE);         }

<FILE_MAIN>"..."               { RETURN_KEYWORD(T_ELLIPSIS, STR_ELLIPSIS);   }

<FILE_MAIN>"::"                { RETURN_KEYWORD(T_PREFIX, STR_PREFIX);       }


   /*-----------------------------------------------------------------------*/

<FILE_MAIN>"const"             {
                                 if (TOP_TOKEN()->_code == T_BASIC)
                                   RETURN_BIT(T_BASIC, BASIC_CONST)
                                 else if (token_const != BR_Null)
                                   token_const->_bits |= BR_INFO_CONST;
                               }


   /*-----------------------------------------------------------------------*/

<FILE_MAIN>{OPERATOR}          { 
                                 if (TOP_TOKEN()->_code == T_OPERATOR)
                                   RETURN_TOKEN(T_IDENT)
				 else
                                   RETURN_TOKEN(T_LEXER_ERROR);
                               }

<FILE_MAIN>"operator"          {
                                 token_const = token_next;
				 RETURN_KEYWORD(T_OPERATOR, STR_OPERATOR);
                               }


   /*-----------------------------------------------------------------------*/

<TEMPLATE_DECL>"class"         { PUSH_STATE(TEMPLATE_ARG);  }

<TEMPLATE_ARG>{IDENT}          { 
                                 POP_STATE();
                                 RETURN_TOKEN(T_TEMPLATE_ARG);
                               }

<TEMPLATE_ARG>[^ \v\t\f\r\n]   { POP_STATE();      }

<TEMPLATE_DECL>">"             {
                                 POP_STATE();
                                 RETURN_CODE(T_SUP);
                               }

<TEMPLATE_DECL>","             {
                                 if (TOP_STATE() == TEMPLATE_ARG)
                                   POP_STATE();
                               }

<TEMPLATE_DECL>[^ \v\t\f\r#{/'"\>,\n]

<FILE_MAIN>"template"          {
                                 PUSH_STATE(TEMPLATE_DECL);
                                 RETURN_CODE(T_TEMPLATE);
                               }


   /*-----------------------------------------------------------------------*/

<TEMPLATE_INST>"<"             { template_level++; }

<TEMPLATE_INST>">"             {
                                 --template_level;
                                 if (template_level <= 0)
                                   POP_STATE();
                               }

<TEMPLATE_INST>[^#{/'"\<>\n]+

<FILE_MAIN>"<"                 {
                                 if (TOP_TOKEN()->_code == T_OPERATOR)
                                   RETURN_TOKEN(T_IDENT)
                                 else
                                 {
                                   template_level = 1;
                                   PUSH_STATE(TEMPLATE_INST);
                                 }
                               }


   /*-----------------------------------------------------------------------*/

<FILE_MAIN>":"                 {
                                 if (colon_ignore != BR_FALSE)
                                   colon_ignore = BR_FALSE;
                                 else
                                 {
	                           PUSH_STATE(BLACK_HOLE);
                                   bhole_exit  = BHEB_SEMI;
                                   bhole_exit |= BHEB_COMMA;
                                   bhole_exit |= BHEB_BRACKET;
                                   bhole_exit |= BHEB_UN_SEMI;
                                   bhole_exit |= BHEB_UN_COMMA;
                                   bhole_exit |= BHEB_UN_BRACKET;
                                   bhole_par_level = 0;
                                 }
                                 RETURN_CODE(T_COLON);
                               }

<FILE_MAIN>"="                 {
                                 if (TOP_TOKEN()->_code == T_OPERATOR)
                                   RETURN_KEYWORD(T_IDENT, STR_EQUAL)
                                 else
                                 {
	                           PUSH_STATE(BLACK_HOLE);
                                   bhole_exit  = BHEB_COMMA;
                                   bhole_exit |= BHEB_SEMI;
                                   bhole_exit |= BHEB_BRACKET;
                                   bhole_exit |= BHEB_PARENTH;
                                   bhole_exit |= BHEB_UN_COMMA;
                                   bhole_exit |= BHEB_UN_SEMI;
                                   bhole_exit |= BHEB_UN_BRACKET;
                                   bhole_exit |= BHEB_UN_PARENTH;
                                   bhole_par_level = 0;
                                   RETURN_CODE(T_EQUAL);
                                 }
                               }

<FILE_MAIN>"["                 {
                                 if (TOP_TOKEN()->_code == T_OPERATOR)
                                 {
                                   if (input() == ']')
                                     RETURN_KEYWORD(T_IDENT, STR_ARRAY)
                                   else
                                     RETURN_TOKEN(T_LEXER_ERROR);
                                 }
                                 else
                                 {
	                           PUSH_STATE(BLACK_HOLE);
                                   bhole_exit  = BHEB_SQUARE;
                                   bhole_par_level = 0;
                                   RETURN_KEYWORD(T_ARRAY, STR_ARRAY);
                                 }
                               }


   /*-----------------------------------------------------------------------*/

<FILE_MAIN>{IDENT}             { RETURN_TOKEN(T_IDENT);  }


   /*-----------------------------------------------------------------------*/

<BLACK_HOLE>[^#{/'";,\]()\n]+

<BLACK_HOLE>"("                { bhole_par_level++; }

<BLACK_HOLE>")"                {
                                 if (  (bhole_par_level <= 0)
                                     &&((bhole_exit & BHEB_PARENTH) != 0))
                                 {
                                   POP_STATE();
                                   if ((bhole_exit & BHEB_UN_PARENTH) != 0)
                                     unput(yytext[0]);
                                 }
                                 --bhole_par_level;
                               }

<BLACK_HOLE>";"                {
                                 if (  (bhole_par_level <= 0)
                                     &&((bhole_exit & BHEB_SEMI) != 0))
                                 {
                                   POP_STATE();
                                   if ((bhole_exit & BHEB_UN_SEMI) != 0)
                                     unput(yytext[0]);
                                 }
                               }

<BLACK_HOLE>","                {
                                 if (  (bhole_par_level <= 0)
                                     &&((bhole_exit & BHEB_COMMA) != 0))
                                 {
                                   POP_STATE();
                                   if ((bhole_exit & BHEB_UN_COMMA) != 0)
                                     unput(yytext[0]);
                                 }
                               }

<BLACK_HOLE>"{"                {
                                 if (  (bhole_par_level <= 0)
                                     &&((bhole_exit & BHEB_BRACKET) != 0))
                                 {
                                   POP_STATE();
                                   if ((bhole_exit & BHEB_UN_BRACKET) != 0)
                                     unput(yytext[0]);
                                 }
                               }

<BLACK_HOLE>"]"                {
                                 if (  (bhole_par_level <= 0)
                                     &&((bhole_exit & BHEB_SQUARE) != 0))
                                 {
                                   POP_STATE();
                                   if ((bhole_exit & BHEB_UN_SQUARE) != 0)
                                     unput(yytext[0]);
                                 }
                               }

<BLACK_HOLE>"/"


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

<BLOCK_IGN>{BLOCK_CNTS}*"{"         { block_level++; }

<BLOCK_IGN>{BLOCK_CNTS}*"{\n"       {
                                      NEW_LINE();
                                      block_level++;
                                    }

<BLOCK_IGN>{BLOCK_CNTS}*"}"         {
                                      --block_level;
                                      if (block_level <= 0)
                                      {
                                        POP_STATE();
                                        RETURN_CODE(T_RBRACKET);
                                      }
                                    }

<BLOCK_IGN>{BLOCK_CNTS}*"}\n"       {
                                      NEW_LINE();
                                      --block_level;
                                      if (block_level <= 0)
                                      {
                                        POP_STATE();
                                        /*fprintf(stderr, ">>> top_state2 = %d\n", top_state); */
                                        RETURN_CODE(T_RBRACKET);
                                      }
                                    }

<BLOCK_IGN>{BLOCK_CNTS}*"\n"        { NEW_LINE();           }

<BLOCK_IGN>{BLOCK_CNTS}+

<BLOCK_IGN>"/"


"{"                                 {
                                      if (bracket_ignore != BR_FALSE)
                                        bracket_ignore = BR_FALSE;
                                      else
                                      {
                                        block_level = 1;
                                        PUSH_STATE(BLOCK_IGN);
                                        RETURN_CODE(T_LBRACKET);
                                      }
                                    }


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

<COMMENT1>[^*$/\n]*"*/"             { POP_STATE();          }

<COMMENT1>[^*$/\n]*"\n"             { NEW_LINE();           }

<COMMENT1>[^*$/\n]*"/*"             { PUSH_STATE(COMMENT1); }

<COMMENT1>[^*$/\n]*"*"

<COMMENT1>[^*$/\n]*"/"

<COMMENT1>"$$"{TAG}                 {
                                      if (BR_info_handler != BR_Null)
                                        BR_info_handler(BR_Null,
                                                        &(yytext[2]),
                                                        BR_INFO_TAG,
                                                        line_num);
                                    }

<COMMENT1>"$"

<COMMENT1>[^*$/\n]+


"/*"                                { PUSH_STATE(COMMENT1); }


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

<COMMENT2>[^\n$]*"\n"               {
                                      NEW_LINE();
                                      POP_STATE();
                                    }

<COMMENT2>"$$"{TAG}                 {
                                      if (BR_info_handler != BR_Null)
                                        BR_info_handler(BR_Null,
                                                        &(yytext[2]),
                                                        BR_INFO_TAG,
                                                        line_num);
                                    }

<COMMENT2>"$"

<COMMENT2>[^$\n]+


"//"                                { PUSH_STATE(COMMENT2); }


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

<STR_IGN>([^"\\\n]|("\\".))*"\\\n"  { NEW_LINE();           }

<STR_IGN>([^"\\\n]|("\\".))*"\""    { POP_STATE();          }

<STR_IGN>([^"\n])+"\n"              {
                                      if (str_error_cnt == 0)
                                      {
                                        str_error_cnt++;
                                        fprintf(stderr,
                                                ">>>> String Error at line %d\n",
                                                line_num);
                                      }
                                      else
                                        POP_STATE();
                                      NEW_LINE();
                                    }

<STR_IGN>"\n"                       {
                                      str_error_cnt++;
                                      NEW_LINE();       
                                    }

"'"([^'\\\n]|("\\".))*"'"

"\""([^"\\\n]|("\\".))*"\""

"\""				    {
                                      str_error_cnt = 0;
                                      PUSH_STATE(STR_IGN);
                                    }


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

<MACRO_START>{INTEGER}              {
                                      line_named = BR_FALSE;
                                      line_num   = atoi(yytext);
                                      SET_STATE(MACRO_LINE);
                                    }

<MACRO_START>{TWS}+


<MACRO_START>.                      {
                                      unput(yytext[0]);
                                      SET_STATE(MACRO_IGN);
                                    }

<MACRO_LINE>{FILE_NAME}             {
			              line_named = BR_TRUE;
                                      if (   (yyleng != fname_len)
                                          || (strcmp(yytext, fname) != 0))
                                      {
                                        if (   (yyleng != lname_len)
                                            || (strcmp(yytext, lname) != 0))
                                        {
                                          lname_len = yyleng;
                                          strcpy(lname, yytext);
                                          if (BR_info_handler != BR_Null)
                                            BR_info_handler(BR_Null,
                                                            lname,
                                                            BR_INFO_INCLUDE,
                                                            line_num);
                                        }
                                        line_num = 0;
                                      }
                                    }

<MACRO_LINE>({TWS}|[0-9"])+

<MACRO_LINE>"\n"                    {
                                      POP_STATE();
                                      if (line_named != BR_FALSE)
                                      {
                                        if (line_num == 0)
                                        {
                                          if (TOP_STATE() != FILE_IGN)
                                            PUSH_STATE(FILE_IGN);
                                        }
                                        else
                                        {
                                          if (TOP_STATE() == FILE_IGN)
                                            POP_STATE();
                                        }
                                      }
                                    }


<MACRO_IGN>([^\\\n]|("\\".))*"\\\n" { NEW_LINE(); }

<MACRO_IGN>(.)*"\n"                 {
                                      NEW_LINE();
                                      POP_STATE();
                                      /*fprintf(stderr, ">>> top_state1 = %d\n", top_state);*/
                                    }

^{TWS}*"#"                          { PUSH_STATE(MACRO_START); }


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

<FILE_IGN>^([^#\n][^\n]*)?"\n"


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

{TWS}+

"\n"+                               { line_num += yyleng; }

{TWS}*"\n"                          { NEW_LINE();         }

<<EOF>>                             { yyterminate();      }


.                                   {
                                      /*
                                      fprintf(stderr,
                                        ">>>>>>>>>>  Bad : %s (s=%d, l=%d)\n",
                                        yytext, 
                                        TOP_STATE(), 
                                        line_num);
                                      */
                                    }
%%


   /*-----------------------------------------------------------------------*/

void
BR_lex_init(main_file, main_name)
    FILE* main_file;
    char* main_name;
{
  if (yyin == 0)
    yyin = main_file;
  else
    yyrestart(main_file);

  val_next       = val_buf;
  token_next     = token_buf;
  token_frame    = BR_Null;
  token_const    = BR_Null;
  bracket_ignore = BR_FALSE;
  colon_ignore   = BR_FALSE;

  strcpy(fname, main_name);
  fname_len = strlen(main_name);

  *lname    = '\0';
  lname_len = 0;

  line_num  = 1;
  top_state = 0;
  SET_STATE(FILE_MAIN);
}


   /*-----------------------------------------------------------------------*/

void
BR_lex_empty_frame()
{
  token_next         = token_frame + 1;
  val_next           = token_frame->_val;
  token_frame->_bits = token_frame->_val_len;
  token_const        = BR_Null;
}


   /*-----------------------------------------------------------------------*/

BR_TokenPt
BR_lex_stack_frame(init_info_bits)
    BR_ULong init_info_bits;
{
  BR_TokenPt result;

  result = BR_Null;
  if (token_next < &(token_buf[MAX_TOKEN_COUNT]))
  {
    result            = token_next++;

    result->_code     = T_FRAME;
    result->_bits     = init_info_bits;
    result->_val_len  = init_info_bits;
    result->_val      = val_next;
    result->_next     = token_frame;
    result->_last     = result;
    result->_line_num = 0;
    token_frame       = result;
    token_const       = BR_Null;
  }
  else
    fprintf(stderr, ">>>> Warning: Lexer Tokens buffer exhausted\n");

  return(result);
}


   /*-----------------------------------------------------------------------*/

BR_TokenPt
BR_lex_unstack_frame()
{
  val_next    = token_frame->_val;
  token_next  = token_frame->_last;
  token_frame = token_frame->_next;

  return(token_frame);  
}


   /*-----------------------------------------------------------------------*/

void
BR_lex_ignore_proc_tail()
{
  if (TOP_STATE() != BLACK_HOLE)
    PUSH_STATE(BLACK_HOLE);

  bhole_exit  = BHEB_BRACKET;
  bhole_exit |= BHEB_UN_BRACKET;

  bhole_par_level = 0;
}


   /*-----------------------------------------------------------------------*/

void
BR_lex_jump_bracket()
{
  if (TOP_STATE() == BLOCK_IGN)
    POP_STATE()
  else
    bracket_ignore = BR_TRUE;
}


   /*-----------------------------------------------------------------------*/

void
BR_lex_jump_colon()
{
  if (TOP_STATE() == BLACK_HOLE)
    POP_STATE()
  else
    colon_ignore = BR_TRUE;
}


   /*-----------------------------------------------------------------------*/

BR_TokenPt
BR_lex_alloc_token(code, val, val_len)
    BR_Int  code;
    BR_Str* val;
    BR_Int  val_len;
{
  BR_TokenPt result;

  result = BR_Null;
  if (token_next < &(token_buf[MAX_TOKEN_COUNT]))
  {
    result            = token_next++;
    result->_code     = code;
    result->_val      = val;
    result->_val_len  = val_len;
    result->_line_num = line_num;
    result->_next     = BR_Null;
    result->_last     = result;
    result->_prefix   = BR_Null;
    result->_bits     = BR_INFO_EMPTY;
  }
  else
    fprintf(stderr, ">>>> Warning: Lexer Tokens buffer exhausted\n");

  return(result);
}


   /*-----------------------------------------------------------------------*/

BR_Int
BR_lex_get_line_num()
{
  return(line_num);
}


   /*-----------------------------------------------------------------------*/

void
BR_lex_save_state()
{
  token_frame->_line_num = top_state;
}


   /*-----------------------------------------------------------------------*/

void
BR_lex_synchronize()
{
  top_state = token_frame->_line_num;
}

