From 1b9cc11ece64ac12f63e6c96e32b404b32fb0f32 Mon Sep 17 00:00:00 2001 From: rjones Date: Wed, 7 Jan 2009 19:38:52 +0000 Subject: [PATCH] Header generation working. --- .cvsignore | 2 + Makefile.am | 4 +- compile | 142 +++++++++++++++++++++++ configure.ac | 7 +- m4/.cvsignore | 0 rpcgen_ast.c | 147 ++++++++++++++++++++++++ rpcgen_codegen.c | 337 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ rpcgen_int.h | 96 ++++++++++++++++ rpcgen_main.c | 115 +++++++++++++++---- rpcgen_parse.y | 100 ++++++++++++++++- rpcgen_scan.l | 6 +- 11 files changed, 930 insertions(+), 26 deletions(-) create mode 100755 compile create mode 100644 m4/.cvsignore create mode 100644 rpcgen_ast.c create mode 100644 rpcgen_codegen.c diff --git a/.cvsignore b/.cvsignore index 3719ab1..987e85c 100644 --- a/.cvsignore +++ b/.cvsignore @@ -23,6 +23,8 @@ depcomp *.loT portable-rpcgen remote_protocol.x +remote_protocol.c +remote_protocol.h rpcgen_parse.c rpcgen_parse.h rpcgen_scan.c diff --git a/Makefile.am b/Makefile.am index fb0fcb3..bb251c2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,5 @@ +ACLOCAL_AMFLAGS = -I m4 + nobase_include_HEADERS = rpc/rpc.h rpc/types.h rpc/xdr.h lib_LTLIBRARIES = libportablexdr.la @@ -14,6 +16,6 @@ BUILT_SOURCES = rpcgen_parse.h AM_YFLAGS = -d bin_PROGRAMS = portable-rpcgen portable_rpcgen_SOURCES = rpcgen_parse.y rpcgen_scan.l \ - rpcgen_int.h rpcgen_main.c + rpcgen_int.h rpcgen_main.c rpcgen_ast.c rpcgen_codegen.c portable_rpcgen_CFLAGS = -Wall #portable_rpcgen_CFLAGS += -DYYDEBUG diff --git a/compile b/compile new file mode 100755 index 0000000..1b1d232 --- /dev/null +++ b/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/configure.ac b/configure.ac index 95d2f2b..97ac4bf 100644 --- a/configure.ac +++ b/configure.ac @@ -3,15 +3,20 @@ AM_INIT_AUTOMAKE AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + AC_CANONICAL_HOST AC_PROG_CC -AC_CHECK_PROGS(AR, ar) +AM_PROG_CC_C_O + AC_PROG_INSTALL AC_PROG_LIBTOOL AC_PROG_LEX AC_PROG_YACC +AC_CHECK_PROGS(AR, ar) + dnl Look for an external 'cpp' program which can run on a file with any dnl extension. The normal CPP can only run on files with a '.c' dnl extension, therefore we prefer to use /usr/bin/cpp if it exists. diff --git a/m4/.cvsignore b/m4/.cvsignore new file mode 100644 index 0000000..e69de29 diff --git a/rpcgen_ast.c b/rpcgen_ast.c new file mode 100644 index 0000000..e1caa99 --- /dev/null +++ b/rpcgen_ast.c @@ -0,0 +1,147 @@ +/* -*- C -*- + * rpcgen - Generate XDR bindings automatically. + * Copyright (C) 2008 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include + +#include "rpcgen_int.h" + +struct type * +new_type (enum type_enum type, int sgn, char *ident, char *len) +{ + struct type *r = malloc (sizeof *r); + r->type = type; + r->sgn = sgn; + r->ident = ident; + r->len = len; + return r; +} + +void +free_type (struct type *t) +{ + if (t) { + free (t->ident); + free (t->len); + free (t); + } +} + +struct decl * +new_decl (enum decl_type decl_type, struct type *type, + char *ident, char *len) +{ + struct decl *r = malloc (sizeof *r); + r->decl_type = decl_type; + r->type = type; + r->ident = ident; + r->len = len; + return r; +} + +void +free_decl (struct decl *d) +{ + if (d) { + free_type (d->type); + free (d->ident); + free (d->len); + free (d); + } +} + +struct enum_value * +new_enum_value (char *ident, char *value) +{ + struct enum_value *r = malloc (sizeof *r); + r->ident = ident; + r->value = value; + return r; +} + +void +free_enum_value (struct enum_value *v) +{ + if (v) { + free (v->ident); + free (v->value); + free (v); + } +} + +struct union_case * +new_union_case (enum union_case_type type, char *const_, struct decl *decl) +{ + struct union_case *r = malloc (sizeof *r); + r->type = type; + r->const_ = const_; + r->decl = decl; + return r; +} + +void +free_union_case (struct union_case *c) +{ + if (c) { + free (c->const_); + free_decl (c->decl); + free (c); + } +} + +struct cons * +new_cons (struct cons *next, void *ptr, free_fn free) +{ + struct cons *r = malloc (sizeof *r); + r->next = next; + r->ptr = ptr; + r->free = free; + return r; +} + +static struct cons * +list_rev_append (struct cons *xs1, struct cons *xs2) +{ + if (!xs1) return xs2; + else { + struct cons *tail = xs1->next; + xs1->next = xs2; + return list_rev_append (tail, xs1); + } +} + +struct cons * +list_rev (struct cons *xs) +{ + return list_rev_append (xs, NULL); +} + +void +list_free (struct cons *xs) +{ + if (xs) { + struct cons *next = xs->next; + if (xs->free) xs->free (xs->ptr); + free (xs); + list_free (next); + } +} diff --git a/rpcgen_codegen.c b/rpcgen_codegen.c new file mode 100644 index 0000000..3184884 --- /dev/null +++ b/rpcgen_codegen.c @@ -0,0 +1,337 @@ +/* -*- C -*- + * rpcgen - Generate XDR bindings automatically. + * Copyright (C) 2008 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include + +#include "rpcgen_int.h" + +static void gen_line (void); +static void gen_decl (int indent, const struct decl *); +static void gen_type (const struct type *); + +static void +spaces (int n) +{ + int i; + + for (i = 0; i < n; ++i) + fputc (' ', yyout); +} + +/* This generates a #line directive referring back to the + * original source file. + */ +static void +gen_line (void) +{ + if (input_filename) + fprintf (yyout, "#line %d \"%s\"\n", yylineno, input_filename); +} + +static void +write_header_def (void) +{ + const char *p; + + p = strrchr (output_filename, '/') ? : output_filename; + + fputs ("RPCGEN_HEADER_", yyout); + + while (*p) { + if (isalnum (*p)) + fputc (toupper (*p), yyout); + else + fputc ('_', yyout); + ++p; + } +} + +void +gen_prologue (const char *filename) +{ + char *basename; + int len; + + fprintf (yyout, + "/* This file was generated by PortableXDR rpcgen %s\n" + " * ANY CHANGES YOU MAKE TO THIS FILE MAY BE LOST!\n" + " * The input file was %s\n" + " */\n" + "\n", + PACKAGE_VERSION, filename); + + switch (output_mode) + { + case output_c: + len = strlen (filename); + basename = malloc (len + 1); + strcpy (basename, filename); + if (len >= 2 && basename[len-2] == '.') + basename[len-2] = '\0'; + fprintf (yyout, "#include \"%s.h\"\n", basename); + free (basename); + break; + + case output_h: + fprintf (yyout, "#ifndef "); + write_header_def (); + fprintf (yyout, "\n#define "); + write_header_def (); + fprintf (yyout, + "\n" + "\n" + "#ifdef __cplusplus\n" + "extern \"C\" {\n" + "#endif\n" + "\n" + "#include \n" + "#include \n" + "\n"); + break; + } +} + +void +gen_epilogue (void) +{ + gen_line (); + + switch (output_mode) + { + case output_c: + break; + + case output_h: + fprintf (yyout, + "\n" + "#ifdef __cplusplus\n" + "}\n" + "#endif\n" + "\n" + "#endif /* "); + write_header_def (); + fprintf (yyout, " */\n"); + break; + } + + fprintf (yyout, "\n/* EOF */\n"); +} + +void +gen_const (const char *name, const char *value) +{ + if (output_mode == output_h) { + gen_line (); + + fprintf (yyout, "#define %s %s\n", name, value); + } +} + +void +gen_enum (const char *name, const struct cons *enum_values) +{ + gen_line (); + + switch (output_mode) + { + case output_h: + fprintf (yyout, "enum %s {\n", name); + while (enum_values) { + struct enum_value *enum_value = (struct enum_value *) enum_values->ptr; + if (enum_value->value) + fprintf (yyout, " %s = %s,\n", + enum_value->ident, enum_value->value); + else + fprintf (yyout, " %s,\n", enum_value->ident); + enum_values = enum_values->next; + } + fprintf (yyout, + "};\n" + "typedef enum %s %s;\n" + "extern bool_t xdr_%s (XDR *, %s *);\n" + "\n", + name, name, name, name); + break; + + case output_c: + /* XXX */ + break; + } +} + +void +gen_struct (const char *name, const struct cons *decls) +{ + gen_line (); + + switch (output_mode) + { + case output_h: + fprintf (yyout, "struct %s {\n", name); + while (decls) { + gen_decl (2, (struct decl *) decls->ptr); + decls = decls->next; + } + fprintf (yyout, + "};\n" + "typedef struct %s %s;\n" + "extern bool_t xdr_%s (XDR *, %s *);\n" + "\n", + name, name, name, name); + break; + + case output_c: + /* XXX */ + break; + } +} + +void +gen_union (const char *name, const struct decl *discrim, + const struct cons *union_cases) +{ + gen_line (); + + switch (output_mode) + { + case output_h: + fprintf (yyout, "struct %s {\n", name); + gen_decl (2, discrim); + fprintf (yyout, " union {\n"); + + while (union_cases) { + struct decl *decl = ((struct union_case *) union_cases->ptr)->decl; + if (decl) gen_decl (4, decl); + union_cases = union_cases->next; + } + fprintf (yyout, + " } %s_u;\n" + "};\n" + "typedef struct %s %s;\n" + "extern bool_t xdr_%s (XDR *, %s *);\n" + "\n", + name, name, name, name, name); + break; + + case output_c: + /* XXX */ + break; + } +} + +void +gen_typedef (const struct decl *decl) +{ + if (output_mode == output_h) { + gen_line (); + fputs ("typedef ", yyout); + gen_decl (0, decl); + fprintf (yyout, + "extern bool_t xdr_%s (XDR *, %s *);\n" + "\n", + decl->ident, decl->ident); + } +} + +static void +gen_decl (int indent, const struct decl *decl) +{ + spaces (indent); + + switch (decl->decl_type) + { + case decl_type_simple: + gen_type (decl->type); + fprintf (yyout, " %s;\n", decl->ident); + break; + + case decl_type_fixed_array: + gen_type (decl->type); + fprintf (yyout, " %s[%s];\n", decl->ident, decl->len); + break; + + case decl_type_variable_array: + fprintf (yyout, "struct {\n"); + spaces (indent+2); + fprintf (yyout, "uint32_t %s_len;\n", decl->ident); + spaces (indent+2); + gen_type (decl->type); + fprintf (yyout, " *%s_val;\n", decl->ident); + spaces (indent); + fprintf (yyout, "} %s;\n", decl->ident); + break; + + case decl_type_pointer: + gen_type (decl->type); + fprintf (yyout, " *%s;\n", decl->ident); + break; + } +} + +static void +gen_type (const struct type *type) +{ + switch (type->type) + { + case type_char: + if (type->sgn) fputs ("int8_t", yyout); + else fputs ("uint8_t", yyout); + break; + + case type_short: + if (type->sgn) fputs ("int16_t", yyout); + else fputs ("uint16_t", yyout); + break; + + case type_int: + if (type->sgn) fputs ("int32_t", yyout); + else fputs ("uint32_t", yyout); + break; + + case type_hyper: + if (type->sgn) fputs ("int64_t", yyout); + else fputs ("uint64_t", yyout); + break; + + case type_double: + fputs ("double", yyout); + break; + + case type_string: + fputs ("char *", yyout); + break; + + case type_opaque: + fputs ("char", yyout); + break; + + case type_bool: + fputs ("bool_t", yyout); + break; + + case type_ident: + fputs (type->ident, yyout); + break; + } +} diff --git a/rpcgen_int.h b/rpcgen_int.h index e372295..9271326 100644 --- a/rpcgen_int.h +++ b/rpcgen_int.h @@ -20,8 +20,98 @@ #ifndef RPCGEN_INT_H #define RPCGEN_INT_H +/* Current input file (updated by # line directives in the source). */ extern char *input_filename; +/* Current output file. */ +extern const char *output_filename; + +/* Current output mode. */ +enum output_mode { + output_c = 0, + output_h = 1, +}; +extern enum output_mode output_mode; + +/* Abstract syntax tree types. */ +enum type_enum { + type_char, type_short, type_int, type_hyper, + type_double, + type_string, type_opaque, type_bool, + type_ident, +}; + +struct type { + enum type_enum type; + int sgn; /* true if signed, false if unsigned */ + char *ident; + char *len; /* length (only for strings) */ +}; + +extern struct type *new_type (enum type_enum, int, char *, char *); +extern void free_type (struct type *); + +enum decl_type { + decl_type_simple, /* type ident; */ + decl_type_fixed_array, /* type ident[len]; */ + decl_type_variable_array, /* type ident; (len is optional) */ + decl_type_pointer, /* type *ident; */ +}; + +struct decl { + enum decl_type decl_type; + struct type *type; + char *ident; + char *len; +}; + +extern struct decl *new_decl (enum decl_type, struct type *, char *, char *); +extern void free_decl (struct decl *); + +struct enum_value { + char *ident; + char *value; +}; + +extern struct enum_value *new_enum_value (char *, char *); +extern void free_enum_value (struct enum_value *); + +enum union_case_type { + union_case_normal, /* case const: decl; */ + union_case_default_void, /* default: void; */ + union_case_default_decl, /* default: decl; */ +}; + +struct union_case { + enum union_case_type type; + char *const_; + struct decl *decl; +}; + +extern struct union_case *new_union_case (enum union_case_type, char *, struct decl *); +extern void free_union_case (struct union_case *); + +typedef void (*free_fn) (void *); + +struct cons { + struct cons *next; /* cdr/tail */ + void *ptr; /* car/head */ + free_fn free; /* free the head element */ +}; + +extern struct cons *new_cons (struct cons *, void *, free_fn); +extern struct cons *list_rev (struct cons *); +extern void list_free (struct cons *); + +/* Code generator functions. */ +extern void gen_prologue (const char *filename); +extern void gen_epilogue (void); +extern void gen_const (const char *name, const char *value); +extern void gen_enum (const char *name, const struct cons *enum_values); +extern void gen_struct (const char *name, const struct cons *decls); +extern void gen_union (const char *name, const struct decl *discrim, const struct cons *union_cases); +extern void gen_typedef (const struct decl *decl); + /* Global functions used by the scanner. */ extern void start_string (void); extern char *end_string (void); @@ -34,4 +124,10 @@ extern void error (const char *, ...) extern void perrorf (const char *, ...) __attribute__((noreturn, format(printf,1,2))); +/* Symbols exported from the scanner and parser. */ +extern FILE *yyin, *yyout; +extern int yyparse (void); +extern int yylineno; +extern int yydebug; + #endif /* RPCGEN_INT_H */ diff --git a/rpcgen_main.c b/rpcgen_main.c index 6ad467f..a2e97b7 100644 --- a/rpcgen_main.c +++ b/rpcgen_main.c @@ -29,26 +29,22 @@ #include "rpcgen_int.h" +enum output_mode output_mode; + static void print_version (void); static void usage (const char *progname); -static void do_rpcgen (const char *filename); +static void do_rpcgen (const char *filename, const char *out); static char *make_cpp_command (const char *filename); -/* Symbols exported from the scanner. */ -extern FILE *yyin, *yyout; -extern int yyparse (void); -extern int yylineno; -extern int yydebug; - int main (int argc, char *argv[]) { int opt; + char *filename; + int output_modes = 0; + char *out = NULL; - /* To enable debugging in the parser, you also need to compile - * with -DYYDEBUG - */ -#if 0 +#if YYDEBUG yydebug = 1; #endif @@ -76,9 +72,16 @@ main (int argc, char *argv[]) /*-- Options that we do support. --*/ case 'c': + output_modes |= 1 << output_c; + break; + case 'h': + output_modes |= 1 << output_h; + break; + case 'o': - ; + out = optarg; + break; /* None of the other versions of rpcgen support a way to print * the version number, which is extremely annoying because @@ -99,8 +102,25 @@ main (int argc, char *argv[]) if (optind >= argc) error ("expected name of input file after options"); - while (optind < argc) - do_rpcgen (argv[optind++]); + while (optind < argc) { + filename = argv[optind++]; + + if (output_modes == 0) { + output_mode = output_h; + do_rpcgen (filename, out); + output_mode = output_c; + do_rpcgen (filename, out); + } else { + if ((output_modes & (1 << output_h)) != 0) { + output_mode = output_h; + do_rpcgen (filename, out); + } + if ((output_modes & (1 << output_c)) != 0) { + output_mode = output_c; + do_rpcgen (filename, out); + } + } + } exit (0); } @@ -138,16 +158,58 @@ usage (const char *progname) exit (0); } +/* This is a global so the error functions can delete the output file. */ +const char *output_filename = NULL; +int unlink_output_filename; + /* Called for each input file. */ static void -do_rpcgen (const char *filename) +do_rpcgen (const char *filename, const char *out) { - char *cmd; - int r; + char *cmd, *t = NULL; + int r, len; + const char *ext; + + /* Open the output file. */ + switch (output_mode) { + case output_c: ext = ".c"; break; + case output_h: ext = ".h"; break; + default: error ("internal error in do_rpcgen / output_mode"); + } + + if (out && strcmp (out, "-") == 0) { + output_filename = NULL; + unlink_output_filename = 0; + yyout = stdout; + } + else if (out) { + output_filename = out; + unlink_output_filename = 1; + yyout = fopen (output_filename, "w"); + if (yyout == NULL) + perrorf ("%s", output_filename); + } + else { + len = strlen (filename); + t = malloc (len + 3); + if (t == NULL) + perrorf ("malloc"); + strcpy (t, filename); + if (len >= 2 && strcmp (t + len - 2, ".x") == 0) + strcpy (t + len - 2, ext); + else + strcat (t, ext); + output_filename = t; + unlink_output_filename = 1; + yyout = fopen (output_filename, "w"); + if (yyout == NULL) + perrorf ("%s", output_filename); + } free (input_filename); input_filename = NULL; + /* Make the CPP command and open a pipe. */ cmd = make_cpp_command (filename); yyin = popen (cmd, "r"); @@ -155,9 +217,9 @@ do_rpcgen (const char *filename) perrorf ("%s", cmd); free (cmd); - yyout = stdout; + gen_prologue (filename); - /* Parse the input file. This either succeeds or exits with an error. */ + /* Parse the input file, this also generates the output as a side-effect. */ r = yyparse (); pclose (yyin); @@ -166,8 +228,17 @@ do_rpcgen (const char *filename) else if (r == 2) error ("parsing failed because we ran out of memory"); + gen_epilogue (); + + if (yyout != stdout) + fclose (yyout); + output_filename = NULL; + unlink_output_filename = 0; + free (input_filename); input_filename = NULL; + + free (t); } /* Concatenate $EXTCPP and filename, and make sure the filename is @@ -270,6 +341,9 @@ error (const char *fs, ...) { va_list arg; + if (output_filename && unlink_output_filename) + unlink (output_filename); + if (input_filename == NULL) fputs (PACKAGE, stderr); else @@ -291,6 +365,9 @@ perrorf (const char *fs, ...) va_list arg; int e = errno; + if (output_filename && unlink_output_filename) + unlink (output_filename); + if (input_filename == NULL) fputs (PACKAGE, stderr); else diff --git a/rpcgen_parse.y b/rpcgen_parse.y index 04b073a..5ccc7dd 100644 --- a/rpcgen_parse.y +++ b/rpcgen_parse.y @@ -27,9 +27,21 @@ extern void yyerror (const char *str); %union { char *str; + struct type *type; + struct decl *decl; + struct enum_value *enum_value; + struct union_case *union_case; + struct cons *list; } +%type type_ident %type const +%type decl +%type simple_decl fixed_array_decl variable_array_decl pointer_decl +%type string_decl +%type enum_value +%type union_case +%type decls enum_values union_cases %token STRUCT %token ENUM @@ -50,6 +62,7 @@ extern void yyerror (const char *str); %token DOUBLE %token STRING %token OPAQUE +%token BOOL /* This is sometimes lumped together with the other types, but * the special keyword void can only occur after "default:" in @@ -73,62 +86,125 @@ stmts : stmt ';' ; stmt : ENUM IDENT '{' enum_values '}' + { + struct cons *enums = list_rev ($4); + gen_enum ($2, enums); + free ($2); + list_free (enums); + } | STRUCT IDENT '{' decls '}' + { + struct cons *decls = list_rev ($4); + gen_struct ($2, decls); + free ($2); + list_free (decls); + } | UNION IDENT SWITCH '(' decl ')' '{' union_cases '}' + { + struct cons *cases = list_rev ($8); + gen_union ($2, $5, cases); + free ($2); + free_decl ($5); + list_free (cases); + } | TYPEDEF decl + { + gen_typedef ($2); + free_decl ($2); + } | CONST IDENT '=' const + { + gen_const ($2, $4); + free ($2); + free ($4); + } | PROGRAM + { + error ("PortableXDR does not support SunRPC program statements"); + } ; /* Declarations used inside structs and unions. eg. "int foo;" */ decls : decl ';' + { $$ = new_cons (NULL, $1, (free_fn) free_decl); } | decls decl ';' + { $$ = new_cons ($1, $2, (free_fn) free_decl); } ; -decl : simple_decl +decl : string_decl + | simple_decl | fixed_array_decl | variable_array_decl | pointer_decl ; +string_decl + : STRING IDENT '<' const '>' + { + $$ = new_decl (decl_type_simple, + new_type (type_string, 0, NULL, $4), + $2, NULL); + } + | STRING IDENT '<' '>' + { + $$ = new_decl (decl_type_simple, + new_type (type_string, 0, NULL, NULL), + $2, NULL); + } + ; + simple_decl : type_ident IDENT + { $$ = new_decl (decl_type_simple, $1, $2, NULL); } ; fixed_array_decl : type_ident IDENT '[' const ']' + { $$ = new_decl (decl_type_fixed_array, $1, $2, $4); } ; variable_array_decl : type_ident IDENT '<' const '>' + { $$ = new_decl (decl_type_variable_array, $1, $2, $4); } | type_ident IDENT '<' '>' + { $$ = new_decl (decl_type_variable_array, $1, $2, NULL); } ; pointer_decl : type_ident '*' IDENT + { $$ = new_decl (decl_type_pointer, $1, $3, NULL); } ; /* Enumerations. */ enum_values : enum_value + { $$ = new_cons (NULL, $1, (free_fn) free_enum_value); } | enum_values ',' enum_value + { $$ = new_cons ($1, $3, (free_fn) free_enum_value); } ; enum_value : IDENT + { $$ = new_enum_value ($1, NULL); } | IDENT '=' const + { $$ = new_enum_value ($1, $3); } ; /* Case list inside a union. */ union_cases : union_case ';' + { $$ = new_cons (NULL, $1, (free_fn) free_union_case); } | union_cases union_case ';' + { $$ = new_cons ($1, $2, (free_fn) free_union_case); } ; union_case : CASE const ':' decl + { $$ = new_union_case (union_case_normal, $2, $4); } | DEFAULT ':' VOID + { $$ = new_union_case (union_case_default_void, NULL, NULL); } | DEFAULT ':' decl + { $$ = new_union_case (union_case_default_decl, NULL, $3); } ; /* Constants, which may be integer literals or refer to previously @@ -139,26 +215,44 @@ const : INTLIT | IDENT ; -/* Types. */ +/* Types. Note 'string' and 'void' are handled by special cases above. */ type_ident : CHAR + { $$ = new_type (type_char, 1, NULL, NULL); } | SIGNED CHAR + { $$ = new_type (type_char, 1, NULL, NULL); } | UNSIGNED CHAR + { $$ = new_type (type_char, 0, NULL, NULL); } | SHORT + { $$ = new_type (type_short, 1, NULL, NULL); } | SIGNED SHORT + { $$ = new_type (type_short, 1, NULL, NULL); } | UNSIGNED SHORT + { $$ = new_type (type_short, 0, NULL, NULL); } | INT + { $$ = new_type (type_int, 1, NULL, NULL); } | SIGNED INT + { $$ = new_type (type_int, 1, NULL, NULL); } | UNSIGNED INT + { $$ = new_type (type_int, 0, NULL, NULL); } | HYPER + { $$ = new_type (type_hyper, 1, NULL, NULL); } | SIGNED HYPER + { $$ = new_type (type_hyper, 1, NULL, NULL); } | UNSIGNED HYPER + { $$ = new_type (type_hyper, 0, NULL, NULL); } | SIGNED + { $$ = new_type (type_int, 1, NULL, NULL); } | UNSIGNED + { $$ = new_type (type_int, 0, NULL, NULL); } | DOUBLE - | STRING + { $$ = new_type (type_double, 0, NULL, NULL); } | OPAQUE + { $$ = new_type (type_opaque, 0, NULL, NULL); } + | BOOL + { $$ = new_type (type_bool, 0, NULL, NULL); } | IDENT + { $$ = new_type (type_ident, 0, $1, NULL); } ; %% diff --git a/rpcgen_scan.l b/rpcgen_scan.l index 061dbbf..4ab278d 100644 --- a/rpcgen_scan.l +++ b/rpcgen_scan.l @@ -29,7 +29,8 @@ HEXLIT "0x"[0-9a-fA-F]+ DECLIT 0|[1-9][0-9]* -INTLIT {HEXLIT}|{DECLIT} +OCTLIT 0[0-7]+ +INTLIT {HEXLIT}|{DECLIT}|{OCTLIT} IDENT [a-zA-Z_][a-zA-Z_0-9]* WS [[:space:]]+ @@ -51,7 +52,7 @@ WS [[:space:]]+ if (filename == NULL) perrorf ("malloc"); if (sscanf (yytext+2, "%d \"%[^\"]\"", &lineno, filename) == 2) { - yylineno = lineno - 1; + yylineno = lineno; free (input_filename); input_filename = filename; } @@ -136,6 +137,7 @@ hyper return HYPER; double return DOUBLE; string return STRING; opaque return OPAQUE; +bool return BOOL; void return VOID; -- 1.8.3.1