/*
 * 
 * (c) Copyright 1991 OPEN SOFTWARE FOUNDATION, INC.
 * (c) Copyright 1991 HEWLETT-PACKARD COMPANY
 * (c) Copyright 1991 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
**
**      IDLPARSE.C
**
**  FACILITY:
**
**      Interface Definition Language (IDL) Compiler
**
**  ABSTRACT:
**
**      This file deals with the problem of using yacc recursively.  On
**      platforms which define the yacc variables as static, there is no way to
**      save, reset, and later restore the current yacc state without having
**      the C code in the same file as the (staticly) declared variables.  The
**      code cannot be placed in the idl.y file because some yacc's (e.g.
**      SunOS 4.1) place any C code *before* the yacc variable definitions.  To
**      ensure that the yacc variables are defined prior to using them, this
**      file includes the yacc-generated code at the beginning of the file.
**
**     Layout for this file is as follows:
**
**          1. include yacc-generated file (from idl.y).
**          2. declare lex variables which must be saved/restored (see comment)
**          3. define the save/restore structure.
**          4. define save and restore routines.
**
**  VERSION: DCE 1.0
*/
 
/*
 * We assume sysdep.h is included by this file.
 */
#include <y_tab.c.h> /* generated by yacc from idl.y */

/*
 * Variables declared in the generated yacc code (included above) :
 *
 *      -- common definitions --
 *      YYSTYPE yylval;
 *      YYSTYPE yyval;
 *      int yychar;
 *      int yynerrs;
 *      YACC_INT yyerrflag;
 *
 *      -- SunOS 4.0 definitions --
 *      -- Ultrix 3.1 definitions --
 *      YYSTYPE yyv[YYMAXDEPTH];
 *
 *      -- SunOS 4.1 --
 *      static YYSTYPE *yyv;
 *      static int *yys;
 *      static YYSTYPE *yypv;
 *      static int yystate;
 *      static int yytmp;
 *
 *      -- SVR4 definitions --
 *      int yy_yys[YYMAXDEPTH];
 *      int *yys;
 *      YYSTYPE yy_yyv[YYMAXDEPTH];
 *      YYSTYPE *yyv;
 */
 
/*
 * Declare definitions for yyv and yys variables.  The problem is that
 * some yacc's declare these as global variables, and others declare
 * a pointer and call malloc to define the array.
 *
 * Currently, platforms where yys is local to yyparse() declare this
 * as an array.  This could be optimized to use a pointer, or even not
 * use the variable at all.
 */
#if     defined (SVR4_LEX_YACC)
/*
 * SVR4 has both, and names the arrays yy_yy{v,s} and the pointers yy{v,s}
 */
# define NIDL_YYV_DEFINITION    YYSTYPE yy_yyv[YYMAXDEPTH], *yyv
# define NIDL_YYS_DEFINITION    YACC_INT yy_yys[YYMAXDEPTH], *yys
# define NIDL_YACC_YYV_ARRAY
# define NIDL_YACC_YYS_ARRAY
#elif defined (GNU_LEX_YACC)
/* GNU doesn't use any of this */
# define NIDL_YYV_DEFINITION
# define NIDL_YYS_DEFINITION

#elif   !(defined(SUN_LEX_YACC) && defined(SUN_41_LEX_YACC))
# define NIDL_YYV_DEFINITION    YYSTYPE yyv[YYMAXDEPTH]
# define NIDL_YYS_DEFINITION    YACC_INT yys[YYMAXDEPTH]
 
# define NIDL_YACC_YYV_ARRAY
# define NIDL_YACC_YYS_ARRAY
 
#else   /* !defined(Sun 4.1 or GNU lex and yacc) */
 
# define NIDL_YYV_DEFINITION    YYSTYPE *yyv
# define NIDL_YYS_DEFINITION    YACC_INT *yys
#endif  /* !defined(Sun 4.1 lex and yacc) */
 
 
/*
 * Non-existent yacc variables : variables which are present in some
 * versions of yacc, but not in others.  This varies from machine to
 * machine.  Again, these could be optimized to only use the variable
 * required by the underlying platform.
 */
#if     defined (UMIPS_LEX_YACC) || defined(ULTRIX_LEX_YACC) || (defined(SUN_LEX_YACC) && !defined(SUN_41_LEX_YACC))
int     yystate;
int     yytmp;
int     *yyps;
YYSTYPE *yypv;
YYSTYPE *yypvt;
NIDL_YYS_DEFINITION;           /* define the yys variable globally */
#endif
 
#if     defined(SUN_LEX_YACC) && defined(SUN_41_LEX_YACC)
YYSTYPE *yypvt;
#endif
 
#if     defined(APOLLO_LEX_YACC) || defined(HPUX_LEX_YACC) || defined(SVR4_LEX_YACC)
YYSTYPE *yypvt;               /* Does not exist on Apollo */
#endif
 
/*
 * External variables defined by lex that must be saved and restored.
 *
 * Note that we should really define a save and restore routine in a
 * file similar to this one for the lex side of this code.  The current
 * method requires the lex variables to be exported, which may not be
 * the case, but seems safe to be on all current platforms.
 */
 
/* type definitions */
struct yywork {
        YYTYPE verify, advance;
};
struct yysvf {
        struct yywork *yystoff;
        struct yysvf *yyother;
        int *yystops;
};
 
/*
 * Variables for Ultrix 3.1; SunOS 4.0 and 4.1
 */
extern  int           yyleng;
extern  int           yymorfg;
extern  char          *yysptr;
extern  int           yytchar;
extern  FILE           *yyin;
extern  struct yysvf   *yyestate;
extern  struct yysvf   *yybgin;
extern  int           yylineno;
extern  char          yytext[];
extern  struct yysvf   *yylstate;
extern  struct yysvf   **yylsp;
extern  struct yysvf   **yyolsp;
extern  char          yysbuf[];
extern  char          *yysptr;
extern  int           *yyfnd;
extern  int           yyprevious;
extern  int	      yynerrs;
 
/*
** State buffer used to save and restore the lex/yacc state.  This
** file handles the allocation and de-allocation of these structures,
** and only exports an opaque pointer to identify a saved structure.
*
* Because of Bison and Flex, we have to use a completely different
* structure from AIX, HPUX, Solaris, OSF, etc.  It's mainly the
* flex stuff as we use the re-entrant version of Bison.
*/

