nidl_y.y   [plain text]


%{
/*
 * Copyright (c) 2010 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Portions of this software have been released under the following terms:
 *
 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
 * (c) Copyright 1989-1993 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.
 *
 * Copyright (c) 2007, Novell, Inc. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Novell Inc. nor the names of its contributors
 *     may be used to endorse or promote products derived from this
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @APPLE_LICENSE_HEADER_END@
 */

/*
**
**  NAME:
**
**      IDL.Y
**
**  FACILITY:
**
**      Interface Definition Language (IDL) Compiler
**
**  ABSTRACT:
**
**      This module defines the main IDL grammar accepted
**      by the IDL compiler.
**
**  VERSION: DCE 1.0
**
*/

#include <sys/types.h>

#include <nidl.h>
#include <nametbl.h>
#include <errors.h>
#include <ast.h>
#include <astp.h>
#include <frontend.h>

#define YYDEBUG 1

extern boolean search_attributes_table ;

/*
**  Local cells used for inter-production communication
*/
static ASTP_attr_k_t       ASTP_bound_type;    /* Array bound attribute */

/* An opaque pointer. */
#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif

typedef struct nidl_parser_state_t
{
   yyscan_t     nidl_yyscanner;
   unsigned     nidl_yynerrs;
   parser_location_t nidl_location;
} nidl_parser_state_t;

static void nidl_yyerror (YYLTYPE *, nidl_parser_p, char const *);

%}

%locations
%defines
%error-verbose
%pure-parser
%name-prefix="nidl_yy"

/* Tell Bison that the Flexer takes a yyscan_t parameter. */
%lex-param { void * lexxer }
/* Tell Bison that we will pass the yyscan_t scanner into yyparse. */
%parse-param { nidl_parser_state_t * nidl }

/* Tell Bison how to get the lexxer argument from the parser state. */
%{
#define lexxer nidl->nidl_yyscanner
%}

        /*   Declaration of yylval, yyval                   */
%union
{
	 NAMETABLE_id_t         y_id ;          /* Identifier           */
	 long                   y_ptrlevels;	/* levels of * for pointers */
	 long					y_ptrclass;		/* class of pointer */
	 STRTAB_str_t           y_string ;      /* String               */
	 STRTAB_str_t           y_float ;       /* Float constant       */
	 AST_export_n_t*        y_export ;      /* an export node       */
	 AST_import_n_t*        y_import ;      /* Import node          */
	 AST_exception_n_t*     y_exception ;   /* Exception node       */
	 AST_constant_n_t*      y_constant;     /* Constant node        */
	 AST_parameter_n_t*     y_parameter ;   /* Parameter node       */
	 AST_type_n_t*          y_type ;        /* Type node            */
	 AST_type_p_n_t*        y_type_ptr ;    /* Type pointer node    */
	 AST_field_n_t*         y_field ;       /* Field node           */
	 AST_arm_n_t*           y_arm ;         /* Union variant arm    */
	 AST_operation_n_t*     y_operation ;   /* Routine node         */
	 AST_interface_n_t*     y_interface ;   /* Interface node       */
	 AST_case_label_n_t*    y_label ;       /* Union tags           */
	 ASTP_declarator_n_t*   y_declarator ;  /* Declarator info      */
	 ASTP_array_index_n_t*  y_index ;       /* Array index info     */
	 nidl_uuid_t            y_uuid ;        /* Universal UID        */
	 char                   y_char;         /* character constant   */
	 ASTP_attributes_t      y_attributes;   /* attributes flags     */

     	 AST_cpp_quote_n_t*     y_cpp_quote;    /* Quoted C within interface treated as one 'kind' of export node + quote outside interfaces */

	 struct {
		  long            int_val ;        /* Integer constant     */
		  AST_type_k_t    int_size;
		  int             int_signed;
	 }                  y_int_info;     /* int size and signedness */
	 AST_exp_n_t           * y_exp;          /* constant expression info */
}

%{
#include <nidl_l.h>
%}

/********************************************************************/
/*                                                                  */
/*          Tokens used by the IDL parser.                          */
/*                                                                  */
/********************************************************************/

/* Keywords                 */
%token ALIGN_KW
%token BYTE_KW
%token CHAR_KW
%token CONST_KW
%token DEFAULT_KW
%token ENUM_KW
%token EXCEPTIONS_KW
%token FLOAT_KW
%token HYPER_KW
%token INT_KW
%token INTERFACE_KW
%token IMPORT_KW
%token LIBRARY_KW
%token LONG_KW
%token PIPE_KW
%token REF_KW
%token SMALL_KW
%token STRUCT_KW
%token TYPEDEF_KW
%token UNION_KW
%token UNSIGNED_KW
%token SHORT_KW
%token VOID_KW
%token DOUBLE_KW
%token BOOLEAN_KW
%token CASE_KW
%token SWITCH_KW
%token HANDLE_T_KW
%token TRUE_KW
%token FALSE_KW
%token NULL_KW
%token BROADCAST_KW
%token COMM_STATUS_KW
%token CONTEXT_HANDLE_KW
%token FIRST_IS_KW
%token HANDLE_KW
%token IDEMPOTENT_KW
%token IGNORE_KW
%token CALL_AS_KW
%token IID_IS_KW
%token IMPLICIT_HANDLE_KW
%token IN_KW
%token LAST_IS_KW
%token LENGTH_IS_KW
%token LOCAL_KW
%token MAX_IS_KW
%token MAYBE_KW
%token MIN_IS_KW
%token MUTABLE_KW
%token OUT_KW
%token OBJECT_KW
%token POINTER_DEFAULT_KW
%token ENDPOINT_KW
%token PTR_KW
%token RANGE_KW
%token REFLECT_DELETIONS_KW
%token REMOTE_KW
%token SECURE_KW
%token SHAPE_KW
%token SIZE_IS_KW
%token STRING_KW
%token SWITCH_IS_KW
%token SWITCH_TYPE_KW
%token TRANSMIT_AS_KW
%token UNIQUE_KW
%token UUID_KW
%token VERSION_KW
%token V1_ARRAY_KW
%token V1_STRING_KW
%token V1_ENUM_KW
%token V1_STRUCT_KW

/* Added by Centeris */

%token CPP_QUOTE_KW

/*  Non-keyword tokens      */

%token UUID_REP

/*  Punctuation             */

%token COLON
%token COMMA
%token DOTDOT
%token EQUAL
%token LBRACE
%token LBRACKET
%token LPAREN
%token RBRACE
%token RBRACKET
%token RPAREN
%token SEMI
%token STAR
%token QUESTION
%token BAR
%token BARBAR
%token LANGLE
%token LANGLEANGLE
%token RANGLE
%token RANGLEANGLE
%token AMP
%token AMPAMP
%token LESSEQUAL
%token GREATEREQUAL
%token EQUALEQUAL
%token CARET
%token PLUS
%token MINUS
%token NOT
%token NOTEQUAL
%token SLASH
%token PERCENT
%token TILDE
%token POUND
%token UNKNOWN  /* Something that doesn't fit in any other token class */

/*  Tokens setting yylval   */

%token <y_id>      		IDENTIFIER
%token <y_string>  		STRING
%token <y_int_info>		INTEGER_NUMERIC
%token <y_char>			CHAR
%token <y_float>		FLOAT_NUMERIC
%start grammar_start

%%

/********************************************************************/
/*                                                                  */
/*          Syntax description and actions for IDL                  */
/*                                                                  */
/********************************************************************/

grammar_start:     	interfaces cpp_quotes
			{
				global_cppquotes_post = (AST_cpp_quote_n_t*)AST_concat_element(
					(ASTP_node_t*)global_cppquotes_post, (ASTP_node_t*)$<y_cpp_quote>2);
			}
			|
			optional_imports_cppquotes
			|
        		{
            			$<y_import>$ = (AST_import_n_t *)NULL;
		        }

			/*{
#if 0
	 			global_imports = (AST_import_n_t*)AST_concat_element(
	 				 (ASTP_node_t*)global_imports, (ASTP_node_t*)$<y_import>1);
#endif
				global_cppquotes_post = (AST_cpp_quote_n_t*)AST_concat_element(
					(ASTP_node_t*)global_cppquotes_post, (ASTP_node_t*)$<y_cpp_quote>2);
			}*/
		;

