|  | /* | 
|  | * 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; | 
|  | } | 
|  | } |