📄 cpp.c
字号:
## include "stdio.h"/* C command/* written by John F. Reiser/* July/August 1978*/#define STATIC#define STDIN 0#define STDOUT 1#define STDERR 2#define READ 0#define WRITE 1#define SALT '#'#ifndef BUFSIZ#define BUFSIZ 512#endifchar *pbeg,*pbuf,*pend;char *outp,*inp;char *newp;char cinit;/* some code depends on whether characters are sign or zero extended *//* #if '\377' < 0 not used here, old cpp doesn't understand */#if pdp11 | vax#define COFF 128#else#define COFF 0#endif# if gcos#define ALFSIZ 512 /* alphabet size */# else#define ALFSIZ 256 /* alphabet size */# endifchar macbit[ALFSIZ+11];char toktyp[ALFSIZ];#define BLANK 1#define IDENT 2#define NUMBR 3/* 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,/* the code is here./* using both scw1 and scw2 is of dubious value.*/#define scw1 1#define scw2 0#if scw2char t21[ALFSIZ],t22[ALFSIZ],t23[ALFSIZ+8];#endif#if scw1#define b0 1#define b1 2#define b2 4#define b3 8#define b4 16#define b5 32#define b6 64#define b7 128#endif#define IB 1#define SB 2#define NB 4#define CB 8#define QB 16#define WB 32char fastab[ALFSIZ];char slotab[ALFSIZ];char *ptrtab;#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[8+BUFSIZ+BUFSIZ+8];# define SBSIZE 12000char sbf[SBSIZE];char *savch = sbf;# define DROP 0xFE /* special character not legal ASCII or EBCDIC */# define WARN DROP# define SAME 0# define MAXINC 10# define MAXFRE 14 /* max buffers of macro pushback */# define MAXFRM 31 /* max number of formals/actuals to a macro */static char warnc = WARN;int mactop,fretop;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 */#if tgpint tgpscan; /* flag for dump(); */#endifSTATIC int inctop[MAXINC];STATIC char *fnames[MAXINC];STATIC char *dirnams[MAXINC]; /* actual directory of #include files */STATIC int fins[MAXINC];STATIC int lineno[MAXINC];STATIC char *dirs[10]; /* -I and <> directories */char *strdex(), *copy(), *subst(), *trmdir();struct symtab *stsym();STATIC int fin = STDIN;STATIC FILE *fout = stdout;STATIC int nd = 1;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 int ifno;# define NPREDEF 20STATIC char *prespc[NPREDEF];STATIC char **predef = prespc;STATIC char *punspc[NPREDEF];STATIC char **prund = punspc;STATIC int exfail;struct symtab { char *name; char *value;} *lastsym, *lookup(), *slookup();# if gcos#include <setjmp.h>static jmp_buf env;# define main mainpp# undef exit# define exit(S) longjmp(env, 1)# define open(S,D) fileno(fopen(S, "r"))# define close(F) fclose(_f[F])extern FILE *_f[];# define symsiz 500# else# define symsiz 400# endifSTATIC 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;STATIC int trulvl;STATIC int flslvl;sayline() { if (pflag==0) fprintf(fout,"# %d \"%s\"\n", lineno[ifno], fnames[ifno]);}/* data structure guide/*/* most of the scanning takes place in the buffer:/*/* (low address) (high address)/* pbeg pbuf pend/* | <-- BUFSIZ chars --> | <-- BUFSIZ chars --> |/* _______________________________________________________________________/* |_______________________________________________________________________|/* | | |/* |<-- waiting -->| |<-- waiting -->/* | to be |<-- current -->| to be/* | written | token | scanned/* | | |/* outp inp p/*/* *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,/* resume scanning./*/* 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.*/dump() {/* 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 tgp#define MAXOUT 80 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'; while (c= *p1++) { if (c=='\\') c= *p1++; if (stopc==c) stopc=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; } if (brk) sayline(); *p2=savc; inp=p2; p1=outp; tgpscan=0; }#endif f=fout;# if gcos/* 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 (!gmfirst) { ++gmfirst; if (gmatch(p1, "^$*program[ \t]*c*")) p1 = strdex(p1, '\n'); }}# endif while (p1<inp) putc(*p1++,f); outp=p1;}char *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++; p=np; for (;;) { 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]; return(p); } else {/* get more text from file(s) */ maclvl=0; if (0<(ninbuf=read(fin,pbuf,BUFSIZ))) { pend=pbuf+ninbuf; *pend='\0'; return(p); } /* end of #include file */ if (ifno==0) {/* end of input */ if (plvl!=0) { 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; return(p); } inp=p; dump(); exit(exfail); } close(fin); fin=fins[--ifno]; dirs[0]=dirnams[ifno]; sayline(); } }}#define BEG 0#define LF 1char *cotoken(p) register char *p; { register int c,i; char quoc; static int state = BEG; if (state!=BEG) goto prevlf;for (;;) {again: while (!isspc(*p++)); switch (*(inp=p-1)) { case 0: { if (eob(--p)) {p=refill(p); goto again;} else ++p; /* ignore null byte */ } break; case '|': case '&': for (;;) {/* sloscan only */ if (*p++== *inp) break; if (eob(--p)) p=refill(p); else break; } break; case '=': case '!': for (;;) {/* sloscan only */ if (*p++=='=') break; if (eob(--p)) p=refill(p); else break; } break; case '<': case '>': for (;;) {/* sloscan only */ if (*p++=='=' || p[-2]==p[-1]) break; if (eob(--p)) p=refill(p); else break; } break; case '\\': for (;;) { if (*p++=='\n') {++lineno[ifno]; break;} if (eob(--p)) p=refill(p); else {++p; break;} } break; case '/': for (;;) { if (*p++=='*') {/* comment */ if (!passcom) {inp=p-2; dump(); ++flslvl;} for (;;) { while (!iscom(*p++)); if (p[-1]=='*') for (;;) { if (*p++=='/') goto endcom; if (eob(--p)) { 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -