%{

/*
 *
 *  (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC.
 *  (c) Copyright 1989 HEWLETT-PACKARD COMPANY
 *  (c) Copyright 1989 DIGITAL EQUIPMENT CORPORATION
 *  To anyone who acknowledges that this file is provided "AS IS"
 *  without any express or implied warranty:
 *                  permission to use, copy, modify, and distribute this
 *  file for any purpose is hereby granted without fee, provided that
 *  the above copyright notices and this notice appears in all source
 *  code copies, and that none of the names of Open Software
 *  Foundation, Inc., Hewlett-Packard Company, or Digital Equipment
 *  Corporation be used in advertising or publicity pertaining to
 *  distribution of the software without specific, written prior
 *  permission.  Neither Open Software Foundation, Inc., Hewlett-
 *  Packard Company, nor Digital Equipment Corporation makes any
 *  representations about the suitability of this software for any
 *  purpose.
 *
 */

/*
 */

 /*
 **
 **  NAME:
 **
 **      acf.l
 **
 **  FACILITY:
 **
 **      Interface Definition Language (IDL) Compiler
 **
 **  ABSTRACT:
 **
 ** "lex" source file for Attribute Configuration File (ACF) parser.
 **
 **  VERSION: DCE 1.0
 **
 */

#define PROCESSING_LEX          /* Define before including nidl.h */
#define PROCESSING_ACF_LEX      /* Define before including nidl.h */
#include <nidl.h>               /* IDL common defs */
#include <acf_y.h>          /* yacc include file */
#include <nametbl.h>            /* Nametable defs */
#include <nidlmsg.h>            /* Error message IDs */
#include <command.h>
#include <flex_bison_support.h>

/* Tank Trap to stop non-flex lexxers */
/* The macro FLEX_SCANNER is defined and generated by FLEX */

#ifndef FLEX_SCANNER
This grammar file needs to be built with GNU Flex V2.4.6 or later.
  GNU Flex can be be obtained from ftp://prep.ai.mit.edu:/pub/gnu
#endif

extern int acf_yylineno;
extern YYSTYPE acf_yylval;

extern void commenteof(         /* Called on EOF within comment */
#ifdef PROTO
    void
#endif
);

static void acf_yymark(         /* Handles # <lineno> left by cpp */
#ifdef PROTO
    void
#endif
);

static int acf_screen(          /* Screens a token to see if it is a keyword */
#ifdef PROTO
    char *token
#endif
);

static void acf_read_comment(   /* Reads and copies comment text */
#ifdef PROTO
    void
#endif
);

static int yywrap(void)
{

   /* 
    * Free the Flex buffer, yy_curent_buffer and yy_delete_buffer() 
    * are FLEX interfaces to the internal buffering system.
    */

#ifdef YY_CURRENT_BUFFER_LVALUE
   acf_yy_delete_buffer(YY_CURRENT_BUFFER_LVALUE); /* free the FLEX buffer */
#else
   acf_yy_delete_buffer(yy_current_buffer); /* free the FLEX buffer */
#endif
   acf_yylineno = 1;
   return 1;
}

/*static char *identifier_name;    Ptr to parsed identifier */

typedef struct                  /* Keyword and corresponding value */
{
    char    *keyword;
    int     token_value;
} keyword_entry;

static keyword_entry acf_keywords[] =   /* Table of keywords and values */
{
    {"auto_handle",     AUTO_HANDLE_KW},
    {"binding_callout", BINDING_CALLOUT_KW},
    {"code",            CODE_KW},
    {"comm_status",     COMM_STATUS_KW},
    {"cs_char",         CS_CHAR_KW},
    {"cs_tag_rtn",      CS_TAG_RTN_KW},
    {"enable_allocate", ENABLE_ALLOCATE_KW},
    {"explicit_handle", EXPLICIT_HANDLE_KW},
    {"extern_exceptions", EXTERN_EXCEPS_KW},
    {"fault_status",    FAULT_STATUS_KW},
    {"handle_t",        HANDLE_T_KW},
    {"heap",            HEAP_KW},
    {"implicit_handle", IMPLICIT_HANDLE_KW},
    {"include",         INCLUDE_KW},
    {"interface",       INTERFACE_KW},
    {"in_line",         IN_LINE_KW},
    {"nocode",          NOCODE_KW},
    {"out_of_line",     OUT_OF_LINE_KW},
    {"represent_as",    REPRESENT_AS_KW},
    {"typedef",         TYPEDEF_KW},
    {"nocancel",        NOCANCEL_KW},
    {0,                 0}      /* Sentinel - Do not remove */
};

%}


delim           [ \t\n\f]
ws              {delim}+
letter          [A-Za-z_$]
digit           [0-9]
oct_digit       [0-7]
hex_digit       [0-9A-Fa-f]
id              {letter}({letter}|{digit})*
other           .

%option yylineno

%%


{ws}        { /* White space: No action, and no return */ }
'\n'        { /* GNUFLEX doesnt automatically track line #'s */
              acf_yylineno++;
            }
","         {return(COMMA);}
"{"         {return(LBRACE);}
"??<"       {return(LBRACE);}
"["         {return(LBRACKET);}
"("         {return(LPAREN);}
"}"         {return(RBRACE);}
"??>"       {return(RBRACE);}
"]"         {return(RBRACKET);}
")"         {return(RPAREN);}
";"         {return(SEMI);}

^"#".*\n    {acf_yymark();}

\"[^\"\n]*\" {  /* Quoted string: Strip off quotes, add to string table. */
                char    stripped_string[max_string_len];

                strcpy(stripped_string, (char *)&yytext[1]);
                stripped_string[strlen((char *)yytext)-2] = '\0';
                acf_yylval.y_string = STRTAB_add_string(stripped_string);
                return(STRING);
            }

"/*"        {   /* Comment: Ignore through closing delimiter. */
                acf_read_comment();
            }

{id}        {
                 /* If id is too long, truncate it and issue a warning */
                 if (yyleng > MAX_ID) {
                    NAMETABLE_id_t id;
                    char const *identifier;
                    id = NAMETABLE_add_id((char *)yytext);
                    NAMETABLE_id_to_string(id, &identifier);
                    log_warning(acf_yylineno, NIDL_IDTOOLONG, identifier,
				MAX_ID, NULL);
                    /* Truncate the string */
                    yytext[MAX_ID] = '\0';
                    id = NAMETABLE_add_id((char *)yytext);
                    }

                /* Identifier: See if it is a valid keyword. */
                return acf_screen((char *)yytext);
            }

{other}     {return(UNKNOWN);};
%%

/*
**  a c f _ y y m a r k
**
**  Processes a "# lineno" line as left by cpp.
**
**  Implicit Outputs:
**      acf_yylineno is updated; If a filename was included in the source
**      line, set_name_for_errors is called to set up the source filename
**      for error messages.
*/

static void acf_yymark()
{
    char    *source ; /* Source file name in #line directive */
    int prev_lineno = acf_yylineno - 1;

    source = NEW_VEC (char, yyleng);
    if (sscanf((char *)yytext, "# line %d %s", &acf_yylineno, source) < 1)
    {
	if (sscanf((char *)yytext, "# %d %s", &acf_yylineno, source) < 1)
        {
            log_warning(prev_lineno, NIDL_CPPCMDOPT,
#ifdef VMS
                (CMD_DCL_interface) ? "/PREPROCESS" :
#endif
                "-cpp_cmd", NULL);
        }
    }

    /* If text included a source file name, set name for error reporting. */
    if (source[0] != '\0')
    {
        char    file_name[max_string_len];

        /* Strip the quotes. */
        strcpy(file_name, &source[1]);
        file_name[strlen(file_name)-1] = '\0';

        set_name_for_errors(file_name);
    }

    FREE(source);
}

/*
 *  a c f _ s c r e e n
 *
 *  Function:   Checks to see if a token is a keyword.
 *
 *  Inputs:     token to check
 *
 *  Returns:    specific keyword ID if token is a keyword;
 *              the value IDENTIFIER otherwise
 */

#ifdef PROTO
static int acf_screen(char *token)
#else
static int acf_screen(token)
    char *token;                /* Token to "screen" */
#endif

{
    int i;

    /*
     * Scan the reserved word table.
     */
    for (i = 0; acf_keywords[i].keyword != 0; i++)
        if (strcmp(token, acf_keywords[i].keyword) == 0)
            return acf_keywords[i].token_value;     /* Return keyword ID */

    /*
     * Not a reserved word; therefore, an identifier, return nametable id.
     */
    acf_yylval.y_id = NAMETABLE_add_id(token);
    return IDENTIFIER;                  /* Return IDENTIFER */
}

/*
 *  a c f _ r e a d _ c o m m e n t
 *
 *  Function:   Reads a comment in the source file.
 *
 */

#ifdef PROTO
static void acf_read_comment(void)
#else
static void acf_read_comment()
#endif

{
    int     c;

    while ( (c = input()) != 0 )
    {
        if (c == '*')
        {
            if ( (c = input()) == '/')
                break;
            else
                yyunput(c, yytext);
        }
        else if (c == 0)
            commenteof();
    }
}