interfaces:
	interfaces interface_plus
	|
	interface_plus
	;

/*Centeris wfu*/
cpp_quotes:
	cpp_quote cpp_quotes
	{
		$<y_cpp_quote>$ = (AST_cpp_quote_n_t *) AST_concat_element(
                                                (ASTP_node_t *) $<y_cpp_quote>1,
                                                (ASTP_node_t *) $<y_cpp_quote>2);
        }
	| /*Nothing*/
	{	$<y_cpp_quote>$ = (AST_cpp_quote_n_t *)NULL;
	}
	;

interface_plus:
	cpp_quotes interface
	{
		global_cppquotes = (AST_cpp_quote_n_t*)AST_concat_element(
			(ASTP_node_t*)global_cppquotes, (ASTP_node_t*)$<y_cpp_quote>1);
	}
	;

interface:
        interface_init interface_start interface_ancestor interface_tail
        {
            AST_finish_interface_node(nidl_location(nidl), the_interface);
        }
	;

interface_start:
        interface_attributes INTERFACE_KW IDENTIFIER
        {
	    AST_type_n_t * interface_type =
          AST_type_node(nidl_location(nidl), AST_interface_k);
	    interface_type->type_structure.interface = the_interface;
	    interface_type->name = $<y_id>3;
            the_interface->name = $<y_id>3;
            ASTP_add_name_binding (nidl_location(nidl), the_interface->name, interface_type);
        }
    ;

interface_ancestor:
	/* Nothing */
	{
		 the_interface->inherited_interface_name = NAMETABLE_NIL_ID;
	}
	 | COLON IDENTIFIER
	{
		 the_interface->inherited_interface_name = $<y_id>2;
	}
	;

interface_init:
        /* Always create the interface node and auto-import the system idl */
        {
            STRTAB_str_t nidl_idl_str;
            nidl_idl_str = STRTAB_add_string (AUTO_IMPORT_FILE);
            AST_interface_n_t* old = the_interface;

	         the_interface = AST_interface_node(nidl_location(nidl));
            the_interface->prev = old;
	         the_interface->exports = NULL;
            the_interface->imports =
               AST_import_node(nidl_location(nidl), nidl_idl_str);
            the_interface->imports->interface = FE_parse_import (nidl_idl_str);
            if (the_interface->imports->interface != NULL)
            {
                AST_CLR_OUT_OF_LINE(the_interface->imports->interface);
                AST_SET_IN_LINE(the_interface->imports->interface);
            }
        }
    ;

interface_tail:
        LBRACE interface_body RBRACE
        { $<y_interface>$ = $<y_interface>2; }
    |   error
        {
            $<y_interface>$ = NULL;
            log_error(nidl_yylineno(nidl),NIDL_MISSONINTER, NULL);
        }
    |   error RBRACE
        {
            $<y_interface>$ = NULL;
        }
    ;

interface_body:
        optional_imports exports extraneous_semi
        {
            /* May already be an import of nbase, so concat */
            the_interface->imports = (AST_import_n_t *) AST_concat_element(
                                        (ASTP_node_t *) the_interface->imports,
                                        (ASTP_node_t *) $<y_import>1);
            the_interface->exports = (AST_export_n_t*)AST_concat_element(
			(ASTP_node_t*)the_interface->exports,
			(ASTP_node_t*)$<y_export>2);
        }
  ;

optional_imports:
        imports
    |   /* Nothing */
        {
            $<y_import>$ = (AST_import_n_t *)NULL;
        }
    ;

optional_imports_cppquotes:
        imports cpp_quotes
	{
#if 0
	 			global_imports = (AST_import_n_t*)AST_concat_element(
	 				 (ASTP_node_t*)global_imports, (ASTP_node_t*)$<y_import>1);
#endif

				global_cppquotes_post = (AST_cpp_quote_n_t*)AST_concat_element(
					(ASTP_node_t*)global_cppquotes_post, (ASTP_node_t*)$<y_cpp_quote>2);
	}

    ;

imports:
        import
    |   imports import
        {
                $<y_import>$ = (AST_import_n_t *) AST_concat_element(
                                                (ASTP_node_t *) $<y_import>1,
                                                (ASTP_node_t *) $<y_import>2);
        }
    ;

import:
        IMPORT_KW error
        {
            $<y_import>$ = (AST_import_n_t *)NULL;
        }
    |   IMPORT_KW error SEMI
        {
            $<y_import>$ = (AST_import_n_t *)NULL;
        }
    |   IMPORT_KW import_files SEMI
        {
            $<y_import>$ = $<y_import>2;
        }
    ;

import_files:
        import_file
    |   import_files COMMA import_file
        {
                $<y_import>$ = (AST_import_n_t *) AST_concat_element(
                                                (ASTP_node_t *) $<y_import>1,
                                                (ASTP_node_t *) $<y_import>3);
        }
    ;

import_file:
        STRING
        {
            AST_interface_n_t  *int_p;
            int_p = FE_parse_import ($<y_string>1);
            if (int_p != (AST_interface_n_t *)NULL)
            {
                $<y_import>$ = AST_import_node(nidl_location(nidl), $<y_string>1);
                $<y_import>$->interface = int_p;
            }
            else
                $<y_import>$ = (AST_import_n_t *)NULL;
        }
    ;

exports:
        export
    |   exports extraneous_semi export
        {
                $<y_export>$ = (AST_export_n_t *) AST_concat_element(
                                            (ASTP_node_t *) $<y_export>1,
                                            (ASTP_node_t *) $<y_export>3) ;
        }
    ;

export:
        type_dcl      SEMI
        {
                $<y_export>$ = AST_types_to_exports (nidl_location(nidl),
                                             $<y_type_ptr>1);
        }
    |   const_dcl     SEMI
        {
                $<y_export>$ = AST_export_node (
                        nidl_location(nidl),
                        (ASTP_node_t *) $<y_constant>1, AST_constant_k);
        }
    |   operation_dcl SEMI
        {
            if (ASTP_parsing_main_idl)
                $<y_export>$ = AST_export_node (
                        nidl_location(nidl),
                        (ASTP_node_t *) $<y_operation>1, AST_operation_k);
        }
    |   cpp_quote
        {
            $<y_export>$ = AST_export_node (
                     nidl_location(nidl),
                (ASTP_node_t *) $<y_cpp_quote>1, AST_cpp_quote_k);
        }
    |   error SEMI
        {
            $<y_export>$ = (AST_export_n_t *)NULL;
        }
    ;

cpp_quote:
        CPP_QUOTE_KW LPAREN STRING RPAREN
        {
            $<y_cpp_quote>$ =
               AST_cpp_quote_node(nidl_location(nidl), $<y_string>3);

        }
	;

const_dcl:
        CONST_KW type_spec declarator EQUAL const_exp

        {
           $<y_constant>$ = AST_finish_constant_node (nidl_location(nidl),
                     $<y_constant>5, $<y_declarator>3, $<y_type>2);
        }
    ;

const_exp:  expression
        {
				$<y_constant>$ = AST_constant_from_exp(nidl_location(nidl),
                                    $<y_exp>1);
				if ($<y_constant>$ == NULL)	{
					 log_error(nidl_yylineno(nidl), NIDL_EXPNOTCONST, NULL);
				}
        }
    ;

type_dcl:
        TYPEDEF_KW type_declarator
        {
            $<y_type_ptr>$ = $<y_type_ptr>2;
        }
    ;

type_declarator:
        attributes type_spec declarators extraneous_comma
        {
            $<y_type_ptr>$  = AST_declarators_to_types(nidl_location(nidl),
                  the_interface, $<y_type>2, $<y_declarator>3, &$<y_attributes>1) ;
            ASTP_free_simple_list((ASTP_node_t *)$<y_attributes>1.bounds);
        }
    ;

type_spec:
        simple_type_spec
    |   constructed_type_spec
    ;

simple_type_spec:
        floating_point_type_spec
    |   integer_type_spec
    |   char_type_spec
    |   boolean_type_spec
    |   byte_type_spec
    |   void_type_spec
    |   named_type_spec
    |   handle_type_spec
    ;

