static char sccsid
[] = "@(#)cpp.c 1.4 %G%";
/* written by John F. Reiser
/* some code depends on whether characters are sign or zero extended */
/* #if '\377' < 0 not used here, old cpp doesn't understand */
#define ALFSIZ 512 /* alphabet size */
#define ALFSIZ 256 /* alphabet size */
/* a superimposed code is used to reduce the number of calls to the
/* symbol table lookup routine. (if the kth character of an identifier
/* is 'a' and there are no macro names whose kth character is 'a'
/* then the identifier cannot be a macro name, hence there is no need
/* to look in the symbol table.) 'scw1' enables the test based on
/* single characters and their position in the identifier. 'scw2'
/* enables the test based on adjacent pairs of characters and their
/* position in the identifier. scw1 typically costs 1 indexed fetch,
/* an AND, and a jump per character of identifier, until the identifier
/* is known as a non-macro name or until the end of the identifier.
/* scw1 is inexpensive. scw2 typically costs 4 indexed fetches,
/* an add, an AND, and a jump per character of identifier, but it is also
/* slightly more effective at reducing symbol table searches.
/* scw2 usually costs too much because the symbol table search is
/* usually short; but if symbol table search should become expensive,
/* using both scw1 and scw2 is of dubious value.
char t21
[ALFSIZ
],t22
[ALFSIZ
],t23
[ALFSIZ
+NCPS
];
#define isslo (ptrtab==(slotab+COFF))
#define isid(a) ((fastab+COFF)[a]&IB)
#define isspc(a) (ptrtab[a]&SB)
#define isnum(a) ((fastab+COFF)[a]&NB)
#define iscom(a) ((fastab+COFF)[a]&CB)
#define isquo(a) ((fastab+COFF)[a]&QB)
#define iswarn(a) ((fastab+COFF)[a]&WB)
#define eob(a) ((a)>=pend)
#define bob(a) (pbeg>=(a))
char buffer
[NCPS
+BUFSIZ
+BUFSIZ
+NCPS
];
# define SBSIZE 60000 /* std = 12000, wnj aug 1979 */
# define DROP 0xFE /* special character not legal ASCII or EBCDIC */
# define MAXFRE 14 /* max buffers of macro pushback */
# define MAXFRM 31 /* max number of formals/actuals to a macro */
static char warnc
= WARN
;
char *instack
[MAXFRE
],*bufstack
[MAXFRE
],*endbuf
[MAXFRE
];
int plvl
; /* parenthesis level during scan for macro actuals */
int maclin
; /* line number of macro call requiring actuals */
char *macfil
; /* file name of macro call requiring actuals */
char *macnam
; /* name of macro requiring actuals */
int maclvl
; /* # calls since last decrease in nesting level */
char *macforw
; /* pointer which must be exceeded to decrease nesting level */
int macdam
; /* offset to macforw due to buffer shifting */
int tgpscan
; /* flag for dump(); */
STATIC
int inctop
[MAXINC
];
STATIC
char *fnames
[MAXINC
];
STATIC
char *dirnams
[MAXINC
]; /* actual directory of #include files */
STATIC
int lineno
[MAXINC
];
STATIC
char *dirs
[10]; /* -I and <> directories */
char *strdex(), *copy(), *subst(), *trmdir();
STATIC
FILE *fout
= stdout
;
STATIC
int pflag
; /* don't put out lines "# 12 foo.c" */
STATIC
int passcom
; /* don't delete comments */
STATIC
int rflag
; /* allow macro recursion */
STATIC
char *prespc
[NPREDEF
];
STATIC
char **predef
= prespc
;
STATIC
char *punspc
[NPREDEF
];
STATIC
char **prund
= punspc
;
} *lastsym
, *lookup(), *slookup();
# define exit(S) longjmp(env, 1)
# define open(S,D) fileno(fopen(S, "r"))
# define close(F) fclose(_f[F])
# define symsiz 1500 /* std = 500, wnj aug 1979 */
STATIC
struct symtab stab
[symsiz
];
STATIC
struct symtab
*defloc
;
STATIC
struct symtab
*udfloc
;
STATIC
struct symtab
*incloc
;
STATIC
struct symtab
*ifloc
;
STATIC
struct symtab
*elsloc
;
STATIC
struct symtab
*eifloc
;
STATIC
struct symtab
*ifdloc
;
STATIC
struct symtab
*ifnloc
;
STATIC
struct symtab
*ysysloc
;
STATIC
struct symtab
*varloc
;
STATIC
struct symtab
*lneloc
;
STATIC
struct symtab
*ulnloc
;
STATIC
struct symtab
*uflloc
;
if (pflag
==0) fprintf(fout
,"# %d \"%s\"\n", lineno
[ifno
], fnames
[ifno
]);
/* most of the scanning takes place in the buffer:
/* (low address) (high address)
/* | <-- BUFSIZ chars --> | <-- BUFSIZ chars --> |
/* _______________________________________________________________________
/* |_______________________________________________________________________|
/* |<-- waiting -->| |<-- waiting -->
/* | to be |<-- current -->| to be
/* | written | token | scanned
/* *outp first char not yet written to output file
/* *inp first char of current token
/* *p first char not yet scanned
/* macro expansion: write from *outp to *inp (chars waiting to be written),
/* ignore from *inp to *p (chars of the macro call), place generated
/* characters in front of *p (in reverse order), update pointers,
/* symbol table pointers point to just beyond the end of macro definitions;
/* the first preceding character is the number of formal parameters.
/* the appearance of a formal in the body of a definition is marked by
/* 2 chars: the char WARN, and a char containing the parameter number.
/* the first char of a definition is preceded by a zero character.
/* when macro expansion attempts to back up over the beginning of the
/* buffer, some characters preceding *pend are saved in a side buffer,
/* the address of the side buffer is put on 'instack', and the rest
/* of the main buffer is moved to the right. the end of the saved buffer
/* is kept in 'endbuf' since there may be nulls in the saved buffer.
/* similar action is taken when an 'include' statement is processed,
/* except that the main buffer must be completely emptied. the array
/* element 'inctop[ifno]' records the last side buffer saved when
/* file 'ifno' was included. these buffers remain dormant while
/* the file is being read, and are reactivated at end-of-file.
/* instack[0 : mactop] holds the addresses of all pending side buffers.
/* instack[inctop[ifno]+1 : mactop-1] holds the addresses of the side
/* buffers which are "live"; the side buffers instack[0 : inctop[ifno]]
/* are dormant, waiting for end-of-file on the current file.
/* space for side buffers is obtained from 'savch' and is never returned.
/* bufstack[0:fretop-1] holds addresses of side buffers which
/* are available for use.
/* write part of buffer which lies between outp and inp .
/* this should be a direct call to 'write', but the system slows to a crawl
/* if it has to do an unaligned copy. thus we buffer. this silly loop
/* is 15% of the total time, thus even the 'putc' macro is too slow.
register char *p1
,*p2
; register FILE *f
;
if ((p1
=outp
)==inp
|| flslvl
!=0) return;
if (!tgpscan
) {/* scan again to insure <= MAXOUT chars between linefeeds */
register char c
,*pblank
; char savc
,stopc
,brk
;
tgpscan
=1; brk
=stopc
=pblank
=0; p2
=inp
; savc
= *p2
; *p2
='\0';
else if (c
=='"' || c
=='\'') stopc
=c
;
if (p1
-outp
>MAXOUT
&& pblank
!=0) {
*pblank
++='\n'; inp
=pblank
; dump(); brk
=1; pblank
=0;
if (c
==' ' && stopc
==0) pblank
=p1
-1;
*p2
=savc
; inp
=p2
; p1
=outp
; tgpscan
=0;
/* filter out "$ program c" card if first line of input */
/* gmatch is a simple pattern matcher in the GCOS Standard Library */
{ static int gmfirst
= 0;
if (gmatch(p1
, "^$*program[ \t]*c*"))
while (p1
<inp
) putc(*p1
++,f
);
refill(p
) register char *p
; {
/* dump buffer. save chars from inp to p. read into buffer at pbuf,
/* contiguous with p. update pointers, return new p.
register char *np
,*op
; register int ninbuf
;
dump(); np
=pbuf
-(p
-inp
); op
=inp
;
if (bob(np
+1)) {pperror("token too long"); np
=pbeg
; p
=inp
+BUFSIZ
;}
macdam
+= np
-inp
; outp
=inp
=np
;
while (op
<p
) *np
++= *op
++;
if (mactop
>inctop
[ifno
]) {/* retrieve hunk of pushed-back macro text */
op
=instack
[--mactop
]; np
=pbuf
;
do {while (*np
++= *op
++);} while (op
<endbuf
[mactop
]); pend
=np
-1;
/* make buffer space avail for 'include' processing */
if (fretop
<MAXFRE
) bufstack
[fretop
++]=instack
[mactop
];
} else {/* get more text from file(s) */
if (0<(ninbuf
=read(fin
,pbuf
,BUFSIZ
))) {
pend
=pbuf
+ninbuf
; *pend
='\0';
/* end of #include file */
if (ifno
==0) {/* end of input */
int n
=plvl
,tlin
=lineno
[ifno
]; char *tfil
=fnames
[ifno
];
lineno
[ifno
]=maclin
; fnames
[ifno
]=macfil
;
pperror("%s: unterminated macro call",macnam
);
lineno
[ifno
]=tlin
; fnames
[ifno
]=tfil
;
np
=p
; *np
++='\n'; /* shut off unterminated quoted string */
while (--n
>=0) *np
++=')'; /* supply missing parens */
pend
=np
; *np
='\0'; if (plvl
<0) plvl
=0;
inp
=p
; dump(); exit(exfail
);
close(fin
); fin
=fins
[--ifno
]; dirs
[0]=dirnams
[ifno
]; sayline();
cotoken(p
) register char *p
; {
register int c
,i
; char quoc
;
if (state
!=BEG
) goto prevlf
;
if (eob(--p
)) {p
=refill(p
); goto again
;}
else ++p
; /* ignore null byte */
case '|': case '&': for (;;) {/* sloscan only */
if (eob(--p
)) p
=refill(p
);
case '=': case '!': for (;;) {/* sloscan only */
if (eob(--p
)) p
=refill(p
);
case '<': case '>': for (;;) {/* sloscan only */
if (*p
++=='=' || p
[-2]==p
[-1]) break;
if (eob(--p
)) p
=refill(p
);
if (*p
++=='\n') {++lineno
[ifno
]; break;}
if (eob(--p
)) p
=refill(p
);
if (*p
++=='*') {/* comment */
if (!passcom
) {inp
=p
-2; dump(); ++flslvl
;}
if (p
[-1]=='*') for (;;) {
if (*p
++=='/') goto endcom
;
if (!passcom
) {inp
=p
; p
=refill(p
);}
else if ((p
-inp
)>=BUFSIZ
) {/* split long comment */
inp
=p
; p
=refill(p
); /* last char written is '*' */
putc('/',fout
); /* terminate first part */
/* and fake start of 2nd */
outp
=inp
=p
-=3; *p
++='/'; *p
++='*'; *p
++='*';
} else if (p
[-1]=='\n') {
++lineno
[ifno
]; if (!passcom
) putc('\n',fout
);
if (!passcom
) {inp
=p
; p
=refill(p
);}
else if ((p
-inp
)>=BUFSIZ
) {/* split long comment */
putc('*',fout
); putc('/',fout
);
outp
=inp
=p
-=2; *p
++='/'; *p
++='*';
} else ++p
; /* ignore null byte */
if (!passcom
) {outp
=inp
=p
; --flslvl
; goto again
;}
if (eob(--p
)) p
=refill(p
);
if (p
[-1]=='\n') {--p
; break;} /* bare \n terminates quotation */
if (p
[-1]=='\\') for (;;) {
if (*p
++=='\n') {++lineno
[ifno
]; break;} /* escaped \n ignored */
if (eob(--p
)) p
=refill(p
);
} else if (eob(--p
)) p
=refill(p
);
else ++p
; /* it was a different quote character */
++lineno
[ifno
]; if (isslo
) {state
=LF
; return(p
);}
if (*p
++=='#') return(p
);
if (eob(inp
= --p
)) p
=refill(p
);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (eob(--p
)) p
=refill(p
);
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
#define tmac1(c,bit) if (!xmac1(c,bit,&)) goto nomac
#define xmac1(c,bit,op) ((macbit+COFF)[c] op (bit))
#define tmac2(c0,c1,cpos) if (!xmac2(c0,c1,cpos,&)) goto nomac
#define xmac2(c0,c1,cpos,op)\
((macbit+COFF)[(t21+COFF)[c0]+(t22+COFF)[c1]] op (t23+COFF+cpos)[c0])
#define tmac2(c0,c1,cpos)
#define xmac2(c0,c1,cpos,op)
i
= *p
++; if (!isid(i
)) goto endid
; tmac1(i
,b1
); tmac2(c
,i
,0);
c
= *p
++; if (!isid(c
)) goto endid
; tmac1(c
,b2
); tmac2(i
,c
,1);
i
= *p
++; if (!isid(i
)) goto endid
; tmac1(i
,b3
); tmac2(c
,i
,2);
c
= *p
++; if (!isid(c
)) goto endid
; tmac1(c
,b4
); tmac2(i
,c
,3);
i
= *p
++; if (!isid(i
)) goto endid
; tmac1(i
,b5
); tmac2(c
,i
,4);
c
= *p
++; if (!isid(c
)) goto endid
; tmac1(c
,b6
); tmac2(i
,c
,5);
i
= *p
++; if (!isid(i
)) goto endid
; tmac1(i
,b7
); tmac2(c
,i
,6);
if (eob(--p
)) {refill(p
); p
=inp
+1; continue;}
if (eob(--p
)) {refill(p
); p
=inp
+1; continue;}
tmac2(p
[-1],0,-1+(p
-inp
));
slookup(inp
,p
,0); if (newp
) {p
=newp
; goto again
;}
if (eob(--p
)) {p
=refill(p
); goto nomac
;}
} /* end of infinite loop */
skipbl(p
) register char *p
; {/* get next non-blank token */
do {outp
=inp
=p
; p
=cotoken(p
);} while ((toktyp
+COFF
)[*inp
]==BLANK
);
unfill(p
) register char *p
; {
/* take <= BUFSIZ chars from right end of buffer and put them on instack .
/* slide rest of buffer to the right, update pointers, return new p.
register char *np
,*op
; register int d
;
pperror("%s: too much pushback",macnam
);
p
=inp
=pend
; dump(); /* begin flushing pushback */
while (mactop
>inctop
[ifno
]) {p
=refill(p
); p
=inp
=pend
; dump();}
if (fretop
>0) np
=bufstack
[--fretop
];
if (savch
>=sbf
+SBSIZE
) {pperror("no space"); exit(exfail
);}
instack
[mactop
]=np
; op
=pend
-BUFSIZ
; if (op
<p
) op
=p
;
for (;;) {while (*np
++= *op
++); if (eob(op
)) break;} /* out with old */
endbuf
[mactop
++]=np
; /* mark end of saved text */
np
=pbuf
+BUFSIZ
; op
=pend
-BUFSIZ
; pend
=np
; if (op
<p
) op
=p
;
while (outp
<op
) *--np
= *--op
; /* slide over new */
if (bob(np
)) pperror("token too long");
d
=np
-outp
; outp
+=d
; inp
+=d
; macdam
+=d
; return(p
+d
);
doincl(p
) register char *p
; {
register char *cp
; char **dirp
,*nfil
; char filname
[BUFSIZ
];
if (*inp
++=='<') {/* special <> syntax */
++flslvl
; /* prevent macro expansion */
outp
=inp
=p
; p
=cotoken(p
);
if (*inp
=='\n') {--p
; *cp
='\0'; break;}
if (*inp
=='>') { *cp
='\0'; break;}
if (*inp
=='.' && !intss()) *inp
='#';
while (inp
<p
) *cp
++= *inp
++;
--flslvl
; /* reenable macro expansion */
} else if (inp
[-1]=='"') {/* regular "" syntax */
while (inp
<p
) {if (*inp
=='.' && !intss()) *inp
='#'; *cp
++= *inp
++;}
while (inp
<p
) *cp
++= *inp
++;
if (*--cp
=='"') *cp
='\0';
} else {pperror("bad include syntax",0); inctype
=2;}
/* flush current file to \n , then write \n */
++flslvl
; do {outp
=inp
=p
; p
=cotoken(p
);} while (*inp
!='\n'); --flslvl
;
inp
=p
; dump(); if (inctype
==2) return(p
);
/* look for included file */
pperror("Unreasonable include nesting",0); return(p
);
if((nfil
=savch
)>sbf
+SBSIZE
-BUFSIZ
) {pperror("no space"); exit(exfail
);}
for (dirp
=dirs
+inctype
; *dirp
; ++dirp
) {
|| **dirp
=='\0') strcpy(nfil
,filname
);
if (0<(fins
[ifno
+1]=open(nfil
,READ
))) {
filok
=1; fin
=fins
[++ifno
]; break;
if (filok
==0) pperror("Can't find include file %s",filname
);
lineno
[ifno
]=1; fnames
[ifno
]=cp
=nfil
; while (*cp
++); savch
=cp
;
dirnams
[ifno
]=dirs
[0]=trmdir(copy(nfil
));
/* save current contents of buffer */
while (!eob(p
)) p
=unfill(p
);
equfrm(a
,p1
,p2
) register char *a
,*p1
,*p2
; {
register char c
; int flag
;
flag
=strcmp(a
,p1
); *p2
=c
; return(flag
==SAME
);
dodef(p
) char *p
; {/* process '#define' */
register char *pin
,*psav
,*cf
;
char **pf
,**qf
; int b
,c
,params
; struct symtab
*np
;
char *formal
[MAXFRM
]; /* formal[n] is name of nth formal */
char formtxt
[BUFSIZ
]; /* space for formal names */
if (savch
>sbf
+SBSIZE
-BUFSIZ
) {pperror("too much defining"); return(p
);}
oldsavch
=savch
; /* to reclaim space if redefinition */
++flslvl
; /* prevent macro expansion during 'define' */
if ((toktyp
+COFF
)[*pin
]!=IDENT
) {
ppwarn("illegal macro name"); while (*inp
!='\n') p
=skipbl(p
); return(p
);
if (oldval
=np
->value
) savch
=oldsavch
; /* was previously defined */
while (cf
<p
) {/* update macbit */
c
= *cf
++; xmac1(c
,b
,|=); b
=(b
+b
)&0xFF;
if (cf
!=p
) xmac2(c
,*cf
,-1+(cf
-pin
),|=);
else xmac2(c
,0,-1+(cf
-pin
),|=);
params
=0; outp
=inp
=p
; p
=cotoken(p
); pin
=inp
;
if (*pin
=='(') {/* with parameters; identify the formals */
--lineno
[ifno
]; --p
; pperror("%s: missing )",np
->name
); break;
if ((toktyp
+COFF
)[*pin
]!=IDENT
) {
c
= *p
; *p
='\0'; pperror("bad formal: %s",pin
); *p
=c
;
} else if (pf
>= &formal
[MAXFRM
]) {
c
= *p
; *p
='\0'; pperror("too many formals: %s",pin
); *p
=c
;
*pf
++=cf
; while (pin
<p
) *cf
++= *pin
++; *cf
++='\0'; ++params
;
if (params
==0) --params
; /* #define foo() ... */
} else if (*pin
=='\n') {--lineno
[ifno
]; --p
;}
/* remember beginning of macro body, so that we can
/* warn if a redefinition is different from old value.
for (;;) {/* accumulate definition until linefeed */
outp
=inp
=p
; p
=cotoken(p
); pin
=inp
;
if (*pin
=='\\' && pin
[1]=='\n') {putc('\n',fout
); continue;} /* ignore escaped lf */
if (params
) {/* mark the appearance of formals in the definiton */
if ((toktyp
+COFF
)[*pin
]==IDENT
) {
for (qf
=pf
; --qf
>=formal
; ) {
*psav
++=qf
-formal
+1; *psav
++=WARN
; pin
=p
; break;
} else if (*pin
=='"' || *pin
=='\''
) {/* inside quotation marks, too */
for (*psav
++= *pin
++; pin
<p
&& *pin
!=quoc
; ) {
while (pin
<p
&& !isid(*pin
)) *psav
++= *pin
++;
cf
=pin
; while (cf
<p
&& isid(*cf
)) ++cf
;
for (qf
=pf
; --qf
>=formal
; ) {
if (equfrm(*qf
,pin
,cf
)) {
*psav
++=qf
-formal
+1; *psav
++=WARN
; pin
=cf
; break;
while (pin
<cf
) *psav
++= *pin
++;
while (pin
<p
) *psav
++= *pin
++;
*psav
++=params
; *psav
++='\0';
if ((cf
=oldval
)!=NULL
) {/* redefinition */
--cf
; /* skip no. of params, which may be zero */
while (*--cf
); /* go back to the beginning */
if (0!=strcmp(++cf
,oldsavch
)) {/* redefinition different from old */
--lineno
[ifno
]; ppwarn("%s redefined",np
->name
); ++lineno
[ifno
];
} else psav
=oldsavch
; /* identical redef.; reclaim space */
--flslvl
; inp
=pin
; savch
=psav
; return(p
);
#define fasscan() ptrtab=fastab+COFF
#define sloscan() ptrtab=slotab+COFF
control(p
) register char *p
; {/* find and handle preprocessor control lines */
register struct symtab
*np
;
fasscan(); p
=cotoken(p
); if (*inp
=='\n') ++inp
; dump();
*--inp
=SALT
; outp
=inp
; ++flslvl
; np
=slookup(inp
,p
,0); --flslvl
;
if (np
==defloc
) {/* define */
if (flslvl
==0) {p
=dodef(p
); continue;}
} else if (np
==incloc
) {/* include */
if (flslvl
==0) {p
=doincl(p
); continue;}
} else if (np
==ifnloc
) {/* ifndef */
++flslvl
; p
=skipbl(p
); np
=slookup(inp
,p
,0); --flslvl
;
if (flslvl
==0 && np
->value
==0) ++trulvl
;
} else if (np
==ifdloc
) {/* ifdef */
++flslvl
; p
=skipbl(p
); np
=slookup(inp
,p
,0); --flslvl
;
if (flslvl
==0 && np
->value
!=0) ++trulvl
;
} else if (np
==eifloc
) {/* endif */
if (flslvl
) {if (--flslvl
==0) sayline();}
else if (trulvl
) --trulvl
;
else pperror("If-less endif",0);
} else if (np
==elsloc
) {/* else */
if (--flslvl
!=0) ++flslvl
;
else {++trulvl
; sayline();}
else if (trulvl
) {++flslvl
; --trulvl
;}
else pperror("If-less else",0);
} else if (np
==udfloc
) {/* undefine */
++flslvl
; p
=skipbl(p
); slookup(inp
,p
,DROP
); --flslvl
;
} else if (np
==ifloc
) {/* if */
pperror(" IF not implemented, true assumed", 0);
if (flslvl
==0) ++trulvl
; else ++flslvl
;
if (flslvl
==0 && yyparse()) ++trulvl
; else ++flslvl
;
} else if (np
==lneloc
) {/* line */
if (flslvl
==0 && pflag
==0) {
char *cp
, *cp2
, *savestring();
outp
=inp
=p
; *--outp
='#'; while (*inp
!='\n') p
=cotoken(p
);
while (isspace(*cp
) && cp
< inp
)
while (isdigit(*cp
) && cp
< inp
)
while (*cp
!= '"' && cp
< inp
)
while (*cp2
!= '"' && cp2
< inp
)
fnames
[ifno
] = savestring(cp
, cp2
);
} else if (*++inp
=='\n') outp
=inp
; /* allows blank line after # */
else pperror("undefined control",0);
++flslvl
; while (*inp
!='\n') {outp
=inp
=p
; p
=cotoken(p
);} --flslvl
;
savestring(start
, finish
)
register char *start
, *finish
;
retbuf
= (char *) calloc(finish
- start
+ 1, sizeof (char));
stsym(s
) register char *s
; {
char buf
[BUFSIZ
]; register char *p
;
/* make definition look exactly like end of #define line */
/* copy to avoid running off end of world when param list is at end */
p
=buf
; while (*p
++= *s
++);
p
=buf
; while (isid(*p
++)); /* skip first identifier */
if (*--p
=='=') {*p
++=' '; while (*p
++);}
else {s
=" 1"; while (*p
++= *s
++);}
sloscan(); dodef(buf
); return(lastsym
);
ppsym(s
) char *s
; {/* kluge */
register struct symtab
*sp
;
cinit
=SALT
; *savch
++=SALT
; sp
=stsym(s
); --sp
->name
; cinit
=0; return(sp
);
pperror(s
,x
,y
) char *s
; {
if (fnames
[ifno
][0]) fprintf(stderr
,
"*%c* \"%s\", line ", exfail
>= 0 ? 'F' : 'W',
fprintf(stderr
, "%d: ",lineno
[ifno
]);
fprintf(stderr
, s
, x
, y
);
yyerror(s
,a
,b
) char *s
; {
register int c
, i
; int around
;
register struct symtab
*sp
;
/* namep had better not be too long (currently, <=NCPS chars) */
np
=namep
; around
=0; i
=cinit
;
while (c
= *np
++) i
+= i
+c
; c
=i
; /* c=i for register usage on pdp11 */
c
%= symsiz
; if (c
<0) c
+= symsiz
;
while (*snp
++ == *np
) if (*np
++ == '\0') {
if (enterf
==DROP
) {sp
->name
[0]= DROP
; sp
->value
=0;}
if (around
) {pperror("too many defines", 0); exit(exfail
);}
else {++around
; sp
= &stab
[symsiz
-1];}
if (enterf
==1) sp
->name
=namep
;
slookup(p1
,p2
,enterf
) register char *p1
,*p2
; int enterf
;{
register char *p3
; char c2
,c3
; struct symtab
*np
;
c2
= *p2
; *p2
='\0'; /* mark end of token */
if ((p2
-p1
)>NCPS
) p3
=p1
+NCPS
; else p3
=p2
;
c3
= *p3
; *p3
='\0'; /* truncate to NCPS chars or less */
if (enterf
==1) p1
=copy(p1
);
np
=lookup(p1
,enterf
); *p3
=c3
; *p2
=c2
;
if (np
->value
!=0 && flslvl
==0) newp
=subst(p2
,np
);
subst(p
,sp
) register char *p
; struct symtab
*sp
; {
static char match
[]="%s: argument mismatch";
register char *ca
,*vp
; int params
;
char *actual
[MAXFRM
]; /* actual[n] is text of nth actual */
char acttxt
[BUFSIZ
]; /* space for actuals */
if (0==(vp
=sp
->value
)) return(p
);
if ((p
-macforw
)<=macdam
) {
if (++maclvl
>symsiz
&& !rflag
) {
pperror("%s: macro recursion",sp
->name
); return(p
);
} else maclvl
=0; /* level decreased */
macforw
=p
; macdam
=0; /* new target for decrease in level */
sprintf(vp
,"%d",lineno
[ifno
]); while (*vp
++);
sprintf(vp
,"\"%s\"",fnames
[ifno
]); while (*vp
++);
if (0!=(params
= *--vp
&0xFF)) {/* definition calls for params */
if (params
==0xFF) params
=1; /* #define foo() ... */
sloscan(); ++flslvl
; /* no expansion during search for actuals */
do p
=skipbl(p
); while (*inp
=='\n'); /* skip \n too */
maclin
=lineno
[ifno
]; macfil
=fnames
[ifno
];
for (plvl
=1; plvl
!=0; ) {
outp
=inp
=p
; p
=cotoken(p
);
if (*inp
==')' && --plvl
==0) {--params
; break;}
if (plvl
==1 && *inp
==',') {--params
; break;}
while (inp
<p
) *ca
++= *inp
++;
pperror("%s: actuals too long",sp
->name
);
if (pa
>= &actual
[MAXFRM
]) ppwarn(match
,sp
->name
);
if (params
!=0) ppwarn(match
,sp
->name
);
while (--params
>=0) *pa
++=""+1; /* null string for missing actuals */
for (;;) {/* push definition onto front of input stack */
if (bob(p
)) {outp
=inp
=p
; p
=unfill(p
);}
if (*vp
==warnc
) {/* insert actual param */
if (bob(p
)) {outp
=inp
=p
; p
=unfill(p
);}
trmdir(s
) register char *s
; {
while (*p
++); --p
; while (p
>s
&& *--p
!='/');
copy(s
) register char *s
; {
old
= savch
; while (*savch
++ = *s
++);
while (*s
) if (*s
++==c
) return(--s
);
if (setjmp(env
)) return (exfail
);
p
="_$ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
(fastab
+COFF
)[c
] |= IB
|NB
|SB
; (toktyp
+COFF
)[c
]=IDENT
;
/* 53 == 63-10; digits rarely appear in identifiers,
/* and can never be the first char of an identifier.
/* 11 == 53*53/sizeof(macbit) .
++i
; (t21
+COFF
)[c
]=(53*i
)/11; (t22
+COFF
)[c
]=i
%11;
while (c
= *p
++) {(fastab
+COFF
)[c
] |= NB
|SB
; (toktyp
+COFF
)[c
]=NUMBR
;}
while (c
= *p
++) (fastab
+COFF
)[c
] |= SB
;
while (c
= *p
++) (fastab
+COFF
)[c
] |= QB
;
p
="*\n"; while (c
= *p
++) (fastab
+COFF
)[c
] |= CB
;
(fastab
+COFF
)[warnc
] |= WB
;
(fastab
+COFF
)['\0'] |= CB
|QB
|SB
|WB
;
for (i
=ALFSIZ
; --i
>=0; ) slotab
[i
]=fastab
[i
]|SB
;
p
=" \t\013\f\r"; /* note no \n; \v not legal for vertical tab? */
while (c
= *p
++) (toktyp
+COFF
)[c
]=BLANK
;
for ((t23
+COFF
)[i
=ALFSIZ
+7-COFF
]=1; --i
>=-COFF
; )
if (((t23
+COFF
)[i
]=(t23
+COFF
+1)[i
]<<1)==0) (t23
+COFF
)[i
]=1;
fnames
[ifno
=0] = ""; dirnams
[0]=dirs
[0]=".";
if (inquire(stdin
, _TTY
)) freopen("*src", "rt", stdin
);
fnames
[ifno
=0] = (char *)inquire(stdin
, _FILENAME
);
dirnams
[0] = dirs
[0] = trmdir(copy(fnames
[0]));
switch(toupper(argv
[i
][1])) { /* case-independent on GCOS */
case 'R': ++rflag
; continue;
case 'C': passcom
++; continue;
if (predef
>prespc
+NPREDEF
) {
pperror("too many -D options, ignoring %s",argv
[i
]);
/* ignore plain "-D" (no argument) */
if (*(argv
[i
]+2)) *predef
++ = argv
[i
]+2;
if (prund
>punspc
+NPREDEF
) {
pperror("too many -U options, ignoring %s",argv
[i
]);
if (nd
>8) pperror("excessive -I file (%s) ignored",argv
[i
]);
else dirs
[nd
++] = argv
[i
]+2;
pperror("unknown flag %s", argv
[i
]);
if (0>(fin
=open(argv
[i
], READ
))) {
pperror("No source file %s",argv
[i
]); exit(8);
fnames
[ifno
]=copy(argv
[i
]);
dirs
[0]=dirnams
[ifno
]=trmdir(argv
[i
]);
/* too dangerous to have file name in same syntactic position
be input or output file depending on file redirections,
so force output to stdout, willy-nilly
[i don't see what the problem is. jfr]
} else if (fout
==stdout
) {
extern char _sobuf
[BUFSIZ
];
if (NULL
==(fout
=fopen(argv
[i
], "w"))) {
pperror("Can't create %s", argv
[i
]); exit(8);
} else {fclose(stdout
); setbuf(fout
,_sobuf
);}
} else pperror("extraneous name %s", argv
[i
]);
/* after user -I files here are the standard include libraries */
dirs
[nd
++] = "/usr/include";
dirs
[nd
++] = "cc/include";
dirs
[nd
++] = intss() ? "SYS3.C." : "" ;
/* dirs[nd++] = "/compool"; */
for (i
=sizeof(macbit
)/sizeof(macbit
[0]); --i
>=0; ) macbit
[i
]=0;
varloc
=stsym ("interdata");
ulnloc
=stsym ("__LINE__");
uflloc
=stsym ("__FILE__");
tf
=fnames
[ifno
]; fnames
[ifno
]="command line"; lineno
[ifno
]=1;
while (cp2
<predef
) stsym(*cp2
++);
if (p
=strdex(*cp2
, '=')) *p
++='\0';
pbeg
=buffer
+NCPS
; pbuf
=pbeg
+BUFSIZ
; pend
=pbuf
+BUFSIZ
;
lineno
[0] = 1; sayline();