/*
 *  a c f _ k e y w o r d _ l o o k u p
 *
 *  Looks up a keyword's text string given its numeric token value.
 */

char * acf_keyword_lookup
#ifdef PROTO
(
    int         token_value     /* Numeric value of keyword token */
)
#else
(token_value)
    int         token_value;    /* Numeric value of keyword token */
#endif

{
    keyword_entry * entry;

    for (entry = acf_keywords ; entry->keyword != NULL ; entry++)
        if (entry->token_value == token_value)
            return entry->keyword;

    /* Not found, just return question mark. */
    return "?";
}

#ifdef FLEX_SCANNER

/*****************************************************************
 *
 *  Helper functions for managing multiple FLEX contexts
 *
 *  GNU FLEX support for DCE 1.2.2 idl_compiler
 *  added 07-11-97 Jim Doyle, Boston University, <jrd@bu.edu>
 *
 *  Maintainance note:
 *
 *    The set of flex-specific static and global variables
 *    managed by the following code may need to be changed
 *    for versions of FLEX newer or later than v2.5.4. This
 *    code was tested with Flex 2.4.6 and 2.5.4. V2.4 of FLEX
 *    defined three static variables (yy_start_stack,
 *    yy_start_stack_depth,yy_start_stack_ptr). In V2.5 of FLEX,
 *    these three statics disappeared. Fortunately FLEX defined
 *    macros YY_FLEX_MANOR_VERSION and YY_FLEX_MINOR_VERSION.
 *    These are helpful for conditionally compiling in support for
 *    several vintages of FLEX.
 *
 * 
 *****************************************************************/

/*****************************************************************
 * 
 * Data structure to store the state of a FLEX lexxer context
 *        ACF grammar
 *
 *****************************************************************/

struct acf_flexxer_state_data {

  /*
   * flex statics - hidden from the outside world. These are
   * generated by flex.
   *
   * MAINTAINANCE NOTE:  In versions later or earlier than 2.5.4,
   * the exact set of static variables that FLEX generates may be
   * different than is what is defined here. In that case, generate
   * the lexxer (i.e. flex nidl.l), grep the resulting generated C
   * flexxer for the word 'static'. You can then determine what 
   * variables are new, dont exist, or have been renamed. Another
   * alternative for learning the names of all the static and global
   * variables used by the flexxer - is to compile the stub and 
   * examine the object table dump (i.e using nm(1) on the .o file).
   *
   */

  YY_BUFFER_STATE yy_current_buffer;
  char            yy_hold_char;
  int             yy_n_chars;
  char          * yy_c_buf_p;
  int             yy_init;
  int             yy_start;
  int             yy_did_buffer_switch_on_eof;
#ifdef YY_USES_REJECT
  yy_state_type  *yy_state_ptr;
  char           *yy_full_match;
  int		  yy_lp;
#else
  yy_state_type   yy_last_accepting_state;
  char          * yy_last_accepting_cpos;
#endif

 #if (YY_FLEX_MAJOR_VERSION == 2) && (YY_FLEX_MINOR_VERSION == 4)
  int             yy_start_stack_ptr;
  int             yy_start_stack_depth;
  int           * yy_start_stack;
 #endif


  /*
   * flex globals - visible to the outside world
   *
   */

  FILE          * yyin;
  FILE          * yyout;
  int             yylineno;
  YYSTYPE         yylval;
  int             yyleng;
  char          * yytext;

};

typedef struct acf_flexxer_state_data acf_flexxer_activation_record;

/*****************************************************************
 *
 * Basic constructors/destructors for FLEX activation states
 *
 *****************************************************************/

void *
new_acf_flexxer_activation_record()
  {
    return (malloc(sizeof(acf_flexxer_activation_record)));
  }

void
delete_acf_flexxer_activation_record(void * p)
{
 if (p)
  {

  /*
   * Note: do not call acf_yy_delete_buffer() from here.
   * Always do it from acf_yywrap(). Otherwise, severe
   * dementia and psychosis will occur.
   */

    free((void *)p);
  }
}


/*****************************************************************
 *
 * Get/Set/Initialize methods
 *
 *****************************************************************/