constructed_type_spec:
        struct_type_spec
    |   union_type_spec
    |   enum_type_spec
    |   pipe_type_spec
    ;

named_type_spec:
        IDENTIFIER
        {
            $<y_type>$ = AST_lookup_named_type(nidl_location(nidl), $<y_id>1);
        }
    ;

floating_point_type_spec:
        FLOAT_KW
        {
            $<y_type>$ = AST_lookup_type_node(AST_short_float_k);
        }
    |   DOUBLE_KW
        {
            $<y_type>$ = AST_lookup_type_node(AST_long_float_k);
        }
    ;

extraneous_comma:
        /* Nothing */
    |   COMMA
        { log_warning(nidl_yylineno(nidl), NIDL_EXTRAPUNCT, ",", NULL);}
    ;

extraneous_semi:
        /* Nothing */
    |   SEMI
        { log_warning(nidl_yylineno(nidl), NIDL_EXTRAPUNCT, ";", NULL);}
    ;

optional_unsigned_kw:
        UNSIGNED_KW     { $<y_int_info>$.int_signed = false; }
    |   /* Nothing */   { $<y_int_info>$.int_signed = true; }
    ;

integer_size_spec:
        SMALL_KW
        {
            $<y_int_info>$.int_size = AST_small_integer_k;
            $<y_int_info>$.int_signed = true;
        }
    |   SHORT_KW
        {
            $<y_int_info>$.int_size = AST_short_integer_k;
            $<y_int_info>$.int_signed = true;
        }
    |   LONG_KW
        {
            $<y_int_info>$.int_size = AST_long_integer_k;
            $<y_int_info>$.int_signed = true;
        }
    |   HYPER_KW
        {
            $<y_int_info>$.int_size = AST_hyper_integer_k;
            $<y_int_info>$.int_signed = true;
        }
    ;

integer_modifiers:
        integer_size_spec
        { $<y_int_info>$ = $<y_int_info>1; }
    |   UNSIGNED_KW integer_size_spec
        {
            $<y_int_info>$.int_size = $<y_int_info>2.int_size;
            $<y_int_info>$.int_signed = false;
        }
    |   integer_size_spec UNSIGNED_KW
        {
            $<y_int_info>$.int_size = $<y_int_info>1.int_size;
            $<y_int_info>$.int_signed = false;
        }
    ;

integer_type_spec:
        integer_modifiers
        { $<y_type>$ = AST_lookup_integer_type_node($<y_int_info>1.int_size,$<y_int_info>1.int_signed); }
    |   integer_modifiers INT_KW
        { $<y_type>$ = AST_lookup_integer_type_node($<y_int_info>1.int_size,$<y_int_info>1.int_signed); }
    |   optional_unsigned_kw INT_KW
        {
            log_warning(nidl_yylineno(nidl),NIDL_INTSIZEREQ, NULL);
            $<y_type>$ = AST_lookup_integer_type_node(AST_long_integer_k,$<y_int_info>1.int_signed);
        }
    ;

char_type_spec:
        optional_unsigned_kw CHAR_KW
        { $<y_type>$ = AST_lookup_type_node(AST_character_k); }
    ;

boolean_type_spec:
        BOOLEAN_KW
        { $<y_type>$ = AST_lookup_type_node(AST_boolean_k); }
    ;

byte_type_spec:
        BYTE_KW
        { $<y_type>$ = AST_lookup_type_node(AST_byte_k); }
    ;

void_type_spec:
        VOID_KW
        { $<y_type>$ = AST_lookup_type_node(AST_void_k); }
    ;

handle_type_spec:
       HANDLE_T_KW
        { $<y_type>$ = AST_lookup_type_node(AST_handle_k); }
    ;

push_name_space:
        LBRACE
        {
            NAMETABLE_push_level ();
        }
    ;

pop_name_space:
        RBRACE
        {
            ASTP_patch_field_reference (nidl_location(nidl));
            NAMETABLE_pop_level ();
        }
    ;

union_type_spec:
        UNION_KW ne_union_body
        {
        $<y_type>$ = AST_disc_union_node(
                         nidl_location(nidl),
                         NAMETABLE_NIL_ID,      /* tag name          */
                         NAMETABLE_NIL_ID,      /* union name        */
                         NAMETABLE_NIL_ID,      /* discriminant name */
                         NULL,                  /* discriminant type */
                         $<y_arm>2 );           /* the arm list      */
        }
    |
        UNION_KW SWITCH_KW LPAREN simple_type_spec IDENTIFIER RPAREN union_body
        {
        $<y_type>$ = AST_disc_union_node(
                         nidl_location(nidl),
                         NAMETABLE_NIL_ID,      /* tag name          */
                         ASTP_tagged_union_id,  /* union name        */
                         $<y_id>5,              /* discriminant name */
                         $<y_type>4,            /* discriminant type */
                         $<y_arm>7 );           /* the arm list      */
        }
    |   UNION_KW IDENTIFIER ne_union_body
        {
        $<y_type>$ = AST_disc_union_node(
                         nidl_location(nidl),
                         $<y_id>2,              /* tag name          */
                         NAMETABLE_NIL_ID,      /* union name        */
                         NAMETABLE_NIL_ID,      /* discriminant name */
                         NULL,                  /* discriminant type */
                         $<y_arm>3 );           /* the arm list      */
        }
    |   UNION_KW SWITCH_KW LPAREN simple_type_spec IDENTIFIER RPAREN IDENTIFIER union_body
        {
        $<y_type>$ = AST_disc_union_node(
                         nidl_location(nidl),
                         NAMETABLE_NIL_ID,      /* tag name          */
                         $<y_id>7,              /* union name        */
                         $<y_id>5,              /* discriminant name */
                         $<y_type>4,            /* discriminant type */
                         $<y_arm>8 );           /* the arm list      */
        }
    |   UNION_KW IDENTIFIER SWITCH_KW LPAREN simple_type_spec IDENTIFIER RPAREN union_body
        {
        $<y_type>$ = AST_disc_union_node(
                         nidl_location(nidl),
                         $<y_id>2,              /* tag name          */
                         ASTP_tagged_union_id,  /* union name        */
                         $<y_id>6,              /* discriminant name */
                         $<y_type>5,            /* discriminant type */
                         $<y_arm>8 );           /* the arm list      */
        }
    |   UNION_KW IDENTIFIER SWITCH_KW LPAREN simple_type_spec IDENTIFIER RPAREN IDENTIFIER union_body
        {
        $<y_type>$ = AST_disc_union_node(
                         nidl_location(nidl),
                         $<y_id>2,              /* tag name          */
                         $<y_id>8,              /* union name        */
                         $<y_id>6,              /* discriminant name */
                         $<y_type>5,            /* discriminant type */
                         $<y_arm>9 );           /* the arm list      */
        }
    |   UNION_KW IDENTIFIER
        {
            $<y_type>$ = AST_type_from_tag (nidl_location(nidl),
                              AST_disc_union_k, $<y_id>2);
        }
    ;

ne_union_body:
        push_name_space ne_union_cases pop_name_space
        {
                $<y_arm>$ = $<y_arm>2;
        }
    ;
union_body:
        push_name_space union_cases pop_name_space
        {
                $<y_arm>$ = $<y_arm>2;
        }
    ;

ne_union_cases:
        ne_union_case
    |   ne_union_cases extraneous_semi ne_union_case
        {
            $<y_arm>$ = (AST_arm_n_t *) AST_concat_element(
                                        (ASTP_node_t *) $<y_arm>1,
                                        (ASTP_node_t *) $<y_arm>3);
        }
    ;
union_cases:
        union_case
    |   union_cases extraneous_semi union_case
        {
            $<y_arm>$ = (AST_arm_n_t *) AST_concat_element(
                                        (ASTP_node_t *) $<y_arm>1,
                                        (ASTP_node_t *) $<y_arm>3);
        }
    ;

ne_union_case:
        ne_union_member
        {
            $<y_arm>$ = $<y_arm>1;
        }
    ;
union_case:
        union_case_list union_member
        {
            $<y_arm>$ = AST_label_arm($<y_arm>2, $<y_label>1) ;
        }
    ;

