hardin@eecea.eece.ksu.edu (David Hardin) (02/08/89)
Before I dive in, I would first like to thank AST for the EM interpreter source. It allowed me to get my AAMP code generator (almost) done. For any of you writing backends for the MINIX C compiler, the EM interpreter is a *must*. The compiler documentation is just not complete enough. Anyway, I have been reading the POSIX discussion with some interest. I got the POSIX text a while back, and have recently been scanning the portions having to do with C. Section 2.2.3 is especially interesting (as legalese goes, that is): "Although IEEE Std 1003.1-1988 references parts of the C Standard ... conformance to the C Standard is unnecessary for conformance to [POSIX] .... Any C Language implementation providing the facilities stipulated in Chapter 8 may claim conformance -- however, it shall clearly state that its C does not conform to the C Standard." So, in other words, an ANSI Standard C is strongly recommended. Is an ANSI C planned for MINIX 2.0? If so, will the compiler still use EM as its intermediate form, or will another approach be taken? Those of us who have a substantial time investment in EM are curious. BTW, I now have access to ACK, which strengthens my interest in EM. While we're on the subject of the C compiler, would it be possible to get UniPress to agree to sell an "ugrade kit" for future compiler upgrades at a reduced cost, as Prentice-Hall will be doing for MINIX Real Soon Now? Thanks in advance for any comments, David -- David Hardin Rockwell International M/S 124-211, 400 Collins Rd. NE INTERNET: hardin@eecea.eece.ksu.edu Cedar Rapids, IA 52498 UUCP: {pyramid,ucsd}!ncr-sd!ncrwic!ksuvax1!eecea!hardin
ast@cs.vu.nl (Andy Tanenbaum) (02/10/89)
In article <552@eecea.eece.ksu.edu> hardin@eecea.eece.ksu.edu (David Hardin) writes: >So, in other words, an ANSI Standard C is strongly recommended. Is an ANSI >C planned for MINIX 2.0? If so, will the compiler still use EM No. We have one, but it is too big for the PC. I'll have to stick with the current compiler. It does use EM, as do all our other compilers, however. Andy Tanenbaum (ast@cs.vu.nl)
agc@nixbln.UUCP (02/20/89)
EM >No. We have one, but it is too big for the PC. I'll have to stick with the >current compiler. It does use EM, as do all our other compilers, however. > > > Andy Tanenbaum (ast@cs.vu.nl) Hello everyone, Here's an (almost) ANSI-C conforming pre-processor. Please note that I haven't tested it under Minix. Please also note that there are two shell archives here. Now, how do I post this using notes? Regards, Alistair G. Crooks, Joypace Ltd., 2 Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 580 753114) UUCP Europe: ...!mcvax!unido!nixpbe!nixbln!agc UUCP the rest of the world: ...!uunet!linus!nixbur!nixpbe!nixbln!agc #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./agcpp.1` then echo "writing ./agcpp.1" cat > ./agcpp.1 << '\Rogue\Monster\' .TH AGCPP 1-local .SH NAME agcpp \- a C preprocessor, and ANSI C to Kernighan and Ritchie C translator .SH SYNOPSIS .B agcpp [ option ... .B ] .B [ ifile .B [ ofile .B ] ] .SH DESCRIPTION .PP .I Agcpp\^ can be used as an ordinary C preprocessor, and I have tried to make it conform to the ANSI C draft specification, as far as I can understand it. It will also take ANSI C, and turn it into Kernighan and Ritchie C, with a one exception and one restriction as detailed below. .PP .I Agcpp\^ optionally accepts two file names as arguments. .I Ifile\^ and .I ofile\^ are respectively the input and output for the preprocessor. They default to standard input and standard output if not supplied. .PP The following arguments are recognised: .TP .B \-ANSI produce ansi output from the preprocessor for the underlying compiler - this means that const, volatile and signed will be passed on, and that function prototypes and new-style function arguments will be passed on to the compiler. .TP .B \-P Preprocess the input without producing the line control information used by the next pass of the C compiler. .TP .BI \-U name\^ Remove any initial definition of .IR name , It is not an error if name is not defined. .TP .BI \-D name\^ .PD 0 .TP .BI \-D name=def\^ Define .I name\^ as if by a .B #define directive. If no .I =def\^ is given, .I name\^ is defined as 1. .PD .TP .BI \-I dir\^ Change the algorithm for searching for .B #include files whose names do not begin with \f3/\fP to look in .I dir\^ before looking in the directories on the standard list. Thus, .B #include files whose names are enclosed in \f3"\|"\fP will be searched for first in the directory of the .I ifile\^ argument, then in directories named in .B \-I options, and last in directories on a standard list. For .B #include files whose names are enclosed in .BR <> , the directory of the .I ifile\^ argument is not searched. .PP ANSI standard definitions that will be recognised by the preprocessor are __LINE__, __FILE__, __DATE__, __TIME__. These will expand to (respectively), the current line number in the source file, the current source file, the current date, and the current time. In addition, the definition __STDC__ will be expanded to 1. .PP .I agcpp will recognise the following directives : .TP .BI #define " name" " " token-string Replace subsequent instances of .I name\^ with .IR token-string . .TP \fB#define\fI name\fB(\fI arg\fB, ...,\fI arg\fB )\fI token-string\fR Notice that there can be no space between .I name and the .BR ( . Replace subsequent instances of .I name followed by a .BR ( , a list of comma separated tokens, and a .B ) by .I token-string where each occurrence of an .I arg in the .I token-string is replaced by the corresponding token in the comma separated list. .TP .BI #undef " name" Cause the definition of .I name (if any) to be forgotten from now on. .TP \fB#include\fI "filename" .PD 0 .TP .BI #include " " < filename > Include at this point the contents of .I filename (which will then be run through .IR cpp ). When the .BI < filename > notation is used, .I filename is only searched for in the standard places. See the .B \-I option above for more detail. .PD .TP \fB#line\fI integer-constant "filename" .I agcpp generates line information for the underlying compiler. .TP .B #endif .br Ends a section of lines begun by a test directive .RB ( #if , .BR #ifdef , or .BR #ifndef ). Each #endif must match a previous #if, #ifdef, #ifndef or #elif. .TP .BI #ifdef " name" The lines following will appear in the output if and only if .I name is defined. .BI #ifndef " name" The lines following will not appear in the output if and only if .I name is not defined. .TP .BI #if " constant-expression" Lines following will appear in the output if and only if the .I constant-expression evaluates to non-zero. All binary non-assignment C operators, the .B ?: operator, the unary .BR \(mi , .BR ! , and .B ~ operators are all legal in .IR constant-expression . There is also a unary operator .BR defined , which can be used in .I constant-expression in these two forms: .BI defined " " ( " name " ) or .BI defined " name" . Only these operators, integer constants, and names which are known by .I cpp should be used in .IR constant-expression . .TP .B #else Reverses the notion of the test directive which matches this directive. So if lines previous to this directive are ignored, the following lines will appear in the output. And vice versa. .TP .BI #if " constant-expression" Reverses the notion of the test directive, and calculates the constant expression given, thereafter acting as a normal #if directive. .TP .BI #error " tokens" reports the error and the tokens on standard error, and terminates processing. .TP .BI #pragma " tokens" (silently ignores this directive). .TP .BI # Also silently ignores the null directive. .PP The test directives and the possible .B #else directives can be nested. .SH FILES .TP 1.5i /usr/include standard directory for .B #include files .SH SEE ALSO .PP cpp(1), cc(1). .SH DIAGNOSTICS .PP Various warnings, and fatal errors such as include files which cannot be found, or running out of memory. They are intended to be self-explanatory. .SH AUTHOR .nf Alistair G. Crooks, Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 580 753114) (...!uunet!linus!nixbur!nixpbe!nixbln!agc) .fi \Rogue\Monster\ else echo "will not over write ./agcpp.1" fi if `test ! -s ./Makefile.att` then echo "writing ./Makefile.att" cat > ./Makefile.att << '\Rogue\Monster\' # # @(#)Makefile.att 1.4 09/02/89 18:32:51 # # Makefile for att unix on Targon 35. # # SRCS = agcpp.c id.c if.c inc.c mac.c parse.c proto.c OBJS = agcpp.o id.o if.o inc.o mac.o parse.o proto.o INC = defs.h CC = mcc CCFLAGS = -O CPPFLAGS = -DATT -DPROCESSOR="\"pyr\"" CFLAGS = $(CCFLAGS) $(CPPFLAGS) agcpp : $(OBJS) $(CC) $(CCFLAGS) $(OBJS) -o agcpp $(OBJS) : $(INC) lint : lint $(CPPFLAGS) $(SRCS) \Rogue\Monster\ else echo "will not over write ./Makefile.att" fi if `test ! -s ./Makefile.bsd` then echo "writing ./Makefile.bsd" cat > ./Makefile.bsd << '\Rogue\Monster\' # # @(#)Makefile.bsd 1.4 09/02/89 18:32:51 # # Makefile for bsd unix on Targon 35. # # SRCS = agcpp.c getopt.c id.c if.c inc.c mac.c parse.c proto.c OBJS = agcpp.o getopt.o id.o if.o inc.o mac.o parse.o proto.o INC = defs.h CC = mcc CCFLAGS = -O CPPFLAGS = -DBSD -DPROCESSOR="\"pyr\"" CFLAGS = $(CCFLAGS) $(CPPFLAGS) agcpp : $(OBJS) $(CC) $(CCFLAGS) $(OBJS) -o agcpp $(OBJS) : $(INC) lint : lint $(CPPFLAGS) $(SRCS) \Rogue\Monster\ else echo "will not over write ./Makefile.bsd" fi if `test ! -s ./Makefile.pws` then echo "writing ./Makefile.pws" cat > ./Makefile.pws << '\Rogue\Monster\' # # @(#)Makefile.pws 1.4 09/02/89 18:32:51 # # Makefile for att unix # # OBJS = agcpp.o id.o if.o inc.o macro.o malloc.o parse.o proto.o INC = defs.h OPTIM = -O CPPFLAGS = -DATT -DPROCESSOR="\"i386\"" -DBADMALLOC -DIDENT_DIR CFLAGS = $(OPTIM) $(CPPFLAGS) agcpp : $(OBJS) cc $(CFLAGS) $(OBJS) -o agcpp $(OBJS) : $(INC) \Rogue\Monster\ else echo "will not over write ./Makefile.pws" fi if `test ! -s ./Makefile.tc` then echo "writing ./Makefile.tc" cat > ./Makefile.tc << '\Rogue\Monster\' agcpp.exe : agcpp.obj getopt.obj id.obj if.obj inc.obj mac.obj parse.obj proto.obj tcc agcpp.obj getopt.obj id.obj if.obj inc.obj mac.obj parse.obj proto.obj agcpp.obj : agcpp.c defs.h tcc -c -DTURBO agcpp.c getopt.obj : getopt.c tcc -c -DTURBO tcgetopt.c id.obj : id.c defs.h tcc -c -DTURBO id.c if.obj : if.c defs.h tcc -c -DTURBO if.c inc.obj : inc.c defs.h tcc -c -DTURBO inc.c mac.obj : mac.c defs.h tcc -c -DTURBO mac.c parse.obj : parse.c defs.h tcc -c -DTURBO parse.c proto.obj : proto.c defs.h tcc -c -DTURBO proto.c \Rogue\Monster\ else echo "will not over write ./Makefile.tc" fi if `test ! -s ./Makefile.ztc` then echo "writing ./Makefile.ztc" cat > ./Makefile.ztc << '\Rogue\Monster\' agcpp.exe : agcpp.obj getopt.obj id.obj if.obj inc.obj mac.obj parse.obj proto.obj ztc agcpp.obj getopt.obj id.obj if.obj inc.obj mac.obj parse.obj proto.obj agcpp.obj : agcpp.c defs.h ztc -c -DZORTECH agcpp.c getopt.obj : getopt.c ztc -c -DZORTECH getopt.c id.obj : id.c defs.h ztc -c -DZORTECH id.c if.obj : if.c defs.h ztc -c -DZORTECH if.c inc.obj : inc.c defs.h ztc -c -DZORTECH inc.c mac.obj : mac.c defs.h ztc -c -DZORTECH mac.c parse.obj : parse.c defs.h ztc -c -DZORTECH parse.c proto.obj : proto.c defs.h ztc -c -DZORTECH proto.c \Rogue\Monster\ else echo "will not over write ./Makefile.ztc" fi if `test ! -s ./agcpp.c` then echo "writing ./agcpp.c" cat > ./agcpp.c << '\Rogue\Monster\' /* * @(#)agcpp.c 1.12 09/02/89 18:22:10 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this * notice remains attached. * * agcpp - a version of a C pre-processor. * * agcpp.c - miscellaneous routines, and main. * * Compile time flags: * ATT Unix System V.[23] * BSD Unix BSD4.[23] * ZORTECH Zortech C++, v1.05 * TURBOC Turbo C, 1.5 * MSC Microsoft C, 5.0 * MINIX Minix 1.2 */ #ifndef lint char *agcppnsccsid = "@(#)agcpp.c 1.12 09/02/89 18:22:10 agc"; #endif /* not lint */ #include <stdio.h> #include <ctype.h> #define EXTERN #include "defs.h" #ifdef ATT #ifndef STDINCLUDE #define STDINCLUDE "/usr/include" #endif /* STDINCLUDE */ #define OSTYPE "unix" #endif /* ATT */ #ifdef BSD #ifndef STDINCLUDE #define STDINCLUDE "/usr/include" #endif /* STDINCLUDE */ #define OSTYPE "unix" #endif /* BSD */ #ifdef ZORTECH #ifndef STDINCLUDE #define STDINCLUDE "c:/zortech/include" #endif /* STDINCLUDE */ #define OSTYPE "dos" #endif /* ZORTECH */ #ifdef TURBOC #ifndef STDINCLUDE #define STDINCLUDE "c:/turboc/include" #endif /* STDINCLUDE */ #define OSTYPE "dos" #endif /* TURBOC */ #ifdef MSC #ifndef STDINCLUDE #define STDINCLUDE "c:/msc/include" #endif /* STDINCLUDE */ #define OSTYPE "dos" #endif /* MSC */ #ifdef MINIX #ifndef STDINCLUDE #define STDINCLUDE "/usr/include" #endif /* STDINCLUDE */ #define OSTYPE "minix" #endif /* MINIX */ #ifndef PROCESSOR #define PROCESSOR "i8088" #endif /* PROCESSOR */ #define READING 1 #define WRITING 2 typedef struct directive { char *d_name; int d_type; #define UNKNOWN 0 #define DEFINE 1 #define ENDIF 2 #define IFDEF 3 #define IFNDEF 4 #define ELSE 5 #define INCLUDE 6 #define IF 7 #define ELIF 8 #define UNDEF 9 #define PRAGMA 10 #define ERROR 11 #define LINE 12 #define IDENT 13 #define EMPTY 14 } DIRECTIVE; static DIRECTIVE directives[] = { "define", DEFINE, "endif", ENDIF, "ifdef", IFDEF, "ifndef", IFNDEF, "else", ELSE, "include", INCLUDE, "if", IF, "elif", ELIF, "undef", UNDEF, "pragma", PRAGMA, "error", ERROR, "line", LINE, #ifdef IDENT_DIR "ident", IDENT, #endif /* IDENT_DIR */ "\n", EMPTY, NULL }; static char *one = "1"; /* string for definitions */ static char linedirectives = 1; /* 1 = line directives are made */ extern char *optarg; extern int optind; /* report an error on stderr, and exit if n greater than 0 */ void error(n, fmt, s) int n; char *fmt; char *s; { if (filename[0]) (void) fprintf(stderr, "\"%s\" ", filename); (void) fprintf(stderr, "%d: ", lineno); (void) fprintf(stderr, fmt, s); (void) fputc('\n', stderr); if (n) (void) exit(n); } /* Minix has no bzero function - to zero n bytes of s */ #ifdef MINIX void bzero(s, n) char *s; unsigned int n; { while (n--) *s++ = 0; } #endif /* MINIX */ /* save n chars of s in malloc'd memory */ char * strnsave(s, n) char *s; int n; { char *cp; NEWARRAY(char, cp, n+1); (void) strncpy(cp, s, n); cp[n] = 0; return(cp); } /* put n tokens of s on stdout */ void output(s, n) char *s; int n; { static char obuf[BUFSIZ]; static char *op = obuf; char *was; char *cp; (void) strncpy(op, s, n); op += n; *op = 0; if (s[n-1] == '\n') { for (cp = op = obuf ; *op ; ) { while (*op && *op != '"') *cp++ = *op++; if (*op == 0) break; for (*cp++ = *op++ ; *op && *op != '"' ; *cp++ = *op++) if (*op == '\\') *cp++ = *op++; if (*op == 0) break; for (was = op++ ; *op && isspace(*op) ; op++) ; if (*op == 0) break; if (*op == '"') op++; else op = was; } for (*cp-- = 0 ; cp != obuf && isspace(*cp) ; --cp) ; if (*cp == '"') op = &obuf[strlen(obuf) - 1]; else { (void) fputs(obuf, stdout); op = obuf; } } } /* delete an ARGS structure */ void delargs(ap) ARGS *ap; { int i; for (i = 0 ; i < ap->a_argc ; i++) (void) nfree((char *) ap->a_argv[i]); (void) nfree((char *) ap); } /* perform the line directive */ void doline() { if (linedirectives) (void) printf("# %d \"%s\"\n", lineno, filename); } #ifdef IDENT_DIR /* perform the ident directive */ void doident(fp) FILE *fp; { (void) printf("# ident "); if (!gettoken(fp, 1, &t)) error(0, "Unexpected end of file in #ident", (char *) NULL); (void) printf("%s\n", t.t_token); } #endif /* IDENT_DIR */ /* perform the error directive */ void doerror(fp) FILE *fp; { tmp[0] = 0; while (gettoken(fp, 0, &t)) { if (t.t_type == T_EOLN) break; (void) strcat(tmp, t.t_token); } error(1, "%s", tmp); } /* perform the undef directive */ void doundef(fp) FILE *fp; { if (!gettoken(fp, 0, &t)) error(1, "Bad undef syntax", (char *) NULL); delmacro(t.t_token); } /* check that we're not at the top level */ int oklevel(level, directive) int level; char *directive; { if (level == 0) error(0, "Unmatched %s", directive); return(level != 0); } /* check that we've not seen an else directive yet */ int okelse(elseln) int elseln; { if (elseln >= 0) error(0, "Previous #else directive line %d", (char *) elseln); return(elseln < 0); } /* find out which directive it was from directives despatch table */ int getdirective(s) char *s; { DIRECTIVE *dp; for (dp = directives ; dp->d_name ; dp++) if (STREQ(dp->d_name, s)) return(dp->d_type); return(UNKNOWN); } /* do a block of the input file - recursive */ void doblock(fp, doing, level, parent) FILE *fp; int doing; int level; int parent; { int elseln = -1; while (gettoken(fp, 0, &t)) { switch(t.t_type) { case T_HASH : if (!gettoken(fp, 1, &t)) error(1, "Unexpected end of file in directive", (char *) NULL); switch(getdirective(t.t_token)) { case DEFINE : if (doing) dodefine(fp); break; case ENDIF : clrtoeoln(fp); if (oklevel(level, "#endif")) { if (!doing) doline(); return; } break; case ELSE : if (oklevel(level, "#else") && okelse(elseln)) { if (!doing) doline(); if (parent) doing = 1 - doing; elseln = lineno; } clrtoeoln(fp); break; case IFDEF : doblock(fp, doifdef(fp, 1, doing), level+1, doing); break; case IFNDEF : doblock(fp, doifdef(fp, 0, doing), level+1, doing); break; case IF : doblock(fp, doif(fp, doing), level+1, doing); break; case ELIF : if (oklevel(level, "#elif") && okelse(elseln)) { if (!doing) doline(); if (parent) doing = 1 - doing; doblock(fp, doif(fp, doing), level+1, doing); if (!doing) doline(); return; } break; case INCLUDE : if (doing) { doinclude(fp, level); doline(); } break; case LINE : if (doing) doline(); break; #ifdef IDENT_DIR case IDENT : if (doing) doident(fp); break; #endif /* IDENT_DIR */ case UNDEF : if (doing) doundef(fp); break; case ERROR : doerror(fp); break; case PRAGMA : clrtoeoln(fp); break; case EMPTY : break; case UNKNOWN : error(0, "Unknown directive '%s'", t.t_token); break; } break; case T_WORD : if (!doing) continue; expand(t.t_token, fp); break; default : if (t.t_token[0] == '{') block++; else if (t.t_token[0] == '}') block--; if (doing) output(t.t_token, t.t_len); if (doing && clevel == K_AND_R && block == 0 && t.t_token[0] == '(') doargs(fp); } } } /* re-direct the desired io stream to/from a file */ void openfp(s, mode) char *s; char mode; { switch(mode) { case READING : if (freopen(s, "r", stdin) == (FILE *) NULL) error(1, "can't read file '%s'", s); break; case WRITING : if (freopen(s, "w+", stdout) == (FILE *) NULL) error(1, "can't write to output file '%s'", s); break; } } main(argc, argv) int argc; char **argv; { char *eq; int c; insdir(STDINCLUDE); addmacro(OSTYPE, (ARGS *) NULL, one, 0); addmacro(PROCESSOR, (ARGS *) NULL, one, 0); addmacro("__FILE__", (ARGS *) NULL, one, 1); addmacro("__LINE__", (ARGS *) NULL, one, 1); addmacro("__DATE__", (ARGS *) NULL, one, 1); addmacro("__TIME__", (ARGS *) NULL, one, 1); addmacro("__STDC__", (ARGS *) NULL, one, 1); compchars = COMPCHARS; clevel = K_AND_R; while ((c = getopt(argc, argv, "A:C:D:I:PU:")) != EOF) { switch(c) { case 'A' : if (STREQ(optarg, "NSI")) clevel = ANSI; break; case 'C' : if ((compchars = atoi(optarg)) == 0) compchars = COMPCHARS; break; case 'D' : if ((eq = index(optarg, '=')) == (char *) NULL) eq = one; else *eq++ = 0; addmacro(optarg, (ARGS *) NULL, eq, 0); break; case 'I' : insdir(optarg); break; case 'P' : linedirectives = 0; break; case 'U' : delmacro(optarg); break; default : error(0, "unrecognised argument '%c'", (char *) c); } } if (clevel == K_AND_R) { addmacro("const", (ARGS *) NULL, " ", 0); addmacro("volatile", (ARGS *) NULL, " ", 0); addmacro("signed", (ARGS *) NULL, " ", 0); } insdir("."); lineno = 0; t.t_type = T_EOLN; if (optind < argc) { (void) strcpy(filename, argv[optind]); #ifdef ZORTECH /* don't ask me why - this needs to be here, or the freopen of stdin fails */ printf("\n"); #endif /* ZORTECH */ openfp(filename, READING); if (argv[++optind] != (char *) NULL) openfp(argv[optind], WRITING); } else filename[0] = 0; doblock(stdin, 1, 0, 1); return(0); } \Rogue\Monster\ else echo "will not over write ./agcpp.c" fi if `test ! -s ./defs.h` then echo "writing ./defs.h" cat > ./defs.h << '\Rogue\Monster\' /* * @(#)defs.h 1.9 09/02/89 18:22:10 agc * * Copyright Joypace Ltd., UK, 1989. All rights reserved. * This code may be freely distributed, provided that this * notice remains attached. * * agcpp - a version of a C pre-processor. * * defs.h - contains all the definitions for agcpp. * * Compile-time flags: * ATT Unix System V.[23] * BSD BSD 4.[23] Unix * ZORTECH Zortech C++, v1.05. * TURBOC Turbo C 1.5 * MSC Microsoft C 5.0 */ #define MAXARGS 32 typedef struct tokstr { /* parsing token */ char t_token[BUFSIZ]; /* the token itself */ char t_type; /* its type */ #define T_HASH 1 #define T_WORD 2 #define T_STRING 3 #define T_NUMBER 4 #define T_SPACE 5 #define T_EOLN 6 #define T_PUNCT 7 #define T_HASHHASH 8 int t_len; /* its length */ } TOKEN; typedef struct argstr { /* argc, argv style arguments */ int a_argc; char *a_argv[MAXARGS]; } ARGS; typedef struct macstr { /* a macro */ char *m_name; /* its name */ char *m_val; /* its value */ ARGS *m_args; /* any arguments (NULL if none) */ char m_prot; /* 1 = macro is protected */ struct macstr *m_next; /* next in bucket */ struct macstr *m_prev; /* previous in bucket */ } MACRO; #define HASHTABLEN 997 /* length of the hash table */ #ifndef SIGCHARS #define SIGCHARS 32 /* signif. chars in cpp identifier */ #endif /* SIGCHARS */ #ifndef COMPCHARS #define COMPCHARS 8 /* signif. chars in cc identifier */ #endif /* COMPCHARS */ #ifndef BADMALLOC #define nfree free #define ncalloc calloc #define nmalloc malloc #endif /* BADMALLOC */ #ifdef ATT #define index strchr #define bzero(s, n) (void) memset(s, 0, n) #include <string.h> #endif /* ATT */ #ifdef ZORTECH #define index strchr #define bzero(s, n) (void) memset(s, 0, n) #include <string.h> #endif /* ZORTECH */ #ifdef TURBOC #define index strchr #define bzero(s, n) (void) memset(s, 0, n) #include <string.h> #endif /* TURBOC */ #ifdef MSC #define index strchr #define bzero(s, n) (void) memset(s, 0, n) #include <string.h> #endif /* MSC */ #ifdef BSD #include <strings.h> #endif /* BSD */ #define NEWARRAY(type, ptr, nel) \ if ((ptr = (type *) ncalloc((unsigned) nel, sizeof(type))) == \ (type *) NULL) \ error(1, "newarray: ncalloc failure", (char *) NULL) #define NEW(type, ptr) { \ if ((ptr = (type *) nmalloc(sizeof(type))) == (type *) NULL) \ error(1, "new: nmalloc failure", (char *) NULL); \ bzero((char *) ptr, sizeof(type)); \ } #define STREQ(s1, s2) (*s1 == *s2 && strcmp(&(s1)[1], &(s2)[1]) == 0) EXTERN TOKEN t; /* the token being processed */ EXTERN char filename[BUFSIZ]; /* current filename */ EXTERN char buf[BUFSIZ]; /* current input buffer */ EXTERN char tmp[BUFSIZ]; /* for temporary stuff */ EXTERN char *here; /* current place in input buffer */ EXTERN int lineno; /* current line number in source file */ EXTERN int ilevel; /* current include nesting level */ EXTERN int block; /* number of {} pairs found */ EXTERN int compchars; /* significant id. chars in cc */ EXTERN int clevel; /* what compiler will accept */ #define K_AND_R 0 #define ANSI 1 extern char *malloc(); extern char *calloc(); #ifdef ATT extern void exit(); extern void free(); #endif /* ATT */ #ifdef BSD extern int exit(); extern int free(); #endif /* BSD */ extern MACRO *isdefined(); extern ARGS *fgetargs(); extern char *strnsave(); extern char *nameof(); extern void error(); extern void addmacro(); extern void delmacro(); extern void dodefine(); extern void clrtoeoln(); extern void doinclude(); extern void expand(); extern void insdir(); extern void doblock(); extern void delargs(); extern void sgettoken(); extern void output(); extern void doargs(); \Rogue\Monster\ else echo "will not over write ./defs.h" fi if `test ! -s ./getopt.c` then echo "writing ./getopt.c" cat > ./getopt.c << '\Rogue\Monster\' #include <stdio.h> #ifndef lint char getopt_sccsid[] = "@(#)getopt.c 1.1 17/09/87 12:07:04 agc 1987"; #endif extern char *index(); /* * getopt - parse the arguments given. * retrieved from net.sources */ int opterr = 1; int optind = 1; int optopt; char *optarg; #define BADCH (int)'?' #define EMSG "" #define TELL(s) (void) fputs(*nargv, stderr); (void) fputs(s, stderr);\ (void) fputc(optopt, stderr); (void) fputc('\n', stderr);\ return(BADCH); int getopt(nargc, nargv, ostr) int nargc; char **nargv; char *ostr; { register char *oli; static char *place = EMSG; if (!*place) { if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF); if (*place == '-') { ++optind; return(EOF); } } if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr, optopt))) { if (!*place) ++optind; TELL(": illegal option -- "); } if (*++oli != ':') { optarg = NULL; if (!*place) ++optind; } else { if (*place) optarg = place; else if (nargc <= ++optind) { place = EMSG; TELL(": option requires an argument -- "); } else optarg = nargv[optind]; place = EMSG; ++optind; } return(optopt); } \Rogue\Monster\ else echo "will not over write ./getopt.c" fi if `test ! -s ./id.c` then echo "writing ./id.c" cat > ./id.c << '\Rogue\Monster\' /* * @(#)id.c 1.1 09/02/89 18:21:55 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this * notice remains attached. * * agcpp - a version of a C pre-processor. * * id.c - long identifier name folding. * * Compile time flags: * ATT Unix System V.[23] * BSD Unix BSD4.[23] * ZORTECH Zortech C++, v1.05 * TURBOC Turbo C, 1.5 * MSC Microsoft C, 5.0 * MINIX Minix 1.2 */ #ifndef lint static char *idnsccsid = "@(#)id.c 1.1 09/02/89 18:21:55 agc"; #endif /* not lint */ #include <stdio.h> #define EXTERN extern #include "defs.h" typedef struct idstr { char *i_name; char *i_alias; struct idstr *i_next; struct idstr *i_prev; } ID; typedef struct hashid { ID *hi_head; ID *hi_tail; } HID; static HID ids[HASHTABLEN]; static int idnum; void addid(old, new) char *old; char *new; { int n; ID *ip; n = hash(old, compchars); for (ip = ids[n].hi_head ; ip ; ip = ip->i_next) if (strcmp(old, ip->i_name) == 0) return; NEW(ID, ip); ip->i_name = strnsave(old, strlen(old)); ip->i_alias = strnsave(new, strlen(new)); if (ids[n].hi_head == (ID *) NULL) ids[n].hi_head = ip; else ids[n].hi_tail->i_next = ip; ip->i_prev = ids[n].hi_tail; ids[n].hi_tail = ip; } void delid(old) char *old; { int n; ID *ip; n = hash(old, compchars); for (ip = ids[n].hi_head ; ip ; ip = ip->i_next) if (strcmp(old, ip->i_name) == 0) break; if (ip == (ID *) NULL) return; (void) free(ip->i_name); (void) free(ip->i_alias); if (ip->i_next == (ID *) NULL) ids[n].hi_tail = ip->i_prev; else ip->i_next->i_prev = ip->i_prev; if (ip->i_prev == (ID *) NULL) ids[n].hi_head = ip->i_next; else ip->i_prev->i_next = ip->i_next; (void) free(ip); } char * getclash(id) char *id; { int n; ID *ip; n = hash(id, compchars); for (ip = ids[n].hi_head ; ip ; ip = ip->i_next) if (strncmp(id, ip->i_name, compchars) == 0) return(ip->i_alias); return((char *) NULL); } char * getid(id) char *id; { int n; ID *ip; n = hash(id, compchars); for (ip = ids[n].hi_head ; ip ; ip = ip->i_next) if (strcmp(id, ip->i_name) == 0) return(ip->i_alias); return((char *) NULL); } char * newid() { static char idname[10]; for (;;) { (void) sprintf(idname, "i%05d", idnum); if (getclash(idname) == (char *) NULL) return(idname); idnum = (idnum == 99999) ? 0 : idnum + 1; } } char * nameof(id, len) char *id; int len; { char *clashname; char *alias; if (len < compchars) { if ((alias = getid(id)) == (char *) NULL) addid(id, id); return(id); } if ((alias = getid(id)) != (char *) NULL) return(alias); clashname = strnsave(id, compchars); if (getclash(clashname) == (char *) NULL) { addid(id, id); (void) free(clashname); return(id); } alias = newid(); addid(id, alias); (void) free(clashname); return(alias); } void initids() { addid("register", "register"); addid("unsigned", "unsigned"); addid("volatile", "volatile"); addid("continue", "continue"); } \Rogue\Monster\ else echo "will not over write ./id.c" fi if `test ! -s ./if.c` then echo "writing ./if.c" cat > ./if.c << '\Rogue\Monster\' /* * @(#)if.c 1.4 25/01/89 15:45:12 agc * * Copyright Joypace Ltd., UK, 1989. All rights reserved. * This code may be freely distributed, provided that this * notice remains attached. * * agcpp - a version of a C pre-processor. * * if.c - contains all the code for #if directives. * * Compile-time flags: * ATT Unix System V.[23] * BSD BSD 4.[23] Unix * ZORTECH Zortech C++, v1.05. * TURBOC Turbo C 1.5 * MSC Microsoft C 5.0 */ #ifndef lint static char *ifnsccsid = "@(#)if.c 1.4 25/01/89 15:45:12 agc"; #endif /* not lint */ #include <stdio.h> #define EXTERN extern #include "defs.h" static char *unaries = "+-~!"; #define NEXTTOKEN(str) \ if (!gettoken(fp, 1, &t)) \ error(0, "Unexpected end of file in %s", str) /* * BNF of an #if directive follows: * * ifstatement ::= cond * | cond && cond * | cond || cond * * cond ::= unary ( expr ) * | unary expr * | unary expr * | ( expr ) * expr * * expr ::= term * | term == term * | term != term * | term >= term * | term <= term * | term > term * | term < term * * term ::= prim * | prim + prim * | prim - prim * | prim * prim * | prim / prim * | prim % prim * | prim & prim * | prim | prim * | prim ^ prim * | prim << prim * | prim >> prim * * prim ::= NUMBER * | defined ( macroname ) * | defined macroname * | macroname * * unary ::= + * | - * | ~ * | ! */ /* recognise a primary symbol */ int prim(fp) FILE *fp; { MACRO *mp; int val; int b = 0; switch(t.t_type) { case T_NUMBER : val = atoi(t.t_token); NEXTTOKEN("#if"); return(val); case T_WORD : if (STREQ(t.t_token, "defined")) { NEXTTOKEN("#if"); if (t.t_token[0] == '(') { b++; NEXTTOKEN("#if"); } val = (isdefined(t.t_token) != (MACRO *) NULL); if (b) NEXTTOKEN("#if"); NEXTTOKEN("#if"); return(val); } if ((mp = isdefined(t.t_token)) == (MACRO *) NULL) return(0); NEXTTOKEN("#if"); return(atoi(mp->m_val)); default : return(0); } } /* recognise a term */ int term(fp) FILE *fp; { int left; int zero; left = prim(fp); if (STREQ(t.t_token, "+")) { NEXTTOKEN("#if"); return(left + prim(fp)); } if (STREQ(t.t_token, "-")) { NEXTTOKEN("#if"); return(left - prim(fp)); } if (STREQ(t.t_token, "*")) { NEXTTOKEN("#if"); return(left * prim(fp)); } if (STREQ(t.t_token, "/")) { NEXTTOKEN("#if"); if ((zero = prim(fp)) == 0) return(0); return(left / zero); } if (STREQ(t.t_token, "%")) { NEXTTOKEN("#if"); return(left % prim(fp)); } if (STREQ(t.t_token, "&")) { NEXTTOKEN("#if"); return(left & prim(fp)); } if (STREQ(t.t_token, "|")) { NEXTTOKEN("#if"); return(left | prim(fp)); } if (STREQ(t.t_token, "^")) { NEXTTOKEN("#if"); return(left ^ prim(fp)); } if (STREQ(t.t_token, "<<")) { NEXTTOKEN("#if"); return(left << prim(fp)); } if (STREQ(t.t_token, ">>")) { NEXTTOKEN("#if"); return(left >> prim(fp)); } return(left); } /* recognise an expression */ int expr(fp) FILE *fp; { int left; left = term(fp); if (STREQ(t.t_token, "==")) { NEXTTOKEN("#if"); return(left == term(fp)); } if (STREQ(t.t_token, "!=")) { NEXTTOKEN("#if"); return(left != term(fp)); } if (STREQ(t.t_token, ">=")) { NEXTTOKEN("#if"); return(left >= term(fp)); } if (STREQ(t.t_token, "<=")) { NEXTTOKEN("#if"); return(left <= term(fp)); } if (STREQ(t.t_token, ">")) { NEXTTOKEN("#if"); return(left > term(fp)); } if (STREQ(t.t_token, "<")) { NEXTTOKEN("#if"); return(left < term(fp)); } return(left); } /* recognise an if condition */ int cond(fp) FILE *fp; { int unary = 0; int result; int b = 0; if (index(unaries, t.t_token[0]) != (char *) NULL) { unary = t.t_token[0]; NEXTTOKEN("#if"); } if (t.t_token[0] == '(') { b++; NEXTTOKEN("#if"); } result = expr(fp); if (b) NEXTTOKEN("#if"); switch(unary) { case '!' : return(!result); case '~' : return(~result); case '-' : return(-result); case '+' : case 0 : return(result); } return(result); } /* perform the if directive */ int doif(fp, doing) FILE *fp; int doing; { int left; if (!doing) return(0); NEXTTOKEN("#if"); left = cond(fp); while (t.t_type != T_EOLN) { if (STREQ(t.t_token, "&&")) { NEXTTOKEN("#if"); left = left && cond(fp); } else if (STREQ(t.t_token, "||")) { NEXTTOKEN("#if"); left = left || cond(fp); } else NEXTTOKEN("#if"); } return(left); } /* perform the ifdef and ifndef directives */ int doifdef(fp, n, doing) FILE *fp; int n; int doing; { MACRO *mp; if (!doing) { while (gettoken(fp, 1, &t)) if (t.t_type == T_EOLN) break; return(0); } NEXTTOKEN((n) ? "#ifdef" : "ifndef"); mp = isdefined(t.t_token); NEXTTOKEN((n) ? "#ifdef" : "ifndef"); return((n) ? (mp != (MACRO *) NULL) : (mp == (MACRO *) NULL)); } \Rogue\Monster\ else echo "will not over write ./if.c" fi if `test ! -s ./inc.c` then echo "writing ./inc.c" cat > ./inc.c << '\Rogue\Monster\' /* * @(#)inc.c 1.6 07/02/89 15:41:32 agc * * Copyright Joypace Ltd., UK, 1989. All rights reserved. * This code may be freely distributed, provided that this * notice remains attached. * * agcpp - a version of a C pre-processor. * * inc.c - contains all the code for #include directives. * * Compile-time flags: * ATT Unix System V.[23] * BSD BSD 4.[23] Unix * ZORTECH Zortech C++, v1.05. * TURBOC Turbo C 1.5 * MSC Microsoft C 5.0 */ #ifndef lint static char *incnsccsid = "@(#)inc.c 1.6 07/02/89 15:41:32 agc"; #endif /* not lint */ #include <stdio.h> #define EXTERN extern #include "defs.h" typedef struct dirinc { char *d_dir; struct dirinc *d_next; } INCDIR; typedef struct incfile { char *i_file; int i_level; struct incfile *i_next; } INCFILE; static INCFILE *ifilehead; static INCFILE *ifiletail; static INCDIR *idirhead; /* insert a directory at the front of the directory list */ void insdir(s) char *s; { INCDIR *dp; NEW(INCDIR, dp); dp->d_dir = strnsave(s, strlen(s)); dp->d_next = idirhead; idirhead = dp; } /* is it ok to include this file? */ int okfile(f, level) char *f; int level; { INCFILE *ip; for (ip = ifilehead ; ip ; ip = ip->i_next) { if (STREQ(ip->i_file, f)) { error(0, "File '%s' already included", f); return(0); } } NEW(INCFILE, ip); ip->i_file = strnsave(f, strlen(f)); ip->i_level = level; if (ifilehead == (INCFILE *) NULL) ifilehead = ip; else ifiletail->i_next = ip; ifiletail = ip; return(1); } /* getthe name of the file, put it in fn, and set start of directory search */ void incname(tp, fn, fp, inp, dpp) TOKEN *tp; char *fn; FILE *fp; char *inp; INCDIR **dpp; { MACRO *mp; TOKEN mt; char *cp1; switch(tp->t_type) { case T_STRING : *dpp = idirhead; (void) strcpy(fn, &tp->t_token[1]); fn[tp->t_len - 2] = 0; break; case T_WORD : if ((mp = isdefined(tp->t_token)) == (MACRO *) NULL) error(1, "Bad include syntax", (char *) NULL); cp1 = tmp; inp = mp->m_val; (void) expmac(mp, &cp1, (FILE *) NULL, &inp); inp = tmp; sgettoken(&inp, 1, &mt); incname(&mt, fn, (FILE *) NULL, inp, dpp); break; default : *dpp = idirhead->d_next; if (fp != (FILE *) NULL) { if (!gettoken(fp, 1, &t)) error(1, "Bad include syntax", (char *) NULL); for (fn[0] = 0 ; t.t_token[0] != '>' ; ) { (void) strcat(fn, t.t_token); if (!gettoken(fp, 1, &t)) error(1, "Bad include syntax", (char *) NULL); } } else { mt.t_type = T_SPACE; sgettoken(&inp, 1, &mt); for (fn[0] = 0 ; mt.t_token[0] != '>' ; ) { (void) strcat(fn, mt.t_token); sgettoken(&inp, 1, &mt); if (mt.t_type == T_EOLN) error(1, "Bad include syntax", (char *) NULL); } } } } /* perform the include directive */ void doinclude(fp, level) FILE *fp; int level; { INCDIR *dp; FILE *newfp; char fn[BUFSIZ]; char *oldname; int oldline; if (!gettoken(fp, 1, &t)) error(1, "Bad include syntax", (char *) NULL); oldname = strnsave(filename, strlen(filename)); oldline = lineno; ilevel += 1; incname(&t, fn, fp, (char *) NULL, &dp); if (fn[0] == '/') { (void) strcpy(filename, fn); newfp = fopen(filename, "r"); } else { for ( ; dp ; dp = dp->d_next) { (void) sprintf(filename, "%s/%s", dp->d_dir, fn); if ((newfp = fopen(filename, "r")) != (FILE *) NULL) break; } } if (newfp == (FILE *) NULL) { (void) strcpy(filename, oldname); error(1, "can't find include file '%s'", fn); } clrtoeoln(fp); lineno = 0; if (okfile(filename, ilevel)) doblock(newfp, 1, level, 1); (void) fclose(newfp); lineno = oldline; ilevel -= 1; (void) strcpy(filename, oldname); (void) nfree(oldname); } \Rogue\Monster\ else echo "will not over write ./inc.c" fi if `test ! -s ./mac.c` then echo "writing ./mac.c" cat > ./mac.c << '\Rogue\Monster\' /* * @(#)mac.c 1.11 09/02/89 18:22:10 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this * notice remains attached. * * agcpp - a version of a C pre-processor. * * mac.c - macro expansion and definition routines. * * Compile time flags: * ATT Unix System V.[23] * BSD Unix BSD4.[23] * ZORTECH Zortech C++, v1.05 * TURBOC Turbo C, 1.5 * MSC Microsoft C, 5.0 * MINIX Minix 1.2 */ #ifndef lint static char *macnsccsid = "@(#)mac.c 1.11 09/02/89 18:22:10 agc"; #endif /* not lint */ #include <stdio.h> #define EXTERN extern #include "defs.h" #ifdef ATT #define time_t long #include <time.h> extern time_t time(); #endif #ifdef BSD #include <sys/types.h> #include <sys/time.h> extern time_t time(); #endif #ifdef ZORTECH #include <time.h> #endif /* ZORTECH */ #ifdef TURBOC #include <time.h> #endif /* TURBOC */ #ifdef MSC #include <time.h> #endif /* MSC */ #ifdef MINIX #define time_t long extern time_t time(); extern char *ctime(); #endif /* MINIX */ #define STACKSIZE 256 typedef struct bucket { MACRO *h_head; MACRO *h_tail; } HASH; typedef struct stack { char *s_name; int s_level; } STACK; static HASH h[HASHTABLEN]; static STACK stackv[STACKSIZE]; static int stackc; extern char *strnsave(); /* rudimentary, but effective hashing algorithm */ int hash(s, n) char *s; int n; { unsigned int ret; int i; for (i = 0, ret = 1 ; *s && i < SIGCHARS && i < n ; i++) ret *= *s++; return(ret % HASHTABLEN); } /* is s defined as a macro? return ptr to it if yes, null otherwise */ MACRO * isdefined(s) char *s; { MACRO *mp; int n; n = hash(s, SIGCHARS); for (mp = h[n].h_head ; mp ; mp = mp->m_next) if (STREQ(mp->m_name, s)) return(mp); return((MACRO *) NULL); } /* stop s being circularly defined - push it on stack */ void push(s, n) char *s; int n; { stackv[stackc].s_name = s; stackv[stackc++].s_level = n; } /* pop the stack */ void pop() { stackv[--stackc].s_name = (char *) NULL; } /* is s being expanded at the moment? */ int doing(s, n) char *s; int n; { STACK *sp; int i; for (i = 0, sp = stackv ; i < stackc ; i++, sp++) if (STREQ(s, sp->s_name) && sp->s_level < n) return(1); return(0); } /* add a macro */ void addmacro(name, ap, val, protected) char *name; ARGS *ap; char *val; char protected; { MACRO *mp; int n; n = hash(name, SIGCHARS); for (mp = h[n].h_head ; mp ; mp = mp->m_next) { if (STREQ(mp->m_name, name)) { error(mp->m_prot, "redefinition of '%s'", name); break; } } if (mp == (MACRO *) NULL) { NEW(MACRO, mp); mp->m_prev = h[n].h_tail; if (h[n].h_head == (MACRO *) NULL) h[n].h_head = mp; else h[n].h_tail->m_next = mp; h[n].h_tail = mp; mp->m_name = strnsave(name, strlen(name)); } else (void) nfree(mp->m_val); mp->m_args = ap; mp->m_val = strnsave(val, strlen(val)); mp->m_prot = protected; } /* delete a macro */ void delmacro(name) char *name; { MACRO *mp; int n; n = hash(name, SIGCHARS); for (mp = h[n].h_head ; mp ; mp = mp->m_next) if (STREQ(mp->m_name, name)) break; if (mp == (MACRO *) NULL) return; (void) nfree(mp->m_name); (void) nfree(mp->m_val); if (mp->m_args != (ARGS *) NULL) delargs(mp->m_args); if (mp == h[n].h_head) h[n].h_head = mp->m_next; else mp->m_prev->m_next = mp->m_next; if (mp == h[n].h_tail) h[n].h_tail = mp->m_prev; else mp->m_next->m_prev = mp->m_prev; (void) nfree((char *)mp); } /* get the arguments from the file */ ARGS * fgetargs(fp, bracket) FILE *fp; char bracket; { ARGS *ap; int n = 0; int b; if (bracket) { if (*here != '(') return((ARGS *) NULL); b = 0; } else { tmp[0] = 0; b = 1; } NEW(ARGS, ap); for (;;) { if (!gettoken(fp, bracket, &t)) error(1, "bad macro format", (char *) NULL); switch(t.t_token[0]) { case ',' : if (b == 1) { ap->a_argv[ap->a_argc++] = strnsave(tmp, n); tmp[0] = 0; n = 0; continue; } break; case '(' : if (b++ == 0) { tmp[0] = 0; n = 0; continue; } break; case ')' : if (--b == 0) { if (n > 0) ap->a_argv[ap->a_argc++] = strnsave(tmp, n); return(ap); } break; } (void) strcat(tmp, t.t_token); n += t.t_len; } } /* get the arguments from the *cpp */ ARGS * sgetargs(cpp) char **cpp; { TOKEN mt; ARGS *ap; char *start; int b = 0; if (**cpp != '(') return((ARGS *) NULL); NEW(ARGS, ap); for (;;) { sgettoken(cpp, 1, &mt); switch(mt.t_token[0]) { case '(' : if (b++ == 0) start = *cpp; break; case ')' : if (--b == 0) { if (*cpp - start > 1) ap->a_argv[ap->a_argc++] = strnsave(start, *cpp - start - 1); return(ap); } break; case ',' : if (b == 1) { ap->a_argv[ap->a_argc++] = strnsave(start, *cpp - start - 1); start = *cpp; } break; } } } /* perform the define directive */ void dodefine(fp) FILE *fp; { TOKEN name; ARGS *ap; name.t_type = T_SPACE; if (!gettoken(fp, 1, &name)) error(1, "Bad define syntax", (char *) NULL); ap = fgetargs(fp, 1); tmp[0] = 0; for (;;) { if (!gettoken(fp, 0, &t)) error(1, "Bad define syntax", (char *) NULL); if (t.t_type == T_EOLN) break; if (t.t_type == T_SPACE) (void) strcat(tmp, " "); else (void) strcat(tmp, t.t_token); } if (name.t_type == T_WORD) addmacro(name.t_token, ap, tmp, 0); else error(0, "illegal macro name '%s'", name.t_token); } /* an ansi predefined string - output it */ void expansi(s, outp) char *s; char **outp; { time_t tim; char *cp; if (STREQ(s, "__FILE__")) { (void) strcpy(*outp, filename); *outp += strlen(filename); return; } if (STREQ(s, "__LINE__")) { (void) sprintf(tmp, "%d", lineno); (void) strcpy(*outp, tmp); *outp += strlen(tmp); return; } if (STREQ(s, "__DATE__")) { (void) time(&tim); cp = ctime(&tim); (void) strncpy(*outp, &cp[4], 6); *outp += 6; (void) strncpy(*outp, &cp[19], 5); *outp += 5; **outp = 0; return; } if (STREQ(s, "__TIME__")) { (void) time(&tim); cp = ctime(&tim); (void) strncpy(*outp, &cp[11], 8); *outp += 8; **outp = 0; return; } if (STREQ(s, "__STDC__")) { (void) strcpy(*outp, "1"); outp += 1; } } /* make the argument s into a string */ void stringize(s, outp) char *s; char **outp; { *(*outp)++ = '"'; while (*s) { if (*s == '"' || *s == '\\') *(*outp)++ = '\\'; *(*outp)++ = *s++; } *(*outp)++ = '"'; } /* is the string s one of the formal arguments? */ int isarg(s, formal) char *s; ARGS *formal; { char **cpp; int i; if (formal == (ARGS *) NULL) return(-1); for (i = 0, cpp = formal->a_argv ; i < formal->a_argc ; i++, cpp++) if (STREQ(s, *cpp)) return(i); return(-1); } /* expand the macro mp */ int expmac(mp, outp, fp, inp) MACRO *mp; char **outp; FILE *fp; char **inp; { TOKEN mt; ARGS *actual; char *cp; int ac; if (mp->m_prot) { expansi(mp->m_name, outp); return(1); } actual = (mp->m_args) ? (fp) ? fgetargs(fp, 1) : sgetargs(inp) : NULL; if (mp->m_args && !actual) { error(0, "Arguments to %s needed", mp->m_name); return(0); } if (mp->m_args && mp->m_args->a_argc != actual->a_argc) { error(0, "Argument %d mismatch", (char *) mp->m_args->a_argc); delargs(actual); return(0); } cp = mp->m_val; mt.t_type = T_SPACE; for (;;) { sgettoken(&cp, 0, &mt); if (mt.t_type == T_EOLN) break; if (mt.t_type == T_WORD) { if ((ac = isarg(mt.t_token, mp->m_args)) >= 0) { (void) strcpy(*outp, actual->a_argv[ac]); *outp += strlen(actual->a_argv[ac]); continue; } } if (mt.t_type == T_HASH) { sgettoken(&cp, 1, &mt); if ((ac = isarg(mt.t_token, mp->m_args)) >= 0) { stringize(actual->a_argv[ac], outp); continue; } continue; } (void) strcpy(*outp, mt.t_token); *outp += mt.t_len; } if (actual != (ARGS *) NULL) delargs(actual); return(1); } /* expand the word s */ void expand(s, fp) char *s; FILE *fp; { MACRO *mp; TOKEN next; TOKEN mt; char one[BUFSIZ]; char two[BUFSIZ]; char *nextp; char *outp; char *inp; char *cp; char isone; int around; int rescan; (void) strcpy(one, s); isone = 1; around = 0; do { mt.t_type = next.t_type = T_SPACE; rescan = 0; inp = (isone) ? one : two; *(outp = (isone) ? two : one) = 0; isone = 1 - isone; for (;;) { sgettoken(&inp, 0, &mt); nextp = inp; sgettoken(&nextp, 1, &next); if (mt.t_type == T_EOLN) { if (mt.t_token[0] == '\n') { *outp++ = '\n'; *outp = 0; } break; } if (next.t_type == T_HASHHASH) { (void) strcpy(outp, mt.t_token); outp += mt.t_len; sgettoken(&inp, 1, &mt); /* skip ## */ sgettoken(&inp, 1, &mt); if (mt.t_type == T_EOLN) break; (void) strcpy(outp, mt.t_token); outp += mt.t_len; rescan = 1; continue; } if (mt.t_type != T_WORD) { (void) strcpy(outp, mt.t_token); outp += mt.t_len; continue; } if ((mp = isdefined(mt.t_token)) != (MACRO *) NULL && !doing(mt.t_token, around)) { push(mp->m_name, around); rescan += expmac(mp, &outp, (around == 0) ? fp : (FILE *) NULL, (around == 0) ? (char **) NULL : &inp); } else { cp = nameof(mt.t_token, mt.t_len); (void) strcpy(outp, cp); outp += strlen(cp); } } around += 1; } while (rescan); while (stackc) pop(); output((isone) ? one : two, strlen((isone) ? one : two)); } \Rogue\Monster\ else echo "will not over write ./mac.c" fi if `test ! -s ./malloc.c` then echo "writing ./malloc.c" cat > ./malloc.c << '\Rogue\Monster\' /* * @(#)malloc.c 1.1 23/01/89 15:47:28 agc * * When will they fix those library routines? Kernighan & Ritchie * memory routines. * * Compile-time flags: * ATT Unix System V.[23] * BSD BSD 4.[23] Unix * ZORTECH Zortech C++, v1.05. * TURBOC Turbo C 1.5 * MSC Microsoft C 5.0 */ #include <stdio.h> typedef int ALIGN; union header { struct { union header *next; unsigned size; } s; ALIGN x; }; typedef union header HEADER; static HEADER base; static HEADER *allocp = (HEADER *) NULL; #define NALLOC 128 void nfree(ap) char *ap; { register HEADER *p, *q; p = (HEADER *) ap - 1; for (q = allocp ; !(p >q && p <q->s.next) ; q = q->s.next) if (q >= q->s.next && (p > q || p < q->s.next)) break; if (p + p->s.size == q->s.next) { p->s.size += q->s.next->s.size; p->s.next = q->s.next->s.next; } else p->s.next = q->s.next; if (q + q->s.size == p) { q->s.size += p->s.size; q->s.next = p->s.next; } else q->s.next = p; allocp = q; } static HEADER * morecore(nu) unsigned nu; { register HEADER *up; register char *cp; register int rnu; char *sbrk(); rnu = NALLOC * ((nu + NALLOC - 1) / NALLOC); cp = sbrk(rnu * sizeof(HEADER)); if ((int) cp == -1) return((HEADER *) NULL); up = (HEADER *)cp; up->s.size = rnu; (void) nfree((char *)(up+1)); return(allocp); } char * nmalloc(nbytes) unsigned nbytes; { register HEADER *p; register HEADER *q; register int nunits; nunits = 1 + (nbytes+sizeof(HEADER)-1)/sizeof(HEADER); if ((q = allocp) == (HEADER *) NULL) { base.s.next = allocp = q = &base; base.s.size = 0; } for (p = q->s.next ; ; q = p, p = p->s.next) { if (p->s.size >= nunits) { if (p->s.size == nunits) q->s.next = p->s.next; else { p->s.size -= nunits; p += p->s.size; p->s.size = nunits; } allocp = q; return((char *)(p+1)); } if (p == allocp) if ((p = morecore(nunits)) == (HEADER *) NULL) return((char *) NULL); } } char * ncalloc(nel, nbytes) unsigned nel; unsigned nbytes; { unsigned siz = nel * nbytes; char *cp; if ((cp = nmalloc(siz)) == (char *) NULL) return((char *) NULL); #ifdef ATT memset(cp, 0, siz); #endif /* ATT */ #ifdef BSD bzero(cp, siz); #endif /* BSD */ return(cp); } \Rogue\Monster\ else echo "will not over write ./malloc.c" fi if `test ! -s ./parse.c` then echo "writing ./parse.c" cat > ./parse.c << '\Rogue\Monster\' /* * @(#)parse.c 1.8 07/02/89 15:02:12 agc * * Copyright Joypace Ltd., UK, 1989. All rights reserved. * This code may be freely distributed, provided that this * notice remains attached. * * agcpp - a version of a C pre-processor. * * parse.c - contains all the parser code * * Compile-time flags: * ATT Unix System V.[23] * BSD BSD 4.[23] Unix * ZORTECH Zortech C++, v1.05. * TURBOC Turbo C 1.5 * MSC Microsoft C 5.0 */ #ifndef lint static char *parsensccsid = "@(#)parse.c 1.8 07/02/89 15:02:12 agc"; #endif /* not lint */ #include <stdio.h> #include <ctype.h> #define EXTERN extern #include "defs.h" static char *id1 = /* first characters of an identifier */ "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char *id2 = /* subsequent characters of an identifier */ "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; /* operators of different lengths */ static char *op3[] = { ">>=", "<<=", 0 }; static char *op2[] = { "==", "!=", "++", "--", "->", "&&", "||", "+=", "-=", ">>", "<<", "*=", "/=", "%=", "&=", "|=", "^=", 0 }; static char *op1 = ";=+-*(){}[].&/%<>|^,?!~:"; #define ISNL(c) ((c) == '\r' || (c) == '\n') /* read a line into buf, folding trigraphs, returning 0 at eof, 1 otherwise */ int readline(fp) FILE *fp; { char *cp; if ((here = fgets(buf, sizeof(buf), fp)) == (char *) NULL) return(0); lineno += 1; for (cp = buf ; *cp != 0 ; ) { if (strncmp(cp, "??", 2) == 0) { cp += 2; switch(*cp++) { case '=' : *here++ = '#'; break; case '(' : *here++ = '['; break; case ')' : *here++ = ']'; break; case '<' : *here++ = '{'; break; case '>' : *here++ = '}'; break; case '/' : *here++ = '\\'; break; case '!' : *here++ = '|'; break; case '-' : *here++ = '-'; break; case '\'' : *here++ = '^'; break; default : *here++ = '?'; cp -= 2; } } else *here++ = *cp++; } *here = 0; here = buf; return(1); } /* get a token from the file, returning 0 at eof, 1 otherwise */ int gettoken(fp, ignspace, tp) FILE *fp; char ignspace; TOKEN *tp; { char **cpp; char *start; char *cp; int base; int dig; int num; int i; for (;;) { if (tp->t_type == T_EOLN) { if (!readline(fp)) return(0); } if (*here == '#') { if (*(here+1) == '#') { (void) strcpy(tp->t_token, "##"); tp->t_type = T_HASHHASH; tp->t_len = 2; here += 2; } else { (void) strcpy(tp->t_token, "#"); tp->t_type = T_HASH; tp->t_len = 1; here++; } return(1); } if (*here == '\\' && ISNL(*(here + 1))) { if (!readline(fp)) return(0); } if (ISNL(*here)) { (void) strcpy(tp->t_token, "\n"); tp->t_type = T_EOLN; tp->t_len = 1; return(1); } if (isspace(*here)) { for (start = here, i = 0 ; *here && isspace(*here) && !ISNL(*here) ; here++, i++) ; if (ignspace) continue; (void) strncpy(tp->t_token, start, i); tp->t_token[here - start] = 0; tp->t_type = T_SPACE; tp->t_len = i; return(1); } if (*here == '/' && *(here + 1) == '*') { here += 2; for (;;) { while (*here && *here != '*' && !ISNL(*here)) here++; if (*here == '*') { if (*(here + 1) == '/') break; here++; } if (*here == 0) return(0); if (ISNL(*here) && !readline(fp)) return(0); } here += 2; if (ignspace) continue; (void) strcpy(tp->t_token, " "); tp->t_type = T_SPACE; tp->t_len = 1; return(1); } if (index(id1, *here)) { for (start = here++, i = 1; *here && index(id2, *here) != (char *) NULL && i < sizeof(tp->t_token) - 1; here++, i++) ; (void) strncpy(tp->t_token, start, i); tp->t_token[i] = 0; tp->t_type = T_WORD; tp->t_len = i; return(1); } if (*here == '"') { cp = tp->t_token; *cp++ = *here++; i = 2; while (*here && *here != '"' && i<sizeof(tp->t_token)) { if (*here == '\\') { switch(*(here+1)) { case 'a' : *cp++ = ''; here += 2; i++; continue; case '\n' : if (!readline(fp)) return(0); continue; default : *cp++ = *here++; i++; } } *cp++ = *here++; i++; } if (*here == 0) { error(0, "%s in string constant", "new line"); *cp++ = *here; } else *cp++ = *here++; *cp++ = 0; tp->t_type = T_STRING; tp->t_len = i; return(1); } if (*here == '\'') { switch(*++here) { case '\\' : switch(*++here) { case 'a' : num = ''; break; case 'n' : num = '\n'; break; case 'r' : num = '\r'; break; case 'b' : num = '\b'; break; case 'f' : num = '\f'; break; case 't' : num = '\t'; break; case 'v' : num = '\v'; break; case '\\' : num = '\\'; break; case '\'' : num = '\''; here++; break; default : (void) sscanf(here, "%o", &num); break; } break; default : num = *here; } (void) sprintf(tp->t_token, "%d", num); while (*here && *here != '\'') here++; here++; tp->t_type = T_NUMBER; tp->t_len = strlen(tp->t_token); return(1); } if (isdigit(*here)) { if (*here == '0' && (*(here+1) == 'x' || *(here+1) == 'X')) { here += 2; for (num = 0; *here && isxdigit(*here) ; here++) { if (index("ABCDEF", *here) != NULL) dig = *here - 'A' + 10; else if (index("abcdef", *here) != NULL) break; else dig = *here - '0'; num = num * 16 + dig; } } else { base = (*here == '0') ? 8 : 10; for (num = 0; *here && isdigit(*here) ; here++) num = num * base + *here - '0'; } (void) sprintf(tp->t_token, "%d", num); tp->t_type = T_NUMBER; tp->t_len = strlen(tp->t_token); return(1); } for (cpp = op3 ; *cpp ; cpp++) { if (strncmp(here, *cpp, 3) == 0) { (void) strcpy(tp->t_token, *cpp); tp->t_type = T_PUNCT; tp->t_len = 3; here += 3; return(1); } } for (cpp = op2 ; *cpp ; cpp++) { if (strncmp(here, *cpp, 2) == 0) { (void) strcpy(tp->t_token, *cpp); tp->t_type = T_PUNCT; tp->t_len = 2; here += 2; return(1); } } if ((start = index(op1, *here)) != (char *) NULL) { (void) strncpy(tp->t_token, here, 1); tp->t_token[1] = 0; tp->t_type = T_PUNCT; tp->t_len = 1; here++; return(1); } error(0, "Bad character %d", (char *) *here++); } } /* get a token from *cpp */ void sgettoken(cpp, ignspace, tp) char **cpp; char ignspace; TOKEN *tp; { char **opp; char *cp; int base; int dig; int num; int i; for (;;) { cp = tp->t_token; if (**cpp == '#') { if (*(*cpp + 1) == '#') { (void) strcpy(tp->t_token, "##"); tp->t_type = T_HASHHASH; tp->t_len = 2; (*cpp) += 2; return; } *cp++ = '#'; *cp = 0; tp->t_type = T_HASH; tp->t_len = 1; (*cpp)++; return; } if (**cpp == 0) { *cp = 0; tp->t_type = T_EOLN; tp->t_len = 0; return; } if (ISNL(**cpp)) { *cp++ = **cpp; *cp = 0; tp->t_type = T_EOLN; tp->t_len = 1; return; } if (isspace(**cpp)) { for (i = 0; **cpp && isspace(**cpp) && !ISNL(**cpp) ; *cp++ = *(*cpp)++, i++) ; if (ignspace) continue; *cp = 0; tp->t_type = T_SPACE; tp->t_len = i; return; } if (**cpp == '/' && *(*cpp + 1) == '*') { *cpp += 2; while (**cpp && **cpp != '*' && *(*cpp + 1) !='/') (*cpp)++; *cpp += 2; continue; } if (index(id1, **cpp)) { for (*cp++ = *(*cpp)++, i = 1; **cpp && index(id2, **cpp) != (char *) NULL ; *cp++ = *(*cpp)++, i++) ; *cp = 0; tp->t_len = i; tp->t_type = T_WORD; return; } if (**cpp == '"') { for (*cp++ = *(*cpp)++, i = 0; **cpp && **cpp != '"' ; *cp++ = *(*cpp)++, i++) if (**cpp == '\\') { *cp++ = *(*cpp)++; i++; } *cp++ = *(*cpp)++; *cp = 0; tp->t_type = T_STRING; tp->t_len = i + 2; return; } if (isdigit(**cpp)) { if (**cpp == '0' && (*(*cpp+1) == 'x' || *(*cpp+1) == 'X')) { *cpp += 2; for (num = 0; **cpp && isxdigit(**cpp) ; (*cpp)++) { if (index("ABCDEF", **cpp) != NULL) dig = **cpp - 'A' + 10; else if (index("abcdef", **cpp) != NULL) break; else dig = **cpp - '0'; num = num * 16 + dig; } } else { base = (**cpp == '0') ? 8 : 10; for (num = 0; **cpp && isdigit(**cpp); (*cpp)++) num = num * base + **cpp - '0'; } (void) sprintf(cp, "%d", num); tp->t_type = T_NUMBER; tp->t_len = strlen(cp); return; } for (opp = op3 ; *opp ; opp++) { if (strncmp(*cpp, *opp, 3) == 0) { (void) strcpy(cp, *opp); tp->t_type = T_PUNCT; tp->t_len = 3; *cpp += 3; return; } } for (opp = op2 ; *opp ; opp++) { if (strncmp(*cpp, *opp, 2) == 0) { (void) strcpy(cp, *opp); tp->t_type = T_PUNCT; tp->t_len = 2; *cpp += 2; return; } } if (index(op1, **cpp) != (char *) NULL) { *cp++ = *(*cpp)++; *cp = 0; tp->t_type = T_PUNCT; tp->t_len = 1; return; } error(0, "Bad character %d", (char *) *(*cpp)++); } } /* flush the rest of the input line */ void clrtoeoln(fp) FILE *fp; { while (t.t_type != T_EOLN) if (!gettoken(fp, 1, &t)) break; } \Rogue\Monster\ else echo "will not over write ./parse.c" fi if `test ! -s ./proto.c` then echo "writing ./proto.c" cat > ./proto.c << '\Rogue\Monster\' /* * @(#)proto.c 1.5 07/02/89 16:25:33 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this * notice remains attached. * * agcpp - a version of a C pre-processor. * * proto.c - deal with function prototypes, and new-style argument passing. * * Compile time flags: * ATT Unix System V.[23] * BSD Unix BSD4.[23] * ZORTECH Zortech C++, v1.05 * TURBOC Turbo C, 1.5 * MSC Microsoft C, 5.0 * MINIX Minix 1.2 */ #ifndef lint static char *protonsccsid = "@(#)proto.c 1.5 07/02/89 16:25:33 agc"; #endif /* lint */ #include <stdio.h> #define EXTERN extern #include "defs.h" /* get the last word in s, and put it in out */ void getname(s, out) char *s; char *out; { TOKEN mt; mt.t_type = T_SPACE; for (;;) { sgettoken(&s, 1, &mt); if (mt.t_type == T_EOLN) return; if (mt.t_type == T_WORD) (void) strcpy(out, mt.t_token); } } /* got a function decl/definition - shuffle the args to K & R style */ void doargs(fp) FILE *fp; { TOKEN mt; ARGS *ap; char **cpp; char *cp; int i; ap = fgetargs(fp, 0); for (;;) { if (!gettoken(fp, 1, &t)) return; if (t.t_type != T_EOLN) break; } switch(t.t_token[0]) { case '{' : /* ANSI-style args, or no args at all */ if (ap->a_argc != 1 || strcmp(ap->a_argv[0], "void") != 0) { for (i = 0, cpp = ap->a_argv; i < ap->a_argc; cpp++, i++) { getname(*cpp, tmp); output(tmp, strlen(tmp)); if (i < ap->a_argc - 1) output(", ", 2); } } output(")\n", 2); if (ap->a_argc != 1 || strcmp(ap->a_argv[0], "void") != 0) { for (i = 0, cpp = ap->a_argv; i < ap->a_argc; cpp++, i++) { cp = *cpp; mt.t_type = T_SPACE; for (;;) { sgettoken(&cp, 0, &mt); if (mt.t_type == T_EOLN) break; if (mt.t_type == T_WORD) expand(mt.t_token, fp); else output(mt.t_token, mt.t_len); } output(";\n", 2); } } block++; break; case ',' : case ';' : /* forward declaration */ output(")", 1); break; default : /* old style args */ for (i = 0, cpp = ap->a_argv ; i < ap->a_argc ; cpp++, i++) { output(*cpp, strlen(*cpp)); if (i < ap->a_argc - 1) output(", ", 2); } output(")\n", 2); do { expand(t.t_token, fp); if (!gettoken(fp, 0, &t)) return; } while (t.t_token[0] != '{'); block++; } output(t.t_token, t.t_len); if (ap != (ARGS *) NULL) delargs(ap); } \Rogue\Monster\ else echo "will not over write ./proto.c" fi if `test ! -s ./sym.c` then echo "writing ./sym.c" cat > ./sym.c << '\Rogue\Monster\' #include <stdio.h> #define EXTERN extern #include "defs.h" #define MAXTYPES 256 #define MAXVARS 128 typedef struct typestr { int t_type; int t_indc; char t_flags; #define T_UNSIGNED 001 #define T_EXTERN 002 #define T_STATIC 004 #define T_REGISTER 010 #define T_CONST 020 #define T_VOLATILE 040 } TYPE; typedef struct varstr { char *v_name; TYPE *v_type; } VAR; typedef struct funcstr { VAR *f_func; int f_argc; VAR *f_argv[MAXARGS]; int f_varargs; } FUNC; typedef struct basetype { char *b_base; char *b_name; } BASE; static BASE typev[MAXTYPES]; static int typec; static TYPE *curtyp; static VAR *globs[MAXVARS]; static int globc; static VAR *locals[MAXVARS]; static int localc; static FUNC *funcs[MAXVARS]; static int funcc; int findtype(s) char *s; { BASE *bp; int i; for (i = 0, bp = typev ; i < typec ; i++, bp++) if (strcmp(s, bp->b_name) == 0) return(i); return(-1); } void inittypes() { typev[typec++].b_name = "int"; typev[typec++].b_name = "void"; typev[typec++].b_name = "char"; typev[typec++].b_name = "short"; typev[typec++].b_name = "long"; typev[typec++].b_name = "double"; typev[typec++].b_name = "float"; } TYPE * gettype(s) char **s; { char typ[BUFSIZ]; TYPE *tp; int b; int i; if (t.t_type != T_WORD) { error(0, "bad type syntax '%s'", s); return((TYPE *) NULL); } if (strcmp(t.t_token, "typedef") == 0) { sgettoken(s, 1, &t); if (strcmp(t.t_token, "struct") == 0) { (void) strcpy(typ, "struct "); sgettoken(s, 1, &t); (void) strcat(typ, t.t_token); sgettoken(s, 1, &t); if (t.t_token[0] == '{') { for (b = 1 ; b != 0 ; ) { sgettoken(s, 1, &t); if (t.t_token[0] == '{') b++; else if (t.t_token[0] == '}') b--; } } } else (void) strcpy(typ, t.t_token); sgettoken(s, 1, &t); typev[typec].b_base = strnsave(typ, strlen(typ)); typev[typec++].b_name = strnsave(t.t_token, t.t_len); return((TYPE *) NULL); } NEW(TYPE, tp); for (;;) { if (strcmp(t.t_token, "extern") == 0) { if (tp->t_flags & T_STATIC) error(0, "can't be static and external", NULL); tp->t_flags |= T_EXTERN; sgettoken(s, 1, &t); } else if (strcmp(t.t_token, "static") == 0) { if (tp->t_flags & T_EXTERN) error(0, "can't be static and external", NULL); tp->t_flags |= T_STATIC; sgettoken(s, 1, &t); } else if (strcmp(t.t_token, "unsigned") == 0) { tp->t_flags |= T_UNSIGNED; sgettoken(s, 1, &t); } else if (strcmp(t.t_token, "register") == 0) { if (tp->t_flags & T_STATIC) error(0, "can't be static and register", NULL); else tp->t_flags |= T_REGISTER; sgettoken(s, 1, &t); } else if (strcmp(t.t_token, "volatile") == 0) { tp->t_flags |= T_VOLATILE; sgettoken(s, 1, &t); } else if (strcmp(t.t_token, "const") == 0) { tp->t_flags |= T_CONST; sgettoken(s, 1, &t); } else if (t.t_token[0] == '*') { tp->t_indc++; sgettoken(s, 1, &t); } else if ((i = findtype(t.t_token)) >= 0) { tp->t_type = i; sgettoken(s, 1, &t); } else return(tp); } } VAR * getvar(s, dotsok) char **s; char dotsok; { FUNC *fp; VAR *vp; int i; if (curtyp == (TYPE *) NULL || t.t_token[0] != ',') { sgettoken(s, 1, &t); if (t.t_token[0] == '.' && dotsok) { for (i = 0 ; i < 2 ; i++) sgettoken(s, 1, &t); return((VAR *) NULL); } curtyp = gettype(s); } NEW(VAR, vp); vp->v_type = curtyp; vp->v_name = strnsave(t.t_token, t.t_len); sgettoken(s, 1, &t); if (t.t_token[0] == ';') return(vp); if (t.t_token[0] == '(') { NEW(FUNC, fp); fp->f_varargs = -1; fp->f_func = vp; for (;;) { curtyp == (TYPE *) NULL; fp->f_argv[fp->f_argc] = getvar(s, 1); if (fp->f_argv[fp->f_argc] == (VAR *) NULL) { fp->f_varargs = fp->f_argc; sgettoken(s, 1, &t); break; } if (t.t_token[0] == ')') break; fp->f_argc++; sgettoken(s, 1, &t); } funcs[funcc++] = fp; } return(vp); } \Rogue\Monster\ else echo "will not over write ./sym.c" fi echo "Finished archive 1 of 2" #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./Readme` then echo "writing ./Readme" cat > ./Readme << '\Rogue\Monster\' agcpp - ANSI C pre-processor and translator. Here is an ANSI C conforming pre-processor. It is also a translator from ANSI C to "K & R C" (with one exception, and one restriction - see below). There are also, probably, lots of bugs, which my coding style has not found. Please inform me if you find any of these. Most of the draft standard's implications, bells and whistles were taken from "The C Book, featuring the draft ANSI C standard", by Mike Banahan of The Instruction Set. This was originally written to replace the old, creaking Minix cpp, because it was driving me up the wall. As I am working in Berlin, this could get quite dangerous. Hopefully, this will allow people to write code in ANSI C, whilst continuing to use their old compilers - so start writing in ANSI C, folks. Please note that it's not quick - but I haven't optimised it yet. 1. The directives it will recognise at the moment are : #include, #define, #undef, #if, #ifdef, #ifndef, #elif, #else, #endif, #line, #error, #pragma, # I have also put the #ident processing in there, but default is not to have it. If you want it, compile agcpp with -DIDENT_DIR. 2. Token pasting (##) and token stringizing (#arg) are carried out during expansion of macros. 3. Comments are recognised as white space within macros. 4. const, volatile and signed will be passed on to the compiler, if ANSI is defined (at run-time), or silently forgotten if not. 5. Multiple whitespace within macros is folded to a single space. (Whitespace in strings is not touched). 6. Command line arguments (run time) are -ANSI for the pre-processor to output ANSI-style C. -Cnumber for the pre-processor to fold identifier name longers than <number> to an internal format of the name. This is really needed for Minix, more than anything else. Default is 8, can be over-ridden at compile-time by defining COMPCHARS, and that in term can be over-ridden at run-time by this argument. -Dsymbol[=value] for a symbol to be defined. This will override any previous definition in agcpp, but will be overridden by any definitions in the text. -Idirectory for an additional include directory to be searched before the standard ones. -P to suppress line directives for the compiler itself. -Usymbol for a symbol to be undefined. It is not an error if symbol is not already defined. 7. #if defined(macroname), and #if defined macroname will be recognised. 8. The ANSI standard's __FILE__, __LINE__, __DATE__ and __TIME__ will all be recognised and expanded. It will also recognise __STDC__ (it has the value 1). 9. It will recognise, and correctly include #define NAME <stdio.h> #define INDIRECTNAME NAME #include INDIRECTNAME (The number of layers of indirection is unlimited - although why you would want to do this is a mystery to me). 10. Character constants are reduced to decimal numbers. 11. Trigraphs are expanded. 12. Adjacent strings will be concatenated, even on different lines. 13. Unary '+' is NOT recognised - it was too difficult really, as I'd have do a syntax check of the program first, to identify unary '+' from (a - b) + (c() / d) etc. Anyway, I don't like unary '+' - I consider it ill-conceived, and horrible syntax - so I won't use it. 14. The '\a' (bell) character will be recognised in string and character constants. 15. I left "noalias" out - is it still in the standard? 16. Function prototypes. If ANSI is not specified (at run-time), these are expanded at the basic level (i.e. not within the definitions in a function). 17. New-style argument passing (including const) is performed, and translated to old (K & R) style arguments if ANSI is not specified (at run-time). Please choose one or the other method of argument passing - mixing methods in the same function will not work. 18. I have added code to test the level at which a file was included, and if an attempt is made to re-include a file twice, then it will give an error message and not include it, if the file was included more deeply in the nested includes. 19. Long name identifier folding may or may not be needed - but I took the trouble to put it in for Minix's somewhat rudimentary (8 char ids) compiler. It's not as efficient as it could be, but it takes up less space than the cpp's I've been able to look at. Main target for efficiency is all the string copying that takes place - I may pass pointers and their lengths when I get time, but that's some distance away - I'll do it the day after Spurs win the league, or Rangers do the double. I may also get around to implementing the run-time library for some systems sometime, so don't hold your breath. Constructive comments gratefully received. If you have any flames about processing time etc, take them somewhere else. Regards, Alistair G. Crooks, Joypace Ltd., 2 Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 580 753114) UUCP Europe: ...!mcvax!unido!nixpbe!nixbln!agc UUCP the rest of the world: ...!uunet!linus!nixbur!nixpbe!nixbln!agc \Rogue\Monster\ else echo "will not over write ./Readme" fi echo "Finished archive 2 of 2" exit needed - but I took the trouble to put it in for Minix's somewhat rudimentary (8 char ids) compiler. It's not as efficient as it could be, but it takes up less space than the cpp's I've been able to look at. Main target
Leisner.Henr@xerox.com (marty) (02/23/89)
The preprocessor got munged by the mail system but it seems I was able to recover it. In parse.c, line 202 I get "empty character constant" errors and sure enough, we get a line like: *cp++ = ''; Is this intentional or did something get lost in transmisssion? I haven't yet attempt to figure out what really fits in there -- I wanna see if I can get to compile and run first. marty ARPA: leisner.henr@xerox.com GV: leisner.henr NS: martin leisner:wbst139:xerox UUCP: hplabs!arisia!leisner
droege@infko.UUCP (Detlev Droege) (02/28/89)
In article <11100001@nixbln> agc@nixbln.UUCP writes: > >Here's an (almost) ANSI-C conforming pre-processor. Please note that I >haven't tested it under Minix. Please also note that there are two shell >archives here. Now, how do I post this using notes? > >Regards, >Alistair G. Crooks, Well, it's a fine idea, but there seems to be a nasty bug. I made it run on a SUN (4.2BSD) and another UNIX box (AT&T Sys V), but in both cases the "squeeze long id-names" feature didn't work. Example: main () { int long_name1; int long_name2; int long_name3; exit (0); } yields in main () { int long_name1; int i00000; int i00000; /* <<<=== baaahhh !!! */ exit (0); } I couldn't trace down the bug in agcpp itself, maybe someone else did ... Waiting for agcpp-patch#1 Detlev -- Detlev Droege, Univ. of Koblenz (EWH), Dept. of Computer Sience Rheinau 3-4, D-5400 Koblenz (West Germany) UUCP: ..!unido!infko!droege droege@infko.UUCP (Voice: +49 261 12156)
n62@np1.hep.nl (Klamer Schutte) (03/02/89)
In article <495@infko.UUCP> droege@infko.UUCP (Detlev Droege) writes: >In article <11100001@nixbln> agc@nixbln.UUCP writes: >> >>Here's an (almost) ANSI-C conforming pre-processor. Please note that I >>haven't tested it under Minix. Please also note that there are two shell >>archives here. Now, how do I post this using notes? >> >>Regards, >>Alistair G. Crooks, > >Well, it's a fine idea, but there seems to be a nasty bug. > description of the bug involving folding of long names >Detlev Droege, Univ. of Koblenz (EWH), Dept. of Computer Sience > Rheinau 3-4, D-5400 Koblenz (West Germany) >UUCP: ..!unido!infko!droege droege@infko.UUCP (Voice: +49 261 12156) I also did encounter 2 bugs in it: 1 the -ANSI command line flag didn't work; prototyped function came out not-prototyped. 2 the following code #define PARMS(arg) arg void some_function PARMS((int arg1, int arg2)); did produce void some_function (intargs1,intarg2); when it should first map the macro to void some_function (int arg1, int arg2); and then make it to void some_function (); I wanted to use this macro to make the same code run with a non-ansi compiler; this will use the macro #define PARMS(arg) /* arg */ I don't mind about bug 1; when somebody fixes bug 2 i will start using the program. Klamer ps all running under minix-st with the ACK compiler -- ________________________________________________________________________________ Klamer Schutte mcvax!nikhefh!n62 n62@nikhefh.hep.nl
agc@nixbln.UUCP (03/03/89)
Well, at least agcpp got out of here - that's about all you can say. 1. Marty Leisner (leisner@arisia.UUCP) said that the BELL characters hadn't made it across the pond. Fixes (below) to parse.c should sort this. Thanks, Marty. Sorry, everybody. 2. Detlev Droege (droege@infko.UUCP) pointed out the long-name folding didn't work correctly. The following fix to id.c should cure it. Danke, Detlev. 3. Klamer Schutte (n62@nikhefh.hep.nl) said that the ANSI argument removed the ANSI-style arguments. Unfortunately, I can't reproduce this. Script started on Fri Mar 3 12:22:51 1989 % cat t1 char *strnsave(char *s, int n); main() { } % agcpp -ANSI t1 char *strnsave(char *s, int n); main() { } % exit % script done on Fri Mar 3 12:23:07 1989 Can you give me some more info, Klamer? Alstublieft. 4. Klamer also pointed out a rather nasty bug which prevented white space being expanded within macro arguments. Following fix to mac.c should cure this. Dank je wel, Klamer. 5. I have also noticed that ANSI C varargs style functions will be expanded wrongly - the fixes to proto.c should cure this. 6. If anyone finds out what the sym.c file does, could they tell me please! So official fixes(#1) to agcpp follow. Thanks once again to everyone for bug reports. Please keep them coming - I'm sure that together we can manage a working space-efficient pre-processor sometime. Regards, Gruessen, Groetjes... Alistair G. Crooks. Joypace Ltd., 2 Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 580 753114) UUCP Europe: ...!mcvax!unido!nixpbe!nixbln!agc UUCP the rest of the world: ...!uunet!linus!nixbur!nixpbe!nixbln!agc P.S. Anyone want to employ a tall Scot who writes pre-processors in his spare time, can speak English and German, and can muddle along in Dutch? *** id.c.old --- id.c ************** *** 1,5 /* ! * @(#)id.c 1.1 09/02/89 18:21:55 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this --- 1,5 ----- /* ! * @(#)id.c 1.2 03/03/89 12:08:35 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this ************** *** 18,24 * MINIX Minix 1.2 */ #ifndef lint ! static char *idnsccsid = "@(#)id.c 1.1 09/02/89 18:21:55 agc"; #endif /* not lint */ #include <stdio.h> --- 18,24 ----- * MINIX Minix 1.2 */ #ifndef lint ! static char *idnsccsid = "@(#)id.c 1.2 03/03/89 12:08:35 agc"; #endif /* not lint */ #include <stdio.h> ************** *** 39,45 } HID; static HID ids[HASHTABLEN]; - static int idnum; void addid(old, new) --- 39,44 ----- } HID; static HID ids[HASHTABLEN]; void addid(old, new) ************** *** 122,127 newid() { static char idname[10]; for (;;) { (void) sprintf(idname, "i%05d", idnum); --- 121,127 ----- newid() { static char idname[10]; + static int idnum; for (;;) { (void) sprintf(idname, "i%05d", idnum); ************** *** 125,130 for (;;) { (void) sprintf(idname, "i%05d", idnum); if (getclash(idname) == (char *) NULL) return(idname); idnum = (idnum == 99999) ? 0 : idnum + 1; --- 125,131 ----- for (;;) { (void) sprintf(idname, "i%05d", idnum); + idnum = (idnum == 99999) ? 0 : idnum + 1; if (getclash(idname) == (char *) NULL) return(idname); } ************** *** 127,133 (void) sprintf(idname, "i%05d", idnum); if (getclash(idname) == (char *) NULL) return(idname); - idnum = (idnum == 99999) ? 0 : idnum + 1; } } --- 128,133 ----- idnum = (idnum == 99999) ? 0 : idnum + 1; if (getclash(idname) == (char *) NULL) return(idname); } } *** mac.c.old --- mac.c ************** *** 1,5 /* ! * @(#)mac.c 1.11 09/02/89 18:22:10 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this --- 1,5 ----- /* ! * @(#)mac.c 1.12 03/03/89 12:08:45 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this ************** *** 18,24 * MINIX Minix 1.2 */ #ifndef lint ! static char *macnsccsid = "@(#)mac.c 1.11 09/02/89 18:22:10 agc"; #endif /* not lint */ #include <stdio.h> --- 18,24 ----- * MINIX Minix 1.2 */ #ifndef lint ! static char *macnsccsid = "@(#)mac.c 1.12 03/03/89 12:08:45 agc"; #endif /* not lint */ #include <stdio.h> ************** *** 226,232 } NEW(ARGS, ap); for (;;) { ! if (!gettoken(fp, bracket, &t)) error(1, "bad macro format", (char *) NULL); switch(t.t_token[0]) { case ',' : --- 226,232 ----- } NEW(ARGS, ap); for (;;) { ! if (!gettoken(fp, 0, &t)) error(1, "bad macro format", (char *) NULL); switch(t.t_token[0]) { case ',' : *** parse.c.old --- parse.c ************** *** 1,5 /* ! * @(#)parse.c 1.8 07/02/89 15:02:12 agc * * Copyright Joypace Ltd., UK, 1989. All rights reserved. * This code may be freely distributed, provided that this --- 1,5 ----- /* ! * @(#)parse.c 1.9 03/03/89 12:08:40 agc * * Copyright Joypace Ltd., UK, 1989. All rights reserved. * This code may be freely distributed, provided that this ************** *** 17,23 * MSC Microsoft C 5.0 */ #ifndef lint ! static char *parsensccsid = "@(#)parse.c 1.8 07/02/89 15:02:12 agc"; #endif /* not lint */ #include <stdio.h> --- 17,23 ----- * MSC Microsoft C 5.0 */ #ifndef lint ! static char *parsensccsid = "@(#)parse.c 1.9 03/03/89 12:08:40 agc"; #endif /* not lint */ #include <stdio.h> ************** *** 44,49 #define ISNL(c) ((c) == '\r' || (c) == '\n') /* read a line into buf, folding trigraphs, returning 0 at eof, 1 otherwise */ int --- 44,51 ----- #define ISNL(c) ((c) == '\r' || (c) == '\n') + #define BELL 007 + /* read a line into buf, folding trigraphs, returning 0 at eof, 1 otherwise */ int ************** *** 199,205 if (*here == '\\') { switch(*(here+1)) { case 'a' : ! *cp++ = ''; here += 2; i++; continue; --- 201,207 ----- if (*here == '\\') { switch(*(here+1)) { case 'a' : ! *cp++ = BELL; here += 2; i++; continue; ************** *** 230,236 case '\\' : switch(*++here) { case 'a' : ! num = ''; break; case 'n' : num = '\n'; --- 232,238 ----- case '\\' : switch(*++here) { case 'a' : ! num = BELL; break; case 'n' : num = '\n'; *** proto.c.old --- proto.c ************** *** 1,5 /* ! * @(#)proto.c 1.5 07/02/89 16:25:33 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this --- 1,5 ----- /* ! * @(#)proto.c 1.6 03/03/89 12:08:47 agc * * Copyright Joypace Ltd, UK, 1989. All rights reserved. * This file may be freely distributed provided that this ************** *** 18,24 * MINIX Minix 1.2 */ #ifndef lint ! static char *protonsccsid = "@(#)proto.c 1.5 07/02/89 16:25:33 agc"; #endif /* lint */ #include <stdio.h> --- 18,24 ----- * MINIX Minix 1.2 */ #ifndef lint ! static char *protonsccsid = "@(#)proto.c 1.6 03/03/89 12:08:47 agc"; #endif /* lint */ #include <stdio.h> ************** *** 38,45 mt.t_type = T_SPACE; for (;;) { sgettoken(&s, 1, &mt); - if (mt.t_type == T_EOLN) - return; if (mt.t_type == T_WORD) (void) strcpy(out, mt.t_token); } --- 38,43 ----- mt.t_type = T_SPACE; for (;;) { sgettoken(&s, 1, &mt); if (mt.t_type == T_WORD) (void) strcpy(out, mt.t_token); if (mt.t_token[0] == '.' && strcmp(s, "..") == 0) { ************** *** 42,47 return; if (mt.t_type == T_WORD) (void) strcpy(out, mt.t_token); } } --- 40,51 ----- sgettoken(&s, 1, &mt); if (mt.t_type == T_WORD) (void) strcpy(out, mt.t_token); + if (mt.t_token[0] == '.' && strcmp(s, "..") == 0) { + (void) strcpy(out, "..."); + return; + } + if (mt.t_type == T_EOLN) + return; } } ************** *** 55,60 ARGS *ap; char **cpp; char *cp; int i; ap = fgetargs(fp, 0); --- 59,65 ----- ARGS *ap; char **cpp; char *cp; + int var = -1; int i; ap = fgetargs(fp, 0); ************** *** 72,77 i < ap->a_argc; cpp++, i++) { getname(*cpp, tmp); output(tmp, strlen(tmp)); if (i < ap->a_argc - 1) output(", ", 2); --- 77,87 ----- i < ap->a_argc; cpp++, i++) { getname(*cpp, tmp); + if (strcmp(&tmp[strlen(tmp) - 3], "...") == 0) { + output("va_alist", 8); + var = i; + break; + } output(tmp, strlen(tmp)); if (i < ap->a_argc - 1) output(", ", 2); ************** *** 82,87 for (i = 0, cpp = ap->a_argv; i < ap->a_argc; cpp++, i++) { cp = *cpp; mt.t_type = T_SPACE; for (;;) { --- 92,101 ----- for (i = 0, cpp = ap->a_argv; i < ap->a_argc; cpp++, i++) { + if (i == var) { + output("char *va_alist;\n", 16); + break; + } cp = *cpp; mt.t_type = T_SPACE; for (;;) {