Commit af40e0ce authored by Kurt Zeilenga's avatar Kurt Zeilenga
Browse files

The world is STDC.

parent 92b28cf3
# @(#) Makefile 1.6 93/06/18 22:29:40
# In the unlikely case that your compiler has no hooks for alternate
# compiler passes, use a "cc cflags -E file.c | unproto >file.i"
# pipeline, then "cc cflags -c file.i" to compile the resulting
# intermediate file.
# Otherwise, the "/lib/cpp | unproto" pipeline can be packaged as an
# executable shell script (see the provided "" script) that should
# be installed as "/whatever/cpp". This script should then be specified
# to the C compiler as a non-default preprocessor.
# PROG = unproto
# PIPE =
# The overhead and problems of shell script interpretation can be
# eliminated by having the unprototyper program itself open the pipe to
# the preprocessor. In that case, define the PIPE_THROUGH_CPP macro as
# the path name of the default C preprocessor (usually "/lib/cpp"),
# install the unprototyper as "/whatever/cpp" and specify that to the C
# compiler as a non-default preprocessor.
PROG = cpp
PIPE = -DPIPE_THROUGH_CPP=\"/lib/cpp\"
# Some compilers complain about some #directives. The following is only a
# partial solution, because the directives are still seen by /lib/cpp.
# Be careful with filtering out #pragma, because some pre-ANSI compilers
# (SunOS) rely on its use.
# SKIP = -DIGNORE_DIRECTIVES=\"pragma\",\"foo\",\"bar\"
# The bell character code depends on the character set. With ASCII, it is
# 7. Specify a string constant with exactly three octal digits. If you
# change this definition, you will have to update the example.out file.
BELL = -DBELL=\"007\"
# Some C compilers have problems with "void". The nature of the problems
# depends on the age of the compiler.
# If your compiler does not understand "void" at all, compile with
# -DMAP_VOID. The unprototyper will replace "void *" by "char *", a
# (void) argument list by an empty one, and will replace all other
# instances of "void" by "int".
# If your compiler has problems with "void *" only, compile with
# -DMAP_VOID_STAR. The unprototyper will replace "void *" by "char *",
# and will replace a (void) argument list by an empty one. All other
# instances of "void" will be left alone.
# If neither of these are defined, (void) argument lists will be replaced
# by empty ones.
# Now that we have brought up the subject of antique C compilers, here's
# a couple of aliases that may be useful, too.
# ALIAS = -Dstrchr=index
# If you need support for functions that implement ANSI-style variable
# length argument lists, edit the stdarg.h file provided with this
# package so that it contains the proper definitions for your machine.
SHELL = /bin/sh
CFILES = unproto.c tok_io.c tok_class.c tok_pool.c vstring.c symbol.c error.c \
hash.c strsave.c
HFILES = error.h token.h vstring.h symbol.h
SAMPLES = stdarg.h stddef.h stdlib.h varargs.c example.c example.out
FILES = $(SOURCES) unproto.1
OBJECTS = tok_io.o tok_class.o tok_pool.o unproto.o vstring.o symbol.o error.o \
hash.o strsave.o
#CFLAGS = -O $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS) -p -Dstatic=
$(CC) $(CFLAGS) -o $@ $(OBJECTS) $(MALLOC)
# For linting, enable all bells and whistles.
lint -DPIPE_THROUGH_CPP=\"foo\" -DIGNORE_DIRECTIVES=\"foo\",\"bar\" \
# Testing requires that the program is compiled with -DDEBUG.
test: $(PROG) cpp example.c example.out
./cpp example.c >example.tmp
@echo the following diff command should produce no output
diff -b example.out example.tmp
rm -f example.tmp
shar: $(FILES)
@shar $(FILES)
rm -f *.o core cpp unproto mon.out varargs.o varargs example.tmp
error.o : error.c token.h error.h Makefile
hash.o : hash.c Makefile
strsave.o : strsave.c error.h Makefile
symbol.o : symbol.c error.h token.h symbol.h Makefile
tok_class.o : tok_class.c error.h vstring.h token.h symbol.h Makefile
tok_io.o : tok_io.c token.h vstring.h error.h Makefile
tok_pool.o : tok_pool.c token.h vstring.h error.h Makefile
unproto.o : unproto.c vstring.h stdarg.h token.h error.h symbol.h Makefile
varargs.o : varargs.c stdarg.h Makefile
vstring.o : vstring.c vstring.h Makefile
@(#) README 1.6 93/06/18 22:29:34
unproto - Compile ANSI C with traditional UNIX C compiler
This is a filter that sits in between the UNIX C preprocessor and the
next UNIX C compiler stage, on the fly transforming ANSI C syntax to
old C syntax. Line number information is preserved so that compiler
diagnostics still make sense. It runs at roughly the same speed as
/lib/cpp, so it has negligible impact on compilation time.
Typically, the program is invoked by the native UNIX C compiler as an
alternate preprocessor. The unprototyper in turn invokes the native C
preprocessor and massages its output. Similar tricks can be used with
the lint(1) command. Details are given below.
The filter rewrites ANSI-style function headings, function pointer
types and type casts, function prototypes, and combinations thereof.
Unlike some other unprototypers, this one is fully recursive and does
not depend on source file layout (see the example.c file).
Besides the rewriting of argument lists, the program does the following
transformations: string concatenation, conversion of \a and \x escape
sequences to their octal equivalents, translation of the __TIME__ and
__DATE__ macros, optional mapping of `void *' to `char *', and optional
mapping of plain `void' to `int'.
The unprototyper provides hooks for compilers that require special
tricks for variadic functions (fortunately, many don't). <stdarg.h>
support is provided for sparc, mips, mc68k, 80x86, vax, and others.
The program has been tested with SunOS 4.1.1 (sparc), Ultrix 4.0 and
4.2 (mips), and Microport System V Release 2 (80286). It should work
with almost every PCC-based UNIX C compiler.
A description of restrictions and workarounds can be found in the
unproto.1 manual page.
Problems fixed with this release:
Prototypes and definitions of functions returning pointer to function
were not rewritten to old style.
This package implements a non-default C preprocessor (the output from
the default C preprocessor being piped through the unprototyper). How
one tells the C compiler to use a non-default preprocessor program is
somewhat compiler-dependent:
SunOS 4.x: cc -Qpath directory_with_alternate_cpp ...
Ultrix 4.x: cc -tp -hdirectory_with_alternate_cpp -B ...
System V.2: cc -Bdirectory_with_alternate_cpp/ -tp ...
Examples of these, and others, can be found in the shell script
that emulates an ANSI C compiler. Your C compiler manual page should
provide the necessary information.
A more portable, but less efficient, approach relies on the observation
that almost every UNIX C compiler supports the -E (write preprocessor
output to stdout) and -P options (preprocess file.c into file.i). Just
add the following lines to your Makefiles:
$(CC) $(CFLAGS) -E $*.c | unproto >$*.i # simulate -P option
$(CC) $(CFLAGS) -c $*.i
rm -f $*.i
On some systems the lint(1) command is just a shell script, and writing
a version that uses the unprototyper should not be too hard. With SunOS
4.x, /usr/bin/lint is not a shell script, but it does accept the same
syntax as the cc(1) command for the specification of a non-default
compiler pass.
You may have to do some research on the lint command provided with your
own machine.
Check the contents of the `stdarg.h' file provided with this package.
This file serves a dual purpose: (1) on systems that do not provide a
stdarg.h file, it should be included by C source files that implements
ANSI-style variadic functions; (2) it is also used to configure the
unprototyper so that it emits the proper magic when it sees `...'.
The `stdarg.h' file has support for sparc, mips, and for compilers that
pass arguments via the stack (typical for 80*86, mc68k and vax). It
gives general hints for other compilers.
The other sample header files (stddef.h and stdlib.h) are not required
to build the unprototyper.
The `varargs.c' file provided with this package can be used to verify
that the `stdarg.h' file has been set up correctly.
If your C compiler has no hooks for an alternate preprocessor (the
unprototyper will be used as: `cc cflags -E file.c | unproto >file.i'),
build the `unproto' executable without the `PIPE_THROUGH_CPP' feature.
Details are given in the Makefile.
Otherwise, the `' shell script can be used to set up the pipe
between the native C preprocessor and the unprototyper command. The
script assumes that the unprototyper binary is called `unproto', and
that it was compiled without the `PIPE_THROUGH_CPP' feature. See the
Makefile and the `' script for details and for a description of
possible problems with this approach.
The overhead and problems of shell-script interpretation can be avoided
by letting the unprototyper itself pipe its standard input through the
C preprocessor. For this mode of operation, the unprototyper binary
should be called `cpp', and the `unproto.c' source file should be
compiled with the `PIPE_THROUGH_CPP' macro defined as the absolute
pathname of the native C preprocessor (usually `/lib/cpp'). See the
Makefile for details.
Install the `unproto.1' manual page in a suitable place. If your system
does not provide a `stdarg.h' file, find a suitable place for the one
provided with the unprototyper and install it there. The same goes for
the sample stddef.h and stdlib.h files; make sure that the definitions
in there apply to your environment. Most or all of the latter files are
already part of Ultrix 4.x and SunOS 4.1.1.
The ANSI float.h and limits.h files can be generated with the config
program by Steve Pemberton (comp.sources.misc volume 10, issue 62,
available from as comp.sources.misc/volume10/config42.Z).
If you run the unprototyper with "cc -E" just install the `unproto'
binary; the `cpp' and `acc' shell scripts will not be needed.
If you use the `cpp' shell script to pipe the preprocessor output
through the unprototyper program, install the `unproto' binary in a
place where the `cpp' shell script can find it, and install the `cpp'
shell script in a suitable place. Edit the `acc' shell script and
install it in a suitable place. From now on, type `acc' instead of
If the unprototyper itself opens the pipe to the C preprocessor (i.e.
the unprototyper was built with the `PIPE_THROUGH_CPP' macro defined),
install the `cpp' unprototyper binary in a suitable place. Edit the
`acc' shell script and install it in a suitable place. From now on,
type `acc' instead of `cc'.
Wietse Venema
Mathematics and Computing Science
Eindhoven University of Technology
The Netherlands
# @(#) 1.1 93/06/18 22:29:42
# Script to emulate most of an ANSI C compiler with a traditional UNIX
# C compiler.
# INCDIR should be the directory with auxiliary include files from the
# unproto source distribution (stdarg.h, stdlib.h, stddef.h, and other
# stuff that is missing from your compilation environment). With Ultrix
# 4.[0-2] you need unproto's stdarg.h even though the system provides
# one.
# CPPDIR should be the directory with the unprototypeing cpp filter
# (preferably the version with the PIPE_THROUGH_CPP feature).
# DEFINES: you will want to define volatile and const, and maybe even
# __STDC__.
DEFINES="-Dvolatile= -Dconst= -D__STDC__"
# Possible problem: INCDIR should be listed after the user-specified -I
# command-line options, not before them as we do here. This is a problem
# only if you attempt to redefine system libraries.
# Choose one of the commands below that is appropriate for your system.
exec cc -Qpath ${CPPDIR} -I${INCDIR} ${DEFINES} "$@" # SunOS 4.x
exec cc -tp -h${CPPDIR} -B -I${INCDIR} ${DEFINES} "$@" # Ultrix 4.2
exec cc -Yp,${CPPDIR} -I${INCDIR} ${DEFINES} "$@" # M88 SysV.3
exec cc -B${CPPDIR}/ -tp -I${INCDIR} ${DEFINES} "$@" # System V.2
# @(#) 1.3 92/01/15 21:53:22
# Unprototypeing preprocessor for pre-ANSI C compilers. On some systems,
# this script can be as simple as:
# /lib/cpp "$@" | unproto
# However, some cc(1) drivers specify output file names on the
# preprocessor command line, so this shell script must be prepared to
# intercept them. Depending on the driver program, the cpp options may
# even go before or after the file name argument(s). The script below
# tries to tackle all these cases.
# You may want to add -Ipath_to_stdarg.h_file, -Dvoid=, -Dvolatile=,
# and even -D__STDC__.
while :
case $1 in
"") break;;
-*) cpp_args="$cpp_args $1";;
*) cpp_args="$cpp_args $1"
case $2 in
""|-*) ;;
*) exec 1> $2 || exit 1; shift;;
/lib/cpp $cpp_args | unproto
/* error 3
/* diagnostics
/* unproto
/* #include "error.h"
/* int errcount;
/* void error(text)
/* char *text;
/* void error_where(path, line, text)
/* char *path;
/* int line;
/* char *text;
/* void fatal(text)
/* char *text;
/* The routines in this file print a diagnostic (text). Some also
/* terminate the program. Upon each error*() call, the errcount variable
/* is incremented.
/* error() provides a default context, i.e. the source-file
/* coordinate of the last read token.
/* error_where() allows the caller to explicitly specify context: path
/* is a source-file name, and line is a line number.
/* fatal() is like error() but terminates the program with a non-zero
/* exit status.
/* context is ignored if the line number is zero or if the path
/* is an empty string.
/* Wietse Venema
/* Eindhoven University of Technology
/* Department of Mathematics and Computer Science
/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/* 92/01/15 21:53:10
/* 1.2
static char error_sccsid[] = "@(#) error.c 1.2 92/01/15 21:53:10";
/* C library */
#include <stdio.h>
extern void exit();
/* Application-specific stuff */
#include "token.h"
#include "error.h"
int errcount = 0; /* error counter */
/* error - report problem (implicit context) */
void error(text)
char *text;
error_where(in_path, in_line, text);
/* error_where - report problem (explicit context) */
void error_where(path, line, text)
char *path;
int line;
char *text;
/* Suppress context info if there is none. */
if (line && path[0])
fprintf(stderr, "%s, line %d: ", path, line);
fprintf(stderr, "%s\n", text);
/* fatal - report problem and terminate unsuccessfully */
void fatal(text)
char *text;
/* @(#) error.h 1.2 92/01/15 21:53:14 */
extern int errcount; /* error counter */
extern void error(); /* default context */
extern void error_where(); /* user-specified context */
extern void fatal(); /* fatal error */
* @(#) example.c 1.5 93/06/18 22:29:46
* Examples of things that can be done with the unproto package
typedef char *charstar;
* New-style argument list with structured argument, one field being pointer
* to function returning pointer to function with function-pointer argument
x(struct {
struct {
int (*(*foo) (int (*arg1) (double))) (float arg2);
} foo;
} baz) {
return (0);
/* New-style function-pointer declaration. */
int (*(*bar0) (float)) (int);
/* Old-style argument list with new-style argument type. */
int (*(*bar) (float)) (int);
* New-style argument list with new-style argument type, declaration
* embedded within block. Plus a couple assignments with function calls that
* look like casts.
foo(int (*(*bar) (float)) (int))
int (*baz) (int) = (int (*) (int)) 0,
y = (y * (*baz) (y)),
*(*z) (int) = (int *(*) (int)) 0;
struct { int (*foo)(int); } *(*s)(int) =
(struct { int (*foo)(int); } *(*)(int)) 0;
y = (y * (*baz) (y));
z = (int *(*) (int)) 0;
s = (struct { int (*foo)(int); } *(*)(int)) 0;
return (0);
/* Multiple declarations in one statement */
int foo2,*(*(*bar)(int))(float),*baz(double);
/* Discriminate declarations from executable statements */
test2(charstar y)
int foo = 5,atoi(charstar);
foo = 5,atoi(y);
/* Declarations without explicit type */
test5(int y)
test7(int x)
/* Checking a complicated cast */
struct {
struct {
int (*f)(int), o;
} bar;
} (*baz2)(int) = (struct { struct { int (*f)(int), o; } bar; } (*)(int)) 0;
/* Distinguish things with the same shape but with different meaning */
struct {
int foo;
} bar(charstar);
do {
int foo;
} while (x);
/* Do not think foo(*bar) is a function pointer declaration */
test9(char *bar)
/* another couple of special-cased words. */
test10(int x)
int test10(int);
do test10(x);
while (x);
return test10(x);
test11(int *x)
while (*x)
test11a(int *x)
for (*x;;)
/* #include directive between stuff that requires lookahead */
char *x = "\xf\0002\002\02\2" /* foo */
#include "/dev/null"
printf("foo" /* 1 */ "bar" /* 2 */ "baz");
*x = '\a';
*x = '\xff';
int test13(void);