#include "flex_state.h"
typedef struct {
#ifdef GNU_LEX_YACC
    struct FlexState	flex_State;
    int                 yynerrs;
    FILE                *yyin;
#else
    /* yacc variables */
    YYSTYPE             yylval;
    YYSTYPE             yyval;
    NIDL_YYV_DEFINITION;
    NIDL_YYS_DEFINITION;
    YYSTYPE             *yypv;
    int                 *yyps;
    YACC_INT            yystate;
    int                 yytmp;
    int                 yynerrs;
    YACC_INT            yyerrflag;
    int                 yychar;
    YYSTYPE             *yypvt;
 
    /* lex variables */
    int                 yyleng;
    int                 yymorfg;
    int                 yytchar;
    FILE                *yyin;
    struct yysvf        *yyestate;
    struct yysvf        *yybgin;
    int                 yylineno;
    char                yytext[ YYLMAX ];
    struct yysvf        *yylstate;
    struct yysvf        **yylsp;
    struct yysvf        **yyolsp;
    char                yysbuf[ YYLMAX ];
    char                *yysptr;
    int                 *yyfnd;
    int                 yyprevious;
#endif
 
}  lex_yacc_state_buffer_t;
 
 
/*
** NIDL_save_lex_yacc_state() -- save the current state so that a
** new parse can be started.  The malloc() of the save buffer could
** be optimized to take from a pool of buffers allocated in this file.
*/
lex_yacc_state_t NIDL_save_lex_yacc_state()
{
    /* Helper variables for saving and restoring the buffers and stacks. */
#ifndef GNU_LEX_YACC
    YYSTYPE     * yyv_ptr;
    YYSTYPE     * yyv_end;
    YACC_INT    * yys_ptr;
    YACC_INT    * yys_end;
    YYSTYPE     * saved_yyv_ptr;
    YACC_INT    * saved_yys_ptr;
#endif
 
    /* Buffer to save current state in */
    lex_yacc_state_buffer_t *save_state;
 
    save_state = (lex_yacc_state_buffer_t *)
        malloc(sizeof(lex_yacc_state_buffer_t));
 
    /* Start State Save Code -- yacc variables first*/
#ifdef GNU_LEX_YACC
    save_state->yynerrs   = yynerrs;
    save_state->yyin      = yyin;
    flex_SaveState (&save_state->flex_State);
#else
    save_state->yylval    = yylval;
    save_state->yyval     = yyval;
    /* yyv and yys are saved below */
    save_state->yypv      = yypv;
    save_state->yyps      = yyps;
    save_state->yystate   = yystate;
    save_state->yytmp     = yytmp;
    save_state->yynerrs   = yynerrs;
    save_state->yyerrflag = yyerrflag;
    save_state->yychar    = yychar;
    save_state->yypvt      = yypvt;
 
    /* State Save Code -- lex variables */
    save_state->yyleng    = yyleng;
    save_state->yymorfg   = yymorfg;
    /* yysbuf is saved below */
    save_state->yytchar   = yytchar;
    save_state->yyin      = yyin;
    save_state->yyestate  = yyestate;
    save_state->yybgin    = yybgin;
    save_state->yylineno  = yylineno;
    /* yytext is saved below */
    save_state->yylstate  = yylstate;
    save_state->yylsp     = yylsp;
    save_state->yyolsp    = yyolsp;
    save_state->yysptr    = yysptr;
    save_state->yyfnd     = yyfnd;
    save_state->yyprevious= yyprevious;
 
    /* Now save various stacks and text buffers. */
#if     defined(NIDL_YACC_YYV_ARRAY)
#if     defined(SVR4_LEX_YACC)
    save_state->yyv = yyv;
    save_state->yys = yys;

    yyv_end = &yy_yyv[YYMAXDEPTH-1];       /* Point at last array element */
    for (yyv_ptr = yy_yyv, saved_yyv_ptr = save_state->yy_yyv;
#else
    yyv_end = &yyv[YYMAXDEPTH-1];       /* Point at last array element */
    for (yyv_ptr = yyv, saved_yyv_ptr = save_state->yyv;
#endif /* SVR4 */
         yyv_ptr <= yyv_end;
         yyv_ptr++, saved_yyv_ptr++)
        *saved_yyv_ptr = *yyv_ptr;
#else   /* NIDL_YACC_YYV_ARRAY */
    save_state->yyv = yyv;
#endif  /* NIDL_YACC_YYV_ARRAY */
 
#if     defined(NIDL_YACC_YYS_ARRAY)
#if     defined(SVR4_LEX_YACC)
    yys_end = &yy_yys[YYMAXDEPTH-1];       /* Point at last array element */
    for (yys_ptr = yy_yys, saved_yys_ptr = save_state->yy_yys;
#else
    yys_end = &yys[YYMAXDEPTH-1];       /* Point at last array element */
    for (yys_ptr = yys, saved_yys_ptr = save_state->yys;
#endif /* SVR4 */
         yys_ptr <= yys_end;
         yys_ptr++, saved_yys_ptr++)
        *saved_yys_ptr = *yys_ptr;
#else   /* NIDL_YACC_YYS_ARRAY */
    save_state->yys = yys;
#endif  /* NIDL_YACC_YYS_ARRAY */
 
    strcpy(save_state->yysbuf, yysbuf);
    strcpy(save_state->yytext, yytext);
#endif /* GNU_LEX_YACC */
 
    return ((lex_yacc_state_t)save_state);
}
 
/*
** NIDL_restore_lex_yacc_state() -- restore the given state so that
** a parse can continue.
**
** Note that state_ptr is an opaque pointer that points to a
** lex_yacc_state_buffer_t structure.  This routine free()'s the
** structure referenced by the given pointer.
*/
void NIDL_restore_lex_yacc_state(state_ptr)
    lex_yacc_state_t state_ptr;
{
    /* Helper variables for saving and restoring the buffers and stacks. */
#ifndef GNU_LEX_YACC
    YYSTYPE     * yyv_ptr;
    YYSTYPE     * yyv_end;
    YACC_INT    * yys_ptr;
    YACC_INT    * yys_end;
    YYSTYPE     * saved_yyv_ptr;
    YACC_INT    * saved_yys_ptr;
#endif
 
    lex_yacc_state_buffer_t *saved_state;
 
    saved_state = (lex_yacc_state_buffer_t *) state_ptr;
 
    /* Restore yacc variables */
#ifdef GNU_LEX_YACC
    yynerrs	= saved_state->yynerrs;
    yyin	= saved_state->yyin;
    flex_RestoreState (&saved_state->flex_State);
#else
    yylval      = saved_state->yylval;
    yyval       = saved_state->yyval;
    /* yyv and yys are restored below */
    yypv        = saved_state->yypv;
    yyps        = saved_state->yyps;
    yystate     = saved_state->yystate;
    yytmp       = saved_state->yytmp;
    yynerrs     = saved_state->yynerrs + yynerrs;
    yyerrflag   = saved_state->yyerrflag;
    yychar      = saved_state->yychar;
    yypvt        = saved_state->yypvt;
 
    /* Restore lex variables */
    yyleng      = saved_state->yyleng;
    yymorfg     = saved_state->yymorfg;
    /* yysbuf is restored below */
    yytchar     = saved_state->yytchar;
    yyin        = saved_state->yyin;
    yyestate    = saved_state->yyestate;
    yybgin      = saved_state->yybgin;
    yylineno    = saved_state->yylineno;
    /* yytext is restored below */
    yylstate    = saved_state->yylstate;
    yylsp       = saved_state->yylsp;
    yyolsp      = saved_state->yyolsp;
    yysptr      = saved_state->yysptr;
    yyfnd       = saved_state->yyfnd;
    yyprevious  = saved_state->yyprevious;
 
    /* restore the various stacks and text buffers. */
#if     defined(NIDL_YACC_YYV_ARRAY)
#if     defined(SVR4_LEX_YACC)
    yys = saved_state->yys;
    yyv = saved_state->yyv;

    yyv_end = &yy_yyv[YYMAXDEPTH-1];       /* Point at last array element */
    for (yyv_ptr = yy_yyv, saved_yyv_ptr = saved_state->yy_yyv;
#else
    yyv_end = &yyv[YYMAXDEPTH-1];       /* Point at last array element */
    for (yyv_ptr = yyv, saved_yyv_ptr = saved_state->yyv;
#endif  /* SVR4 */
         yyv_ptr <= yyv_end;
         yyv_ptr++, saved_yyv_ptr++)
        *yyv_ptr = *saved_yyv_ptr;
#else   /* NIDL_YACC_YYV_ARRAY */
    yyv = saved_state->yyv;
#endif  /* NIDL_YACC_YYV_ARRAY */
 
#if     defined(NIDL_YACC_YYS_ARRAY)
#if     defined(SVR4_LEX_YACC)
    yys_end = &yy_yys[YYMAXDEPTH-1];       /* Point at last array element */
    for (yys_ptr = yy_yys, saved_yys_ptr = saved_state->yy_yys;
#else
    yys_end = &yys[YYMAXDEPTH-1];       /* Point at last array element */
    for (yys_ptr = yys, saved_yys_ptr = saved_state->yys;
#endif  /* SVR4 */
         yys_ptr <= yys_end;
         yys_ptr++, saved_yys_ptr++)
        *yys_ptr = *saved_yys_ptr;
#else   /* NIDL_YACC_YYS_ARRAY */
    yys = saved_state->yys;
#endif  /* NIDL_YACC_YYS_ARRAY */
 
    strcpy(yysbuf, saved_state->yysbuf);
    strcpy(yytext, saved_state->yytext);
#endif  /* GNU_LEX_YACC */
 
    free((char *)saved_state);
 
    return;
}