ne_union_case_list:
        ne_union_case_label
    |   ne_union_case_list COMMA ne_union_case_label
        {
            $<y_label>$ = (AST_case_label_n_t *) AST_concat_element(
                                        (ASTP_node_t *) $<y_label>1,
                                        (ASTP_node_t *) $<y_label>3);
        }
    ;
union_case_list:
        union_case_label
    |   union_case_list union_case_label
        {
            $<y_label>$ = (AST_case_label_n_t *) AST_concat_element(
                                        (ASTP_node_t *) $<y_label>1,
                                        (ASTP_node_t *) $<y_label>2);
        }
    ;

ne_union_case_label:
        const_exp
        {
            $<y_label>$ = AST_case_label_node(
                              nidl_location(nidl), $<y_constant>1);
        }
    ;
union_case_label:
        CASE_KW const_exp COLON
        {
            $<y_label>$ = AST_case_label_node(
                              nidl_location(nidl), $<y_constant>2);
        }
    |   DEFAULT_KW COLON
        {
            $<y_label>$ = AST_default_case_label_node(
                              nidl_location(nidl));
        }
    ;

ne_union_member:
        attribute_opener rest_of_attribute_list SEMI
        {
            $<y_arm>$ = AST_declarator_to_arm(nidl_location(nidl),
                  NULL, NULL, &$<y_attributes>2);
            ASTP_free_simple_list((ASTP_node_t *)$<y_attributes>2.bounds);
        }
    |   attribute_opener rest_of_attribute_list type_spec declarator SEMI
        {
            $<y_arm>$ = AST_declarator_to_arm(nidl_location(nidl),
                  $<y_type>3, $<y_declarator>4, &$<y_attributes>2);
            ASTP_free_simple_list((ASTP_node_t *)$<y_attributes>2.bounds);
        }
    ;
union_member:
        /* nothing */ SEMI
        {
            $<y_arm>$ = AST_arm_node(nidl_location(nidl),
                              NAMETABLE_NIL_ID,NULL,NULL);
        }
    |   attributes type_spec declarator SEMI
        {
            if (ASTP_TEST_ATTR(&$<y_attributes>1, ASTP_CASE))
            {
                ASTP_attr_flag_t attr1 = ASTP_CASE;
                log_error(nidl_yylineno(nidl), NIDL_EUMEMATTR,
                      KEYWORDS_lookup_text(AST_attribute_to_token(&attr1)),
		      NULL);
            }
            if (ASTP_TEST_ATTR(&$<y_attributes>1, ASTP_DEFAULT))
            {
                ASTP_attr_flag_t attr1 = ASTP_DEFAULT;
                log_error(nidl_yylineno(nidl), NIDL_EUMEMATTR,
                      KEYWORDS_lookup_text(AST_attribute_to_token(&attr1)),
		      NULL);
            }
            $<y_arm>$ = AST_declarator_to_arm(nidl_location(nidl),
                  $<y_type>2, $<y_declarator>3, &$<y_attributes>1);
            ASTP_free_simple_list((ASTP_node_t *)$<y_attributes>1.bounds);
        }
    ;

struct_type_spec:
        STRUCT_KW push_name_space member_list pop_name_space
        {
            $<y_type>$ = AST_structure_node(nidl_location(nidl),
                           $<y_field>3, NAMETABLE_NIL_ID) ;
        }
    |   STRUCT_KW IDENTIFIER push_name_space member_list pop_name_space
        {
            $<y_type>$ = AST_structure_node(nidl_location(nidl),
                           $<y_field>4, $<y_id>2) ;
        }
    |   STRUCT_KW IDENTIFIER
        {
            $<y_type>$ = AST_type_from_tag (nidl_location(nidl),
                              AST_structure_k, $<y_id>2);
        }
    ;

member_list:
        member
    |   member_list extraneous_semi member
        {
            $<y_field>$ = (AST_field_n_t *)AST_concat_element(
                                    (ASTP_node_t *) $<y_field>1,
                                    (ASTP_node_t *) $<y_field>3) ;
        }
    ;

member:
        attributes type_spec old_attribute_syntax declarators SEMI
        {
            $<y_field>$ = AST_declarators_to_fields(nidl_location(nidl),
                                                    $<y_declarator>4,
                                                    $<y_type>2,
                                                    &$<y_attributes>1);
            ASTP_free_simple_list((ASTP_node_t *)$<y_attributes>1.bounds);
        }
    ;

enum_type_spec:
        ENUM_KW optional_tag enum_body
        {
             $<y_type>$ = AST_enumerator_node(nidl_location(nidl),
                              $<y_constant>3, AST_short_integer_k);
        }
    ;

optional_tag:
	IDENTIFIER
		{
		}
	| /* Nothing */
	;

enum_body:
        LBRACE enum_ids extraneous_comma RBRACE
        {
            $<y_constant>$ = $<y_constant>2 ;
        }
    ;

enum_ids:
        enum_id
    |   enum_ids COMMA enum_id
        {
            $<y_constant>$ = (AST_constant_n_t *) AST_concat_element(
                                    (ASTP_node_t *) $<y_constant>1,
                                    (ASTP_node_t *) $<y_constant>3) ;
        }
    ;

enum_id:
        IDENTIFIER optional_value
        {
            $<y_constant>$ = AST_enum_constant(nidl_location(nidl),
                              $<y_id>1, $<y_exp>2) ;
        }
    ;

pipe_type_spec:
        PIPE_KW type_spec
        {
            $<y_type>$ = AST_pipe_node (nidl_location(nidl), $<y_type>2);
        }
    ;

optional_value:
	/* Nothing */
		{
			 $<y_exp>$ = AST_exp_integer_constant(nidl_location(nidl),
                                 0, true);
		}
	| EQUAL expression
		{
          ASTP_validate_integer(nidl_location(nidl), $<y_exp>2);
			 $<y_exp>$ = $<y_exp>2;
		}
	;

declarators:
        declarator
		  {
				$<y_declarator>$ =  $<y_declarator>1;
		  }
    |   declarators COMMA declarator
        {
            $<y_declarator>$ = (ASTP_declarator_n_t *) AST_concat_element(
                                            (ASTP_node_t *) $<y_declarator>1,
                                            (ASTP_node_t *) $<y_declarator>3) ;
        }
    ;

declarator:
	declarator1
		{ $<y_declarator>$ = $<y_declarator>1; }
		;

declarator1:
        direct_declarator
            { $<y_declarator>$ = $<y_declarator>1; }
       |    pointer direct_declarator
            {
                $<y_declarator>$ = $<y_declarator>2;
                AST_declarator_operation($<y_declarator>$, AST_pointer_k,
                        (ASTP_node_t *)NULL, $<y_ptrlevels>1 );
            };

pointer :
            STAR
            { $<y_ptrlevels>$ = 1;}
       |    STAR pointer
            { $<y_ptrlevels>$ = $<y_ptrlevels>2 + 1; };

direct_declarator:
            IDENTIFIER
            { $<y_declarator>$ = AST_declarator_node ( $<y_id>1 ); }
       |        direct_declarator array_bounds
            {
                $<y_declarator>$ = $<y_declarator>$;
                AST_declarator_operation($<y_declarator>$, AST_array_k,
                        (ASTP_node_t *) $<y_index>2, 0 );
            }
       |   LPAREN declarator RPAREN
            {
            $<y_declarator>$ = $<y_declarator>2;
            }
       |        direct_declarator parameter_dcls
            {
                $<y_declarator>$ = $<y_declarator>$;
                AST_declarator_operation($<y_declarator>$, AST_function_k,
                        (ASTP_node_t *) $<y_parameter>2, 0 );
            }
       ;

    /*
     * The following productions use an AST routine with the signature:
     *
     *   ASTP_array_index_node( AST_constant_n_t * lower_bound,
     *                          ASTP_bound_t lower_bound_type,
     *                          AST_constant_n_t * upper_bound,
     *                          ASTP_bound_t upper_bound_type);
     *
     * The type ASTP_bound_t is defined as:
     *
     *   typedef enum {ASTP_constant_bound,
     *                 ASTP_default_bound,
     *                 ASTP_open_bound} ASTP_bound_t;
     *
     * The bound value passed is only used if the associated bound type is
     * ASTP_constant_bound.
     */

