*.loT
portable-rpcgen
remote_protocol.x
+remote_protocol.c
+remote_protocol.h
rpcgen_parse.c
rpcgen_parse.h
rpcgen_scan.c
+ACLOCAL_AMFLAGS = -I m4
+
nobase_include_HEADERS = rpc/rpc.h rpc/types.h rpc/xdr.h
lib_LTLIBRARIES = libportablexdr.la
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
--- /dev/null
+#! /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 <tromey@cygnus.com>.
+#
+# 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 <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+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 <bug-automake@gnu.org>.
+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:
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.
--- /dev/null
+/* -*- 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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);
+ }
+}
--- /dev/null
+/* -*- 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#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 <stdint.h>\n"
+ "#include <rpc/rpc.h>\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;
+ }
+}
#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>; (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);
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 */
#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
/*-- 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
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);
}
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");
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);
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
{
va_list arg;
+ if (output_filename && unlink_output_filename)
+ unlink (output_filename);
+
if (input_filename == NULL)
fputs (PACKAGE, stderr);
else
va_list arg;
int e = errno;
+ if (output_filename && unlink_output_filename)
+ unlink (output_filename);
+
if (input_filename == NULL)
fputs (PACKAGE, stderr);
else
%union {
char *str;
+ struct type *type;
+ struct decl *decl;
+ struct enum_value *enum_value;
+ struct union_case *union_case;
+ struct cons *list;
}
+%type <type> type_ident
%type <str> const
+%type <decl> decl
+%type <decl> simple_decl fixed_array_decl variable_array_decl pointer_decl
+%type <decl> string_decl
+%type <enum_value> enum_value
+%type <union_case> union_case
+%type <list> decls enum_values union_cases
%token STRUCT
%token ENUM
%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
;
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
| 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); }
;
%%
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:]]+
if (filename == NULL) perrorf ("malloc");
if (sscanf (yytext+2, "%d \"%[^\"]\"", &lineno, filename) == 2) {
- yylineno = lineno - 1;
+ yylineno = lineno;
free (input_filename);
input_filename = filename;
}
double return DOUBLE;
string return STRING;
opaque return OPAQUE;
+bool return BOOL;
void return VOID;