| /* | 
 |  * From: @(#)rpc_parse.c 1.8 89/02/22 | 
 |  * | 
 |  * Copyright (c) 2010, Oracle America, Inc. | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions are | 
 |  * met: | 
 |  * | 
 |  *     * Redistributions of source code must retain the above copyright | 
 |  *       notice, this list of conditions and the following disclaimer. | 
 |  *     * 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. | 
 |  *     * Neither the name of the "Oracle America, Inc." 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 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 HOLDER 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. | 
 |  */ | 
 |  | 
 | /* | 
 |  * rpc_parse.c, Parser for the RPC protocol compiler | 
 |  * Copyright (C) 1987 Sun Microsystems, Inc. | 
 |  */ | 
 | #include <stdio.h> | 
 | #include <string.h> | 
 | #include "rpc/types.h" | 
 | #include "rpc_scan.h" | 
 | #include "rpc_parse.h" | 
 | #include "rpc_util.h" | 
 | #include "proto.h" | 
 |  | 
 | #define ARGNAME "arg" | 
 |  | 
 | static void isdefined (definition * defp); | 
 | static void def_struct (definition * defp); | 
 | static void def_program (definition * defp); | 
 | static void def_enum (definition * defp); | 
 | static void def_const (definition * defp); | 
 | static void def_union (definition * defp); | 
 | static void check_type_name (const char *name, int new_type); | 
 | static void def_typedef (definition * defp); | 
 | static void get_declaration (declaration * dec, defkind dkind); | 
 | static void get_prog_declaration (declaration * dec, defkind dkind, int num); | 
 | static void get_type (const char **prefixp, const char **typep, defkind dkind); | 
 | static void unsigned_dec (const char **typep); | 
 |  | 
 | /* | 
 |  * return the next definition you see | 
 |  */ | 
 | definition * | 
 | get_definition (void) | 
 | { | 
 |   definition *defp; | 
 |   token tok; | 
 |  | 
 |   defp = ALLOC (definition); | 
 |   get_token (&tok); | 
 |   switch (tok.kind) | 
 |     { | 
 |     case TOK_STRUCT: | 
 |       def_struct (defp); | 
 |       break; | 
 |     case TOK_UNION: | 
 |       def_union (defp); | 
 |       break; | 
 |     case TOK_TYPEDEF: | 
 |       def_typedef (defp); | 
 |       break; | 
 |     case TOK_ENUM: | 
 |       def_enum (defp); | 
 |       break; | 
 |     case TOK_PROGRAM: | 
 |       def_program (defp); | 
 |       break; | 
 |     case TOK_CONST: | 
 |       def_const (defp); | 
 |       break; | 
 |     case TOK_EOF: | 
 |       free (defp); | 
 |       return (NULL); | 
 |     default: | 
 |       error ("definition keyword expected"); | 
 |     } | 
 |   scan (TOK_SEMICOLON, &tok); | 
 |   isdefined (defp); | 
 |   return (defp); | 
 | } | 
 |  | 
 | static void | 
 | isdefined (definition * defp) | 
 | { | 
 |   STOREVAL (&defined, defp); | 
 | } | 
 |  | 
 | static void | 
 | def_struct (definition * defp) | 
 | { | 
 |   token tok; | 
 |   declaration dec; | 
 |   decl_list *decls; | 
 |   decl_list **tailp; | 
 |  | 
 |   defp->def_kind = DEF_STRUCT; | 
 |  | 
 |   scan (TOK_IDENT, &tok); | 
 |   defp->def_name = tok.str; | 
 |   scan (TOK_LBRACE, &tok); | 
 |   tailp = &defp->def.st.decls; | 
 |   do | 
 |     { | 
 |       get_declaration (&dec, DEF_STRUCT); | 
 |       decls = ALLOC (decl_list); | 
 |       decls->decl = dec; | 
 |       *tailp = decls; | 
 |       tailp = &decls->next; | 
 |       scan (TOK_SEMICOLON, &tok); | 
 |       peek (&tok); | 
 |     } | 
 |   while (tok.kind != TOK_RBRACE); | 
 |   get_token (&tok); | 
 |   *tailp = NULL; | 
 | } | 
 |  | 
 | static void | 
 | def_program (definition * defp) | 
 | { | 
 |   token tok; | 
 |   declaration dec; | 
 |   decl_list *decls; | 
 |   decl_list **tailp; | 
 |   version_list *vlist; | 
 |   version_list **vtailp; | 
 |   proc_list *plist; | 
 |   proc_list **ptailp; | 
 |   int num_args; | 
 |   bool_t isvoid = FALSE;	/* whether first argument is void */ | 
 |   defp->def_kind = DEF_PROGRAM; | 
 |   scan (TOK_IDENT, &tok); | 
 |   defp->def_name = tok.str; | 
 |   scan (TOK_LBRACE, &tok); | 
 |   vtailp = &defp->def.pr.versions; | 
 |   tailp = &defp->def.st.decls; | 
 |   scan (TOK_VERSION, &tok); | 
 |   do | 
 |     { | 
 |       scan (TOK_IDENT, &tok); | 
 |       vlist = ALLOC (version_list); | 
 |       vlist->vers_name = tok.str; | 
 |       scan (TOK_LBRACE, &tok); | 
 |       ptailp = &vlist->procs; | 
 |       do | 
 | 	{ | 
 | 	  /* get result type */ | 
 | 	  plist = ALLOC (proc_list); | 
 | 	  get_type (&plist->res_prefix, &plist->res_type, | 
 | 		    DEF_PROGRAM); | 
 | 	  if (streq (plist->res_type, "opaque")) | 
 | 	    { | 
 | 	      error ("illegal result type"); | 
 | 	    } | 
 | 	  scan (TOK_IDENT, &tok); | 
 | 	  plist->proc_name = tok.str; | 
 | 	  scan (TOK_LPAREN, &tok); | 
 | 	  /* get args - first one */ | 
 | 	  num_args = 1; | 
 | 	  isvoid = FALSE; | 
 | 	  /* type of DEF_PROGRAM in the first | 
 | 	   * get_prog_declaration and DEF_STURCT in the next | 
 | 	   * allows void as argument if it is the only argument | 
 | 	   */ | 
 | 	  get_prog_declaration (&dec, DEF_PROGRAM, num_args); | 
 | 	  if (streq (dec.type, "void")) | 
 | 	    isvoid = TRUE; | 
 | 	  decls = ALLOC (decl_list); | 
 | 	  plist->args.decls = decls; | 
 | 	  decls->decl = dec; | 
 | 	  tailp = &decls->next; | 
 | 	  /* get args */ | 
 | 	  while (peekscan (TOK_COMMA, &tok)) | 
 | 	    { | 
 | 	      num_args++; | 
 | 	      get_prog_declaration (&dec, DEF_STRUCT, | 
 | 				    num_args); | 
 | 	      decls = ALLOC (decl_list); | 
 | 	      decls->decl = dec; | 
 | 	      *tailp = decls; | 
 | 	      if (streq (dec.type, "void")) | 
 | 		isvoid = TRUE; | 
 | 	      tailp = &decls->next; | 
 | 	    } | 
 | 	  /* multiple arguments are only allowed in newstyle */ | 
 | 	  if (!newstyle && num_args > 1) | 
 | 	    { | 
 | 	      error ("only one argument is allowed"); | 
 | 	    } | 
 | 	  if (isvoid && num_args > 1) | 
 | 	    { | 
 | 	      error ("illegal use of void in program definition"); | 
 | 	    } | 
 | 	  *tailp = NULL; | 
 | 	  scan (TOK_RPAREN, &tok); | 
 | 	  scan (TOK_EQUAL, &tok); | 
 | 	  scan_num (&tok); | 
 | 	  scan (TOK_SEMICOLON, &tok); | 
 | 	  plist->proc_num = tok.str; | 
 | 	  plist->arg_num = num_args; | 
 | 	  *ptailp = plist; | 
 | 	  ptailp = &plist->next; | 
 | 	  peek (&tok); | 
 | 	} | 
 |       while (tok.kind != TOK_RBRACE); | 
 |       *ptailp = NULL; | 
 |       *vtailp = vlist; | 
 |       vtailp = &vlist->next; | 
 |       scan (TOK_RBRACE, &tok); | 
 |       scan (TOK_EQUAL, &tok); | 
 |       scan_num (&tok); | 
 |       vlist->vers_num = tok.str; | 
 |       /* make the argument structure name for each arg */ | 
 |       for (plist = vlist->procs; plist != NULL; | 
 | 	   plist = plist->next) | 
 | 	{ | 
 | 	  plist->args.argname = make_argname (plist->proc_name, | 
 | 					      vlist->vers_num); | 
 | 	  /* free the memory ?? */ | 
 | 	} | 
 |       scan (TOK_SEMICOLON, &tok); | 
 |       scan2 (TOK_VERSION, TOK_RBRACE, &tok); | 
 |     } | 
 |   while (tok.kind == TOK_VERSION); | 
 |   scan (TOK_EQUAL, &tok); | 
 |   scan_num (&tok); | 
 |   defp->def.pr.prog_num = tok.str; | 
 |   *vtailp = NULL; | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | def_enum (definition * defp) | 
 | { | 
 |   token tok; | 
 |   enumval_list *elist; | 
 |   enumval_list **tailp; | 
 |  | 
 |   defp->def_kind = DEF_ENUM; | 
 |   scan (TOK_IDENT, &tok); | 
 |   defp->def_name = tok.str; | 
 |   scan (TOK_LBRACE, &tok); | 
 |   tailp = &defp->def.en.vals; | 
 |   do | 
 |     { | 
 |       scan (TOK_IDENT, &tok); | 
 |       elist = ALLOC (enumval_list); | 
 |       elist->name = tok.str; | 
 |       elist->assignment = NULL; | 
 |       scan3 (TOK_COMMA, TOK_RBRACE, TOK_EQUAL, &tok); | 
 |       if (tok.kind == TOK_EQUAL) | 
 | 	{ | 
 | 	  scan_num (&tok); | 
 | 	  elist->assignment = tok.str; | 
 | 	  scan2 (TOK_COMMA, TOK_RBRACE, &tok); | 
 | 	} | 
 |       *tailp = elist; | 
 |       tailp = &elist->next; | 
 |     } | 
 |   while (tok.kind != TOK_RBRACE); | 
 |   *tailp = NULL; | 
 | } | 
 |  | 
 | static void | 
 | def_const (definition * defp) | 
 | { | 
 |   token tok; | 
 |  | 
 |   defp->def_kind = DEF_CONST; | 
 |   scan (TOK_IDENT, &tok); | 
 |   defp->def_name = tok.str; | 
 |   scan (TOK_EQUAL, &tok); | 
 |   scan2 (TOK_IDENT, TOK_STRCONST, &tok); | 
 |   defp->def.co = tok.str; | 
 | } | 
 |  | 
 | static void | 
 | def_union (definition *defp) | 
 | { | 
 |   token tok; | 
 |   declaration dec; | 
 |   case_list *cases; | 
 | /*  case_list *tcase; */ | 
 |   case_list **tailp; | 
 | #if 0 | 
 |   int flag; | 
 | #endif | 
 |  | 
 |   defp->def_kind = DEF_UNION; | 
 |   scan (TOK_IDENT, &tok); | 
 |   defp->def_name = tok.str; | 
 |   scan (TOK_SWITCH, &tok); | 
 |   scan (TOK_LPAREN, &tok); | 
 |   get_declaration (&dec, DEF_UNION); | 
 |   defp->def.un.enum_decl = dec; | 
 |   tailp = &defp->def.un.cases; | 
 |   scan (TOK_RPAREN, &tok); | 
 |   scan (TOK_LBRACE, &tok); | 
 |   scan (TOK_CASE, &tok); | 
 |   while (tok.kind == TOK_CASE) | 
 |     { | 
 |       scan2 (TOK_IDENT, TOK_CHARCONST, &tok); | 
 |       cases = ALLOC (case_list); | 
 |       cases->case_name = tok.str; | 
 |       scan (TOK_COLON, &tok); | 
 |       /* now peek at next token */ | 
 | #if 0 | 
 |       flag = 0; | 
 | #endif | 
 |       if (peekscan (TOK_CASE, &tok)) | 
 | 	{ | 
 |  | 
 | 	  do | 
 | 	    { | 
 | 	      scan2 (TOK_IDENT, TOK_CHARCONST, &tok); | 
 | 	      cases->contflag = 1;	/* continued case statement */ | 
 | 	      *tailp = cases; | 
 | 	      tailp = &cases->next; | 
 | 	      cases = ALLOC (case_list); | 
 | 	      cases->case_name = tok.str; | 
 | 	      scan (TOK_COLON, &tok); | 
 |  | 
 | 	    } | 
 | 	  while (peekscan (TOK_CASE, &tok)); | 
 | 	} | 
 | #if 0 | 
 |       else if (flag) | 
 | 	{ | 
 |  | 
 | 	  *tailp = cases; | 
 | 	  tailp = &cases->next; | 
 | 	  cases = ALLOC (case_list); | 
 | 	}; | 
 | #endif | 
 |  | 
 |       get_declaration (&dec, DEF_UNION); | 
 |       cases->case_decl = dec; | 
 |       cases->contflag = 0;	/* no continued case statement */ | 
 |       *tailp = cases; | 
 |       tailp = &cases->next; | 
 |       scan (TOK_SEMICOLON, &tok); | 
 |  | 
 |       scan3 (TOK_CASE, TOK_DEFAULT, TOK_RBRACE, &tok); | 
 |     } | 
 |   *tailp = NULL; | 
 |   if (tok.kind == TOK_DEFAULT) | 
 |     { | 
 |       scan (TOK_COLON, &tok); | 
 |       get_declaration (&dec, DEF_UNION); | 
 |       defp->def.un.default_decl = ALLOC (declaration); | 
 |       *defp->def.un.default_decl = dec; | 
 |       scan (TOK_SEMICOLON, &tok); | 
 |       scan (TOK_RBRACE, &tok); | 
 |     } | 
 |   else | 
 |     { | 
 |       defp->def.un.default_decl = NULL; | 
 |     } | 
 | } | 
 |  | 
 | static const char *reserved_words[] = | 
 | { | 
 |   "array", | 
 |   "bytes", | 
 |   "destroy", | 
 |   "free", | 
 |   "getpos", | 
 |   "inline", | 
 |   "pointer", | 
 |   "reference", | 
 |   "setpos", | 
 |   "sizeof", | 
 |   "union", | 
 |   "vector", | 
 |   NULL | 
 | }; | 
 |  | 
 | static const char *reserved_types[] = | 
 | { | 
 |   "opaque", | 
 |   "string", | 
 |   NULL | 
 | }; | 
 |  | 
 | /* | 
 |  * check that the given name is not one that would eventually result in | 
 |  * xdr routines that would conflict with internal XDR routines. | 
 |  */ | 
 | static void | 
 | check_type_name (const char *name, int new_type) | 
 | { | 
 |   int i; | 
 |   char tmp[100]; | 
 |  | 
 |   for (i = 0; reserved_words[i] != NULL; i++) | 
 |     { | 
 |       if (strcmp (name, reserved_words[i]) == 0) | 
 | 	{ | 
 | 	  sprintf (tmp, | 
 | 		"illegal (reserved) name :\'%s\' in type definition", name); | 
 | 	  error (tmp); | 
 | 	} | 
 |     } | 
 |   if (new_type) | 
 |     { | 
 |       for (i = 0; reserved_types[i] != NULL; i++) | 
 | 	{ | 
 | 	  if (strcmp (name, reserved_types[i]) == 0) | 
 | 	    { | 
 | 	      sprintf (tmp, | 
 | 		"illegal (reserved) name :\'%s\' in type definition", name); | 
 | 	      error (tmp); | 
 | 	    } | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 |  | 
 |  | 
 | static void | 
 | def_typedef (definition * defp) | 
 | { | 
 |   declaration dec; | 
 |  | 
 |   defp->def_kind = DEF_TYPEDEF; | 
 |   get_declaration (&dec, DEF_TYPEDEF); | 
 |   defp->def_name = dec.name; | 
 |   check_type_name (dec.name, 1); | 
 |   defp->def.ty.old_prefix = dec.prefix; | 
 |   defp->def.ty.old_type = dec.type; | 
 |   defp->def.ty.rel = dec.rel; | 
 |   defp->def.ty.array_max = dec.array_max; | 
 | } | 
 |  | 
 | static void | 
 | get_declaration (declaration * dec, defkind dkind) | 
 | { | 
 |   token tok; | 
 |  | 
 |   get_type (&dec->prefix, &dec->type, dkind); | 
 |   dec->rel = REL_ALIAS; | 
 |   if (streq (dec->type, "void")) | 
 |     { | 
 |       return; | 
 |     } | 
 |  | 
 |   check_type_name (dec->type, 0); | 
 |  | 
 |   scan2 (TOK_STAR, TOK_IDENT, &tok); | 
 |   if (tok.kind == TOK_STAR) | 
 |     { | 
 |       dec->rel = REL_POINTER; | 
 |       scan (TOK_IDENT, &tok); | 
 |     } | 
 |   dec->name = tok.str; | 
 |   if (peekscan (TOK_LBRACKET, &tok)) | 
 |     { | 
 |       if (dec->rel == REL_POINTER) | 
 | 	{ | 
 | 	  error ("no array-of-pointer declarations -- use typedef"); | 
 | 	} | 
 |       dec->rel = REL_VECTOR; | 
 |       scan_num (&tok); | 
 |       dec->array_max = tok.str; | 
 |       scan (TOK_RBRACKET, &tok); | 
 |     } | 
 |   else if (peekscan (TOK_LANGLE, &tok)) | 
 |     { | 
 |       if (dec->rel == REL_POINTER) | 
 | 	{ | 
 | 	  error ("no array-of-pointer declarations -- use typedef"); | 
 | 	} | 
 |       dec->rel = REL_ARRAY; | 
 |       if (peekscan (TOK_RANGLE, &tok)) | 
 | 	{ | 
 | 	  dec->array_max = "~0";	/* unspecified size, use max */ | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  scan_num (&tok); | 
 | 	  dec->array_max = tok.str; | 
 | 	  scan (TOK_RANGLE, &tok); | 
 | 	} | 
 |     } | 
 |   if (streq (dec->type, "opaque")) | 
 |     { | 
 |       if (dec->rel != REL_ARRAY && dec->rel != REL_VECTOR) | 
 | 	{ | 
 | 	  error ("array declaration expected"); | 
 | 	} | 
 |     } | 
 |   else if (streq (dec->type, "string")) | 
 |     { | 
 |       if (dec->rel != REL_ARRAY) | 
 | 	{ | 
 | 	  error ("variable-length array declaration expected"); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | get_prog_declaration (declaration * dec, defkind dkind, int num /* arg number */ ) | 
 | { | 
 |   token tok; | 
 |   char name[10];		/* argument name */ | 
 |  | 
 |   if (dkind == DEF_PROGRAM) | 
 |     { | 
 |       peek (&tok); | 
 |       if (tok.kind == TOK_RPAREN) | 
 | 	{			/* no arguments */ | 
 | 	  dec->rel = REL_ALIAS; | 
 | 	  dec->type = "void"; | 
 | 	  dec->prefix = NULL; | 
 | 	  dec->name = NULL; | 
 | 	  return; | 
 | 	} | 
 |     } | 
 |   get_type (&dec->prefix, &dec->type, dkind); | 
 |   dec->rel = REL_ALIAS; | 
 |   if (peekscan (TOK_IDENT, &tok))	/* optional name of argument */ | 
 |     strcpy (name, tok.str); | 
 |   else | 
 |     sprintf (name, "%s%d", ARGNAME, num);	/* default name of argument */ | 
 |  | 
 |   dec->name = (char *) strdup (name); | 
 |  | 
 |   if (streq (dec->type, "void")) | 
 |     { | 
 |       return; | 
 |     } | 
 |  | 
 |   if (streq (dec->type, "opaque")) | 
 |     { | 
 |       error ("opaque -- illegal argument type"); | 
 |     } | 
 |   if (peekscan (TOK_STAR, &tok)) | 
 |     { | 
 |       if (streq (dec->type, "string")) | 
 | 	{ | 
 | 	  error ("pointer to string not allowed in program arguments\n"); | 
 | 	} | 
 |       dec->rel = REL_POINTER; | 
 |       if (peekscan (TOK_IDENT, &tok))	/* optional name of argument */ | 
 | 	dec->name = strdup (tok.str); | 
 |     } | 
 |   if (peekscan (TOK_LANGLE, &tok)) | 
 |     { | 
 |       if (!streq (dec->type, "string")) | 
 | 	{ | 
 | 	  error ("arrays cannot be declared as arguments to procedures -- use typedef"); | 
 | 	} | 
 |       dec->rel = REL_ARRAY; | 
 |       if (peekscan (TOK_RANGLE, &tok)) | 
 | 	{ | 
 | 	  dec->array_max = "~0";	/* unspecified size, use max */ | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  scan_num (&tok); | 
 | 	  dec->array_max = tok.str; | 
 | 	  scan (TOK_RANGLE, &tok); | 
 | 	} | 
 |     } | 
 |   if (streq (dec->type, "string")) | 
 |     { | 
 |       if (dec->rel != REL_ARRAY) | 
 | 	{			/* .x specifies just string as | 
 | 				 * type of argument | 
 | 				 * - make it string<> | 
 | 				 */ | 
 | 	  dec->rel = REL_ARRAY; | 
 | 	  dec->array_max = "~0";	/* unspecified size, use max */ | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | get_type (const char **prefixp, const char **typep, defkind dkind) | 
 | { | 
 |   token tok; | 
 |  | 
 |   *prefixp = NULL; | 
 |   get_token (&tok); | 
 |   switch (tok.kind) | 
 |     { | 
 |     case TOK_IDENT: | 
 |       *typep = tok.str; | 
 |       break; | 
 |     case TOK_STRUCT: | 
 |     case TOK_ENUM: | 
 |     case TOK_UNION: | 
 |       *prefixp = tok.str; | 
 |       scan (TOK_IDENT, &tok); | 
 |       *typep = tok.str; | 
 |       break; | 
 |     case TOK_UNSIGNED: | 
 |       unsigned_dec (typep); | 
 |       break; | 
 |     case TOK_SHORT: | 
 |       *typep = "short"; | 
 |       (void) peekscan (TOK_INT, &tok); | 
 |       break; | 
 |     case TOK_LONG: | 
 |       *typep = "long"; | 
 |       (void) peekscan (TOK_INT, &tok); | 
 |       break; | 
 |     case TOK_HYPER: | 
 |       *typep = "quad_t"; | 
 |       (void) peekscan(TOK_INT, &tok); | 
 |       break; | 
 |     case TOK_VOID: | 
 |       if (dkind != DEF_UNION && dkind != DEF_PROGRAM) | 
 | 	{ | 
 | 	  error ("voids allowed only inside union and program definitions with one argument"); | 
 | 	} | 
 |       *typep = tok.str; | 
 |       break; | 
 |     case TOK_STRING: | 
 |     case TOK_OPAQUE: | 
 |     case TOK_CHAR: | 
 |     case TOK_INT: | 
 |     case TOK_FLOAT: | 
 |     case TOK_DOUBLE: | 
 |     case TOK_BOOL: | 
 |       *typep = tok.str; | 
 |       break; | 
 |     default: | 
 |       error ("expected type specifier"); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | unsigned_dec (const char **typep) | 
 | { | 
 |   token tok; | 
 |  | 
 |   peek (&tok); | 
 |   switch (tok.kind) | 
 |     { | 
 |     case TOK_CHAR: | 
 |       get_token (&tok); | 
 |       *typep = "u_char"; | 
 |       break; | 
 |     case TOK_SHORT: | 
 |       get_token (&tok); | 
 |       *typep = "u_short"; | 
 |       (void) peekscan (TOK_INT, &tok); | 
 |       break; | 
 |     case TOK_LONG: | 
 |       get_token (&tok); | 
 |       *typep = "u_long"; | 
 |       (void) peekscan (TOK_INT, &tok); | 
 |       break; | 
 |     case TOK_HYPER: | 
 |       get_token (&tok); | 
 |       *typep = "u_quad_t"; | 
 |       (void) peekscan(TOK_INT, &tok); | 
 |       break; | 
 |     case TOK_INT: | 
 |       get_token (&tok); | 
 |       *typep = "u_int"; | 
 |       break; | 
 |     default: | 
 |       *typep = "u_int"; | 
 |       break; | 
 |     } | 
 | } |