array_bounds:
        LBRACKET RBRACKET
        {
            $<y_index>$ = ASTP_array_index_node (nidl_location(nidl),
                                                 NULL, ASTP_default_bound,
                                                 NULL, ASTP_open_bound);
        }
    |   LBRACKET STAR RBRACKET
        {
            $<y_index>$ = ASTP_array_index_node  (nidl_location(nidl),
                                                 NULL, ASTP_default_bound,
                                                 NULL, ASTP_open_bound);
        }
    |   LBRACKET const_exp RBRACKET
        {
            $<y_index>$ = ASTP_array_index_node  (nidl_location(nidl),
                                                 NULL, ASTP_default_bound,
                                                 $<y_constant>2, ASTP_constant_bound);
        }
    |   LBRACKET STAR DOTDOT STAR RBRACKET
        {
            $<y_index>$ = ASTP_array_index_node  (nidl_location(nidl),
                                                 NULL, ASTP_open_bound,
                                                 NULL, ASTP_open_bound);
        }
    |   LBRACKET STAR DOTDOT const_exp RBRACKET
        {
            $<y_index>$ = ASTP_array_index_node  (nidl_location(nidl),
                                                 NULL, ASTP_open_bound,
                                                 $<y_constant>4,
                                                 ASTP_constant_bound);
        }
    |   LBRACKET const_exp DOTDOT STAR RBRACKET
        {
            $<y_index>$ = ASTP_array_index_node  (nidl_location(nidl),
                                                 $<y_constant>2,
                                                 ASTP_constant_bound,
                                                 NULL, ASTP_open_bound);
        }
    |   LBRACKET const_exp DOTDOT const_exp RBRACKET
        {
            $<y_index>$ = ASTP_array_index_node  (nidl_location(nidl),
                                                 $<y_constant>2, ASTP_constant_bound,
                                                 $<y_constant>4, ASTP_constant_bound);
        }
    ;

operation_dcl:
        attributes type_spec declarators extraneous_comma
        {
            if (ASTP_parsing_main_idl)
                $<y_operation>$ = AST_operation_node (
                                    nidl_location(nidl),
                                    $<y_type>2,         /*The type node*/
                                    $<y_declarator>3,   /* Declarator list */
                                   &$<y_attributes>1);  /* attributes */
            ASTP_free_simple_list((ASTP_node_t *)$<y_attributes>1.bounds);
        }
    | error declarators
        {
        log_error(nidl_yylineno(nidl),NIDL_MISSONOP, NULL);
        $<y_operation>$ = NULL;
        }
    ;

parameter_dcls:
        param_names param_list extraneous_comma end_param_names
        {
            $<y_parameter>$ = $<y_parameter>2;
        }
    ;

param_names:
        LPAREN
        {
        NAMETABLE_push_level ();
        }
    ;

end_param_names:
        RPAREN
        {
        ASTP_patch_field_reference (nidl_location(nidl));
        NAMETABLE_pop_level ();
        }
    ;

param_list:
        param_dcl
    |   param_list COMMA param_dcl
        {
            if (ASTP_parsing_main_idl)
                $<y_parameter>$ = (AST_parameter_n_t *) AST_concat_element(
                                    (ASTP_node_t *) $<y_parameter>1,
                                    (ASTP_node_t *) $<y_parameter>3);
        }
    |   /* nothing */
        {
            $<y_parameter>$ = (AST_parameter_n_t *)NULL;
        }
    ;

param_dcl:
        attributes type_spec old_attribute_syntax declarator_or_null
        {
            /*
             * We have to use special code here to allow (void) as a parameter
             * specification.  If there are no declarators, then we need to
             * make sure that the type is void and that there are no attributes .
             */
            if ($<y_declarator>4 == NULL)
            {
                /*
                 * If the type is not void or some attribute is specified,
                 * there is a syntax error.  Force a yacc error, so that
                 * we can safely recover from the lack of a declarator.
                 */
                if (($<y_type>2->kind != AST_void_k) ||
                   ($<y_attributes>1.bounds != NULL) ||
                   ($<y_attributes>1.attr_flags != 0))
                {
                    yywhere(nidl_location(nidl));  /* Issue a syntax error for this line */
                    YYERROR;    /* Allow natural error recovery */
                }

                $<y_parameter>$ = (AST_parameter_n_t *)NULL;
            }
            else
            {
                if (ASTP_parsing_main_idl)
                    $<y_parameter>$ = AST_declarator_to_param(
                                            nidl_location(nidl),
                                            &$<y_attributes>1,
                                            $<y_type>2,
                                            $<y_declarator>4);
            }
            ASTP_free_simple_list((ASTP_node_t *)$<y_attributes>1.bounds);
        }
    |    error old_attribute_syntax declarator_or_null
        {
            log_error(nidl_yylineno(nidl), NIDL_MISSONPARAM, NULL);
            $<y_parameter>$ = (AST_parameter_n_t *)NULL;
        }
    ;

declarator_or_null:
        declarator
        { $<y_declarator>$ = $<y_declarator>1; }
    |   /* nothing */
        { $<y_declarator>$ = NULL; }
    ;

/*
 * Attribute definitions
 *
 * Attributes may appear on types, fields, parameters, operations and
 * interfaces.  Thes productions must be used around attributes in order
 * for LEX to recognize attribute names as keywords instead of identifiers.
 * The bounds productions are used in attribute options (such
 * as size_is) because variable names the may look like attribute names
 * should be allowed.
 */

attribute_opener:
        LBRACKET
        {
            search_attributes_table = true;
        }
    ;

attribute_closer:
        RBRACKET
        {
            search_attributes_table = false;
        }
    ;

bounds_opener:
        LPAREN
        {
            search_attributes_table = false;
        }
    ;

bounds_closer:
        RPAREN
        {
            search_attributes_table = true;
        }
    ;

/*
 * Production to accept attributes in the old location, and issue a clear error that
 * the translator should be used.
 */
old_attribute_syntax:
        attributes
        {
            /* Give an error on notranslated sources */
            if (($<y_attributes>1.bounds != NULL) ||
               ($<y_attributes>1.attr_flags != 0))
            {
                log_error(nidl_yylineno(nidl),NIDL_ATTRTRANS, NULL);
                ASTP_free_simple_list((ASTP_node_t *)$<y_attributes>1.bounds);
            }
        }
    ;

/*
 * Interface Attributes
 *
 * Interface attributes are special--there is no cross between interface
 * attributes and other attributes (for instance on fields or types.
 */
interface_attributes:
        attribute_opener interface_attr_list extraneous_comma attribute_closer
    |   attribute_opener error attribute_closer
        {
            log_error(nidl_yylineno(nidl),NIDL_ERRINATTR, NULL);
        }

    |   /* Nothing */
    ;

interface_attr_list:
        interface_attr
    |   interface_attr_list COMMA interface_attr
    |   /* nothing */
    ;

