/* * 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 #include #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[MAXLINESIZE]; /* 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; } }