| /* |
| * Copyright (c) 2009, Sun Microsystems, 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: |
| * - 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 Sun Microsystems, 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. |
| */ |
| |
| #if 0 |
| static char sccsid[] = "@(#)rpc_parse.c 1.8 89/02/22 (C) 1987 SMI"; |
| #endif |
| |
| /* |
| * 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" |
| |
| #define ARGNAME "arg" |
| |
| /* |
| extern char *make_argname(); |
| extern char *strdup(); |
| */ |
| |
| 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(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(char **prefixp, char **typep, defkind dkind); |
| static void unsigned_dec(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 **tailp; |
| |
| 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(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)); |
| } |
| |
| 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 char* reserved_words[] = |
| { |
| "array", |
| "bytes", |
| "destroy", |
| "free", |
| "getpos", |
| "inline", |
| "pointer", |
| "reference", |
| "setpos", |
| "sizeof", |
| "union", |
| "vector", |
| NULL |
| }; |
| |
| static 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(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) |
| { |
| 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(char **prefixp, 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_INT32: |
| *typep = "int32_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(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_INT32: |
| get_token(&tok); |
| *typep = "u_int32_"; |
| (void) peekscan(TOK_INT, &tok); |
| break; |
| case TOK_INT: |
| get_token(&tok); |
| *typep = "u_int"; |
| break; |
| default: |
| *typep = "u_int"; |
| break; |
| } |
| } |