interface_attr:
        UUID_KW error
        {
            log_error(nidl_yylineno(nidl),NIDL_SYNTAXUUID, NULL);
        }
    |   UUID_KW UUID_REP
        {
            {
                if (ASTP_IF_AF_SET(the_interface,ASTP_IF_UUID))
                        log_error(nidl_yylineno(nidl), NIDL_ATTRUSEMULT, NULL);
                ASTP_SET_IF_AF(the_interface,ASTP_IF_UUID);
                the_interface->uuid = $<y_uuid>2;
            }
        }
    |   ENDPOINT_KW LPAREN port_list extraneous_comma RPAREN
        {
            if (ASTP_IF_AF_SET(the_interface,ASTP_IF_PORT))
                    log_error(nidl_yylineno(nidl), NIDL_ATTRUSEMULT, NULL);
            ASTP_SET_IF_AF(the_interface,ASTP_IF_PORT);
        }
    |   EXCEPTIONS_KW LPAREN excep_list extraneous_comma RPAREN
        {
            if (ASTP_IF_AF_SET(the_interface, ASTP_IF_EXCEPTIONS))
                log_error(nidl_yylineno(nidl), NIDL_ATTRUSEMULT, NULL);
            ASTP_SET_IF_AF(the_interface, ASTP_IF_EXCEPTIONS);
        }
    |   VERSION_KW LPAREN version_number RPAREN
        {
            {
                if (ASTP_IF_AF_SET(the_interface,ASTP_IF_VERSION))
                        log_error(nidl_yylineno(nidl), NIDL_ATTRUSEMULT, NULL);
                ASTP_SET_IF_AF(the_interface,ASTP_IF_VERSION);
            }

        }
    |   LOCAL_KW
        {
            {
                if (AST_LOCAL_SET(the_interface))
                        log_warning(nidl_yylineno(nidl), NIDL_MULATTRDEF, NULL);
                AST_SET_LOCAL(the_interface);
            }
        }
    |   POINTER_DEFAULT_KW LPAREN pointer_class RPAREN
        {
            if (the_interface->pointer_default != 0)
                    log_error(nidl_yylineno(nidl), NIDL_ATTRUSEMULT, NULL);
            the_interface->pointer_default = $<y_ptrclass>3;
        }
	 /* extensions to osf */
	 |	  OBJECT_KW
	 		{
				if (AST_OBJECT_SET(the_interface))
					 log_warning(nidl_yylineno(nidl), NIDL_MULATTRDEF, NULL);
				AST_SET_OBJECT(the_interface);
			}
	 |		acf_interface_attr
	 		{
				/* complain about compat here */
			}
    ;

acf_interface_attr:
	IMPLICIT_HANDLE_KW LPAREN HANDLE_T_KW IDENTIFIER RPAREN
	{
		if (the_interface->implicit_handle_name != NAMETABLE_NIL_ID)
			 log_error(nidl_yylineno(nidl), NIDL_ATTRUSEMULT, NULL);

		ASTP_set_implicit_handle(the_interface, NAMETABLE_NIL_ID, $<y_id>4);
	}
	|
	IMPLICIT_HANDLE_KW LPAREN IDENTIFIER IDENTIFIER RPAREN
	{
		if (the_interface->implicit_handle_name != NAMETABLE_NIL_ID)
			log_error(nidl_yylineno(nidl), NIDL_ATTRUSEMULT, NULL);

		ASTP_set_implicit_handle(the_interface, $<y_id>3, $<y_id>4);
	}
	;

pointer_class:
        REF_KW { $<y_ptrclass>$ = ASTP_REF; }
    |   PTR_KW { $<y_ptrclass>$ = ASTP_PTR; }
    |   UNIQUE_KW { $<y_ptrclass>$ = ASTP_UNIQUE; }
    ;

version_number:
        INTEGER_NUMERIC
        {
            the_interface->version = $<y_int_info>1.int_val;
            if (the_interface->version > /*(unsigned int)*/ASTP_C_USHORT_MAX)
                log_error(nidl_yylineno(nidl), NIDL_MAJORTOOLARGE,
			  ASTP_C_USHORT_MAX, NULL);
        }
   |    FLOAT_NUMERIC
        {
            char const *float_text;
            unsigned int            major_version,minor_version;
            STRTAB_str_to_string($<y_string>1, &float_text);
            sscanf(float_text,"%d.%d",&major_version,&minor_version);
            if (major_version > (unsigned int)ASTP_C_USHORT_MAX)
                log_error(nidl_yylineno(nidl), NIDL_MAJORTOOLARGE,
			  ASTP_C_USHORT_MAX, NULL);
            if (minor_version > (unsigned int)ASTP_C_USHORT_MAX)
                log_error(nidl_yylineno(nidl), NIDL_MINORTOOLARGE,
			  ASTP_C_USHORT_MAX, NULL);
            the_interface->version = (minor_version * 65536) + major_version;
        }
    ;

port_list:
        port_spec
    |   port_list COMMA port_spec
    ;

excep_list:
        excep_spec
        {
            the_interface->exceptions = $<y_exception>1;
        }
    |   excep_list COMMA excep_spec
        {
            $<y_exception>$ = (AST_exception_n_t *) AST_concat_element(
                                (ASTP_node_t *) the_interface->exceptions,
                                (ASTP_node_t *) $<y_exception>3 );
        }
    ;

port_spec:
        STRING
        {
            ASTP_parse_port(the_interface,$<y_string>1);
        }
    ;

excep_spec:
        IDENTIFIER
        {
            if (ASTP_parsing_main_idl)
            {
                $<y_exception>$ =
                   AST_exception_node(nidl_location(nidl), $<y_id>1);
            }
            else
            {
                $<y_exception>$ = NULL;
            }
        }
    ;

/*
 * Attributes that can appear on fields or parameters. These are the array
 * bounds attributes, i.e., last_is and friends. They are handled differently
 * from any other attributes.
 */
fp_attribute:
        array_bound_type bounds_opener array_bound_id_list bounds_closer
        {
            $<y_attributes>$.bounds = $<y_attributes>3.bounds;
            $<y_attributes>$.attr_flags = 0;
        }
    |   neu_switch_type bounds_opener neu_switch_id bounds_closer
        {
            $<y_attributes>$.bounds = $<y_attributes>3.bounds;
            $<y_attributes>$.attr_flags = 0;
        }
    ;

array_bound_type:
        FIRST_IS_KW
        {
            ASTP_bound_type = first_is_k;
        }
    |   LAST_IS_KW
        {
            ASTP_bound_type = last_is_k;
        }
    |   LENGTH_IS_KW
        {
            ASTP_bound_type = length_is_k;
        }
    |   MAX_IS_KW
        {
            ASTP_bound_type = max_is_k;
        }
    |   MIN_IS_KW
        {
            ASTP_bound_type = min_is_k;
        }
    |   SIZE_IS_KW
        {
            ASTP_bound_type = size_is_k;
        }
    ;

array_bound_id_list:
        array_bound_id
    |   array_bound_id_list COMMA array_bound_id
        {
        $<y_attributes>$.bounds = (ASTP_type_attr_n_t *) AST_concat_element (
                                (ASTP_node_t*) $<y_attributes>1.bounds,
                                (ASTP_node_t*) $<y_attributes>3.bounds);
        }
    ;

/* expression conflicts with identifier here */
array_bound_id:
	  expression
			{
				 $<y_attributes>$.bounds =
                AST_array_bound_from_expr(nidl_location(nidl),
                        $<y_exp>1, ASTP_bound_type);
			}
    |   /* nothing */
        {
        $<y_attributes>$.bounds = AST_array_bound_info (nidl_location(nidl),
                        NAMETABLE_NIL_ID, ASTP_bound_type, FALSE);
        }
    ;

neu_switch_type:
        SWITCH_IS_KW
        {
            ASTP_bound_type = switch_is_k;
        }
    ;

neu_switch_id:
        IDENTIFIER
        {
        $<y_attributes>$.bounds = AST_array_bound_info(nidl_location(nidl),
                        $<y_id>1, ASTP_bound_type, FALSE);
        }
    |   STAR IDENTIFIER
        {
        $<y_attributes>$.bounds = AST_array_bound_info(nidl_location(nidl),
                        $<y_id>2, ASTP_bound_type, TRUE);
        }
    ;

/*
 * Generalized Attribute processing
 */
attributes:
        attribute_opener rest_of_attribute_list
        { $<y_attributes>$ = $<y_attributes>2; }
     |
        /* nothing */
        {
        $<y_attributes>$.bounds = NULL;
        $<y_attributes>$.attr_flags = 0;
        }
     ;

rest_of_attribute_list:
        attribute_list extraneous_comma attribute_closer
     |  error attribute_closer
        {
        /*
         * Can't tell if we had any valid attributes in the list, so return
         * none.
         */
        $<y_attributes>$.bounds = NULL;
        $<y_attributes>$.attr_flags = 0;
        log_error(nidl_yylineno(nidl), NIDL_ERRINATTR, NULL);
        }
     |  error SEMI
        {
        /*
         * No closer to the attribute, so give a different message.
         */
        $<y_attributes>$.bounds = NULL;
        $<y_attributes>$.attr_flags = 0;
        log_error(nidl_yylineno(nidl), NIDL_MISSONATTR, NULL);
        search_attributes_table = false;
        }
     ;