void *
get_current_acf_flexxer_activation()
  {
    acf_flexxer_activation_record * p;

    p = (acf_flexxer_activation_record * )new_acf_flexxer_activation_record();

    /* 
     * save the statics internal to the flexxer
     *
     */

#ifdef YY_CURRENT_BUFFER_LVALUE
    yyensure_buffer_stack();
    p->yy_current_buffer = YY_CURRENT_BUFFER_LVALUE;
#else
    p->yy_current_buffer = yy_current_buffer;
#endif
    p->yy_hold_char = yy_hold_char;
    p->yy_n_chars = yy_n_chars;
    p->yy_c_buf_p = yy_c_buf_p;
    p->yy_init = yy_init;
    p->yy_start = yy_start;
    p->yy_did_buffer_switch_on_eof = yy_did_buffer_switch_on_eof;
#ifdef YY_USES_REJECT
    p->yy_state_ptr = yy_state_ptr;
    p->yy_full_match = yy_full_match;
    p->yy_lp = yy_lp;
#else
    p->yy_last_accepting_state = yy_last_accepting_state;
    p->yy_last_accepting_cpos = yy_last_accepting_cpos;
#endif

    /* FLEX 2.5 does not have these variables.
     * FLEX 2.4 does have them though...
     */

  #if (YY_FLEX_MAJOR_VERSION == 2) && (YY_FLEX_MINOR_VERSION == 4)
    p->yy_start_stack_ptr = yy_start_stack_ptr;
    p->yy_start_stack_depth = yy_start_stack_depth;
    p->yy_start_stack = yy_start_stack;
  #endif

    /*
     * save the globals, these are visible outside the scope
     * of the lexxer
     *
     */

    p->yyin = acf_yyin;
    p->yyout = acf_yyout;
    p->yylineno = acf_yylineno;
    p->yylval = acf_yylval;
    p->yyleng = acf_yyleng;
    p->yytext = acf_yytext;


    return (void *)p;
  }


void
set_current_acf_flexxer_activation(void * ptr)
  {

    acf_flexxer_activation_record * p = (acf_flexxer_activation_record *)ptr;

    /* restore the statics */
#ifdef YY_CURRENT_BUFFER_LVALUE
    YY_CURRENT_BUFFER_LVALUE = p->yy_current_buffer;
#else
    yy_current_buffer = p->yy_current_buffer;
#endif
    yy_hold_char = p->yy_hold_char;
    yy_n_chars = p->yy_n_chars;
    yy_c_buf_p = p->yy_c_buf_p;
    yy_init = p->yy_init;
    yy_start = p->yy_start;
    yy_did_buffer_switch_on_eof = p->yy_did_buffer_switch_on_eof;
#ifdef YY_USES_REJECT
    yy_state_ptr = p->yy_state_ptr;
    yy_full_match = p->yy_full_match;
    yy_lp = p->yy_lp;
#else
    yy_last_accepting_state = p->yy_last_accepting_state;
    yy_last_accepting_cpos = p->yy_last_accepting_cpos;
#endif

    /* FLEX 2.5 does not have these variables.
     * FLEX 2.4 does have them though...
     */

  #if (YY_FLEX_MAJOR_VERSION == 2) && (YY_FLEX_MINOR_VERSION == 4)
    yy_start_stack_ptr = p->yy_start_stack_ptr;
    yy_start_stack_depth = p->yy_start_stack_depth;
    yy_start_stack = p->yy_start_stack;
  #endif
    
    /*
     * save the globals, these are visible outside the scope
     * of the lexxer
     *
     */

    acf_yyin = p->yyin;
    acf_yyout = p->yyout;
    acf_yylineno = p->yylineno;
    acf_yylval = p->yylval;
    acf_yyleng = p->yyleng;
    acf_yytext = p->yytext;


  }

void
init_new_acf_flexxer_activation()
  {

    /*
     * set some initial conditions for a new FLEXER state
     * These were gleaned by looking at the compile-time 
     * initializations in the generated nidl_lex_yy.c file.
     *
     */

#ifdef YY_CURRENT_BUFFER_LVALUE
    yyensure_buffer_stack();
    YY_CURRENT_BUFFER_LVALUE = 0;
#else
    yy_current_buffer = 0;
#endif /* YY_CURRENT_BUFFER_LVALUE */
    yy_c_buf_p = (char *) 0;
    yy_init = 1;
    yy_start = 0;

    /* FLEX 2.5 does not have these variables.
     * FLEX 2.4 does have them though...
     */
  #if (YY_FLEX_MAJOR_VERSION == 2) && (YY_FLEX_MINOR_VERSION == 4)
    yy_start_stack_ptr = 0;
    yy_start_stack_depth = 0;
    yy_start_stack = 0;
  #endif


  }

#endif /* FLEX_SCANNER */

 /** End of "lex" source file. **/
/* preserve coding style vim: set tw=78 sw=4 : */