attribute_list:
        attribute
        { $<y_attributes>$ = $<y_attributes>1; }
     |
        attribute_list COMMA attribute
        {
          /*
           * If the same bit has been specified more than once, then issue
           * a message.
           */
          if (($<y_attributes>1.attr_flags & $<y_attributes>3.attr_flags) != 0)
                log_warning(nidl_yylineno(nidl), NIDL_MULATTRDEF, NULL);
          $<y_attributes>$.attr_flags = $<y_attributes>1.attr_flags |
                                        $<y_attributes>3.attr_flags;
          $<y_attributes>$.bounds = (ASTP_type_attr_n_t *) AST_concat_element (
                                (ASTP_node_t*) $<y_attributes>1.bounds,
                                (ASTP_node_t*) $<y_attributes>3.bounds);
        }
     ;

attribute:
        /* bound attributes */
        fp_attribute            { $<y_attributes>$ = $<y_attributes>1; }

        /* Operation Attributes */
    |   BROADCAST_KW            { $<y_attributes>$.attr_flags = ASTP_BROADCAST;
                                  $<y_attributes>$.bounds = NULL;       }
    |   MAYBE_KW                { $<y_attributes>$.attr_flags = ASTP_MAYBE;
                                  $<y_attributes>$.bounds = NULL;       }
    |   IDEMPOTENT_KW           { $<y_attributes>$.attr_flags = ASTP_IDEMPOTENT;
                                  $<y_attributes>$.bounds = NULL;       }
    |   REFLECT_DELETIONS_KW    { $<y_attributes>$.attr_flags = ASTP_REFLECT_DELETIONS;
                                  $<y_attributes>$.bounds = NULL;       }
	 |   LOCAL_KW                { $<y_attributes>$.attr_flags = ASTP_LOCAL;
	                               $<y_attributes>$.bounds = NULL;       }
	 |   CALL_AS_KW LPAREN IDENTIFIER RPAREN	{	}

        /* Parameter-only Attributes */
    |   PTR_KW                  { $<y_attributes>$.attr_flags = ASTP_PTR;
                                  $<y_attributes>$.bounds = NULL;       }
    |   IN_KW                   { $<y_attributes>$.attr_flags = ASTP_IN;
                                  $<y_attributes>$.bounds = NULL;       }
    |   IN_KW LPAREN SHAPE_KW RPAREN
                                { $<y_attributes>$.attr_flags =
                                        ASTP_IN | ASTP_IN_SHAPE;
                                  $<y_attributes>$.bounds = NULL;       }
    |   OUT_KW                  { $<y_attributes>$.attr_flags = ASTP_OUT;
                                  $<y_attributes>$.bounds = NULL;       }
    |   OUT_KW LPAREN SHAPE_KW RPAREN
                                { $<y_attributes>$.attr_flags =
                                        ASTP_OUT | ASTP_OUT_SHAPE;
                                  $<y_attributes>$.bounds = NULL;       }
	 |	  IID_IS_KW LPAREN IDENTIFIER RPAREN
											{ $<y_attributes>$.iid_is_name = $<y_id>3;
                                   $<y_attributes>$.bounds = NULL;
                                   $<y_attributes>$.attr_flags = 0;
											}
	 |	  IID_IS_KW LPAREN STAR IDENTIFIER RPAREN /* MIDL extension */
											{ $<y_attributes>$.iid_is_name = $<y_id>4;
                                   $<y_attributes>$.bounds = NULL;
                                   $<y_attributes>$.attr_flags = 0;
											}

        /* Type, Field, Parameter Attributes */
    |   V1_ARRAY_KW             { $<y_attributes>$.attr_flags = ASTP_SMALL;
                                  $<y_attributes>$.bounds = NULL;       }
    |   STRING_KW               { $<y_attributes>$.attr_flags = ASTP_STRING;
                                  $<y_attributes>$.bounds = NULL;       }
    |   V1_STRING_KW            { $<y_attributes>$.attr_flags = ASTP_STRING0;
                                  $<y_attributes>$.bounds = NULL;       }
    |   UNIQUE_KW               { $<y_attributes>$.attr_flags = ASTP_UNIQUE;
                                  $<y_attributes>$.bounds = NULL;       }
    |   REF_KW                  { $<y_attributes>$.attr_flags = ASTP_REF;
                                  $<y_attributes>$.bounds = NULL;       }
    |   IGNORE_KW               { $<y_attributes>$.attr_flags = ASTP_IGNORE;
                                  $<y_attributes>$.bounds = NULL;       }
    |   CONTEXT_HANDLE_KW       { $<y_attributes>$.attr_flags = ASTP_CONTEXT;
                                  $<y_attributes>$.bounds = NULL;       }
    |   RANGE_KW LPAREN expression COMMA expression RPAREN /* MIDL extension */
                                { $<y_attributes>$.attr_flags = ASTP_RANGE;
                                  $<y_attributes>$.bounds =
                                     AST_range_from_expr(nidl_location(nidl),
                                           $<y_exp>3, $<y_exp>5);
                                }

        /* Type-only Attribute(s) */
    |   V1_STRUCT_KW            { $<y_attributes>$.attr_flags = ASTP_UNALIGN;
                                  $<y_attributes>$.bounds = NULL;       }
    |   V1_ENUM_KW              { $<y_attributes>$.attr_flags = ASTP_V1_ENUM;
                                  $<y_attributes>$.bounds = NULL;       }
    |   ALIGN_KW LPAREN SMALL_KW RPAREN
                                { $<y_attributes>$.attr_flags = ASTP_ALIGN_SMALL;
                                  $<y_attributes>$.bounds = NULL;       }
    |   ALIGN_KW LPAREN SHORT_KW RPAREN
                                { $<y_attributes>$.attr_flags = ASTP_ALIGN_SHORT;
                                  $<y_attributes>$.bounds = NULL;       }
    |   ALIGN_KW LPAREN LONG_KW RPAREN
                                { $<y_attributes>$.attr_flags = ASTP_ALIGN_LONG;
                                  $<y_attributes>$.bounds = NULL;       }
    |   ALIGN_KW LPAREN HYPER_KW RPAREN
                                { $<y_attributes>$.attr_flags = ASTP_ALIGN_HYPER;
                                  $<y_attributes>$.bounds = NULL;       }
    |   HANDLE_KW               { $<y_attributes>$.attr_flags = ASTP_HANDLE;
                                  $<y_attributes>$.bounds = NULL;       }
    |   TRANSMIT_AS_KW LPAREN simple_type_spec RPAREN
                                { $<y_attributes>$.attr_flags = ASTP_TRANSMIT_AS;
                                  $<y_attributes>$.bounds = NULL;
                                  ASTP_transmit_as_type = $<y_type>3;
                                }
    |   SWITCH_TYPE_KW LPAREN simple_type_spec RPAREN
                                { $<y_attributes>$.attr_flags = ASTP_SWITCH_TYPE;
                                  $<y_attributes>$.bounds = NULL;
                                  ASTP_switch_type = $<y_type>3;
                                }

        /* Arm-only Attribute(s) */
    |   CASE_KW LPAREN ne_union_case_list RPAREN
                                { $<y_attributes>$.attr_flags = ASTP_CASE;
                                  $<y_attributes>$.bounds = NULL;
                                  ASTP_case = $<y_label>3;
                                }
    |   DEFAULT_KW              { $<y_attributes>$.attr_flags = ASTP_DEFAULT;
                                  $<y_attributes>$.bounds = NULL;
                                }
    |   IDENTIFIER      /* Not an attribute, so give an error */
        {
                char const *identifier; /* place to receive the identifier text */
                NAMETABLE_id_to_string ($<y_id>1, &identifier);
                log_error (nidl_yylineno(nidl), NIDL_UNKNOWNATTR, identifier, NULL);
                $<y_attributes>$.attr_flags = 0;
                $<y_attributes>$.bounds = NULL;
        }
    ;

/********************************************************************/
/*                                                                  */
/*          Compiletime Integer expression evaluation               */
/*                                                                  */
/********************************************************************/
expression: conditional_expression
        {$<y_exp>$ = $<y_exp>1;}
   ;

conditional_expression:
        logical_OR_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    logical_OR_expression QUESTION expression COLON conditional_expression
        {
            $<y_exp>$ = AST_expression(nidl_location(nidl),
                     AST_EXP_TERNARY_OP, $<y_exp>1, $<y_exp>3, $<y_exp>5);
        }
   ;

logical_OR_expression:
        logical_AND_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    logical_OR_expression BARBAR logical_AND_expression
        {
            $<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_LOG_OR, $<y_exp>1, $<y_exp>3, NULL);
        }
   ;

logical_AND_expression:
        inclusive_OR_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    logical_AND_expression AMPAMP inclusive_OR_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_LOG_AND, $<y_exp>1, $<y_exp>3, NULL);
        }
   ;

inclusive_OR_expression:
        exclusive_OR_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    inclusive_OR_expression BAR exclusive_OR_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_OR, $<y_exp>1, $<y_exp>3, NULL);
        }
   ;

exclusive_OR_expression:
        AND_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    exclusive_OR_expression CARET AND_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_XOR, $<y_exp>1, $<y_exp>3, NULL);
        }
   ;

AND_expression:
        equality_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    AND_expression AMP equality_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_AND, $<y_exp>1, $<y_exp>3, NULL);
        }
   ;

equality_expression:
        relational_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    equality_expression EQUALEQUAL relational_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_EQUAL, $<y_exp>1, $<y_exp>3, NULL);
        }
   |    equality_expression NOTEQUAL relational_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_NE, $<y_exp>1, $<y_exp>3, NULL);

        }
   ;

relational_expression:
        shift_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    relational_expression LANGLE shift_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_LT, $<y_exp>1, $<y_exp>3, NULL);
        }
   |    relational_expression RANGLE shift_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_GT, $<y_exp>1, $<y_exp>3, NULL);
        }
   |    relational_expression LESSEQUAL shift_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_LE, $<y_exp>1, $<y_exp>3, NULL);
        }
   |    relational_expression GREATEREQUAL shift_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_GE, $<y_exp>1, $<y_exp>3, NULL);

        }
   ;

shift_expression:
        additive_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    shift_expression LANGLEANGLE additive_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_LSHIFT, $<y_exp>1, $<y_exp>3, NULL);
        }
   |    shift_expression RANGLEANGLE additive_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_RSHIFT, $<y_exp>1, $<y_exp>3, NULL);

        }
   ;

additive_expression:
        multiplicative_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    additive_expression PLUS multiplicative_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_PLUS, $<y_exp>1, $<y_exp>3, NULL);

        }
   |    additive_expression MINUS multiplicative_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_MINUS, $<y_exp>1, $<y_exp>3, NULL);
        }
   ;

multiplicative_expression:
        cast_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    multiplicative_expression STAR cast_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_STAR, $<y_exp>1, $<y_exp>3, NULL);
				/*
            if (($<y_exp>$.exp.constant.val.integer < $<y_exp>1.exp.constant.val.integer) &&
                ($<y_exp>$.exp.constant.val.integer < $<y_exp>3.exp.constant.val.integer))
                log_error (nidl_yylineno(nidl), NIDL_INTOVERFLOW,
			   KEYWORDS_lookup_text(LONG_KW), NULL);
					*/
        }
   |    multiplicative_expression SLASH cast_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_SLASH, $<y_exp>1, $<y_exp>3, NULL);
        }
   |    multiplicative_expression PERCENT cast_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_BINARY_PERCENT, $<y_exp>1, $<y_exp>3, NULL);
            /*    log_error (nidl_yylineno(nidl), NIDL_INTDIVBY0, NULL); */
        }
   ;

cast_expression: unary_expression
        {$<y_exp>$ = $<y_exp>1;}
    ;

unary_expression:
        primary_expression
        {$<y_exp>$ = $<y_exp>1;}
   |    PLUS primary_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_UNARY_PLUS, $<y_exp>2, NULL, NULL);
		  }
   |    MINUS primary_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_UNARY_MINUS, $<y_exp>2, NULL, NULL);
        }
   |    TILDE primary_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_UNARY_TILDE, $<y_exp>2, NULL, NULL);
        }
   |    NOT primary_expression
        {
				$<y_exp>$ = AST_expression(nidl_location(nidl),
                  AST_EXP_UNARY_NOT, $<y_exp>2, NULL, NULL);
        }
	|	  STAR primary_expression
		  {
			  $<y_exp>$ = AST_expression(nidl_location(nidl),
                 AST_EXP_UNARY_STAR, $<y_exp>2, NULL, NULL);
		  }
   ;

primary_expression:
        LPAREN expression RPAREN
        { $<y_exp>$ = $<y_exp>2; }
    |   INTEGER_NUMERIC
        {
				$<y_exp>$ = AST_exp_integer_constant(
               nidl_location(nidl),
					$<y_int_info>1.int_val,
					$<y_int_info>1.int_signed);
        }
    |   CHAR
        {
				$<y_exp>$ = AST_exp_char_constant(nidl_location(nidl), $<y_char>1);
        }
    |   IDENTIFIER
        {
            $<y_exp>$ = AST_exp_identifier(nidl_location(nidl), $<y_id>1);
        }
    |   STRING
        {
            $<y_exp>$ = AST_exp_string_constant(
                  nidl_location(nidl), $<y_string>1);
        }
    |   NULL_KW
        {
            $<y_exp>$ = AST_exp_null_constant(nidl_location(nidl));
        }

    |   TRUE_KW
        {
            $<y_exp>$ = AST_exp_boolean_constant(nidl_location(nidl), true);
        }

    |   FALSE_KW
        {
            $<y_exp>$ = AST_exp_boolean_constant(nidl_location(nidl), false);
        }
   |    FLOAT_NUMERIC
        {
				$<y_exp>$ = AST_exp_integer_constant(nidl_location(nidl), 0,0);
            log_error(nidl_yylineno(nidl), NIDL_FLOATCONSTNOSUP, NULL);
        }
   ;
%%

nidl_parser_p nidl_parser_alloc
(
    boolean     *cmd_opt_arr,   /* [in] Array of command option flags */
    void        **cmd_val_arr,  /* [in] Array of command option values */
    char        *nidl_file       /* [in] ACF file name */
)
{
   nidl_parser_state_t * nidl;

   nidl = NEW(nidl_parser_state_t);

   /* Set global (STRTAB_str_t error_file_name_id) for error processing. */
   set_name_for_errors(nidl_file);
   nidl->nidl_location.fileid = STRTAB_add_string(nidl_file);

   // XXX save file name ID in parser state

   return nidl;
}

void nidl_parser_destroy
(
   nidl_parser_p nidl
)
{
   FREE(nidl);
   yyin_p = NULL;
   yylineno_p = NULL;
}

void nidl_parser_input
(
    nidl_parser_p nidl,
    FILE * in
)
{
    assert(nidl->nidl_yyscanner == NULL);

    nidl_yylex_init(&nidl->nidl_yyscanner);
    nidl_yyset_in(in, nidl->nidl_yyscanner);

    yyin_p = in;
    yylineno_p = &nidl->nidl_location.lineno;
}

const parser_location_t * nidl_location
(
   nidl_parser_p nidl
)
{
    /* Update the current location before handing it back ... */
    nidl->nidl_location.lineno = nidl_yylineno(nidl);
    nidl->nidl_location.location = *nidl_yyget_lloc(nidl->nidl_yyscanner);
    nidl->nidl_location.text = nidl_yyget_text(nidl->nidl_yyscanner);

    return &nidl->nidl_location;
}

unsigned nidl_yylineno
(
   nidl_parser_p nidl
)
{
   return nidl_yyget_lineno(nidl->nidl_yyscanner);
}

unsigned nidl_errcount
(
   nidl_parser_p nidl
)
{
   return nidl->nidl_yynerrs;
}

static void nidl_yyerror
(
    YYLTYPE * yylloc ATTRIBUTE_UNUSED,
    nidl_parser_p nidl,
    char const * message
)
{
    const struct parser_location_t * loc;
    loc = nidl_location(nidl);
    idl_yyerror(loc, message);
}

/* preserve coding style vim: set tw=78 sw=3 ts=3 et : */