mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-24 00:44:23 +00:00
578 lines
12 KiB
C
578 lines
12 KiB
C
#
|
|
/*
|
|
Copyright 1981
|
|
Alcyon Corporation
|
|
8474 Commerce Av.
|
|
San Diego, Ca. 92121
|
|
*/
|
|
|
|
#include "preproc.h"
|
|
#define CSTKSIZE 20
|
|
|
|
#ifdef VAX
|
|
char *stdincl "lib:"; /*standard include directory*/
|
|
#endif
|
|
|
|
#ifdef UNIX
|
|
char *stdincl ="/usr/include/";
|
|
#endif
|
|
|
|
#ifdef MC68000
|
|
char *stdincl "";
|
|
#endif
|
|
|
|
int clabel =1000;
|
|
int nlabel =1001;
|
|
int lineno = 0;
|
|
|
|
struct builtin {
|
|
char *b_name;
|
|
int b_type;
|
|
} btab[] {
|
|
"define", DEFINE,
|
|
"include", INCLUDE,
|
|
"undef", UNDEF,
|
|
"ifdef", IFDEF,
|
|
"ifndef", IFNDEF,
|
|
"else", ELSE,
|
|
"endif", ENDIF,
|
|
"if", IF,
|
|
0,
|
|
};
|
|
|
|
char cstack[CSTKSIZE]={0};
|
|
char *cstkptr=0;
|
|
|
|
/* domacro - do macro processing*/
|
|
/* Does the macro pre-processing on the input file and leaves the*/
|
|
/* result on the output file.*/
|
|
domacro(infile,outfile,nd,nds) /* returns 1 if ok, 0 otherwise*/
|
|
char *infile; /* input file name*/
|
|
char *outfile; /* output file name*/
|
|
int nd; /* number of defines*/
|
|
char *nds[]; /*points to defines*/
|
|
{
|
|
register struct builtin *bp;
|
|
register char *l;
|
|
|
|
filep = 0;
|
|
if( fopen(infile,&inbuf[filep],0) < 0 ) {
|
|
error("can't open %s\n",infile);
|
|
return(0);
|
|
}
|
|
if( fcreat(outfile,&outbuf,0666) < 0 ) {
|
|
error("can't creat %s\n",outfile);
|
|
return(0);
|
|
}
|
|
if( defap == 0 ) {
|
|
defp = defap = sbrk(1024);
|
|
defmax = defcount = 1024;
|
|
}
|
|
else {
|
|
defcount = defmax;
|
|
defp = defap;
|
|
}
|
|
lineno = 1;
|
|
defused = 0;
|
|
mfail = 0;
|
|
pbp = &pbbuf[0];
|
|
cstkptr = &cstack[0];
|
|
install("Newlabel",NEWLABEL);
|
|
install("Label",LABEL);
|
|
while( --nd >= 0 )
|
|
install(nds[nd],0);
|
|
while( getline() ) {
|
|
l = line;
|
|
if( filep == 0 && pbp == pbbuf )
|
|
lineno++;
|
|
else if( pflag == 0 && asflag == 0 )
|
|
putc(SOH,&outbuf);
|
|
while( *l )
|
|
putc(*l++,&outbuf);
|
|
putc('\n',&outbuf);
|
|
}
|
|
if( cstkptr != &cstack[0] )
|
|
error("unmatched conditional");
|
|
if( defused > defmax )
|
|
defmax = defused;
|
|
myfflush(&outbuf);
|
|
close(outbuf.fd);
|
|
close(inbuf[0].fd);
|
|
return(mfail==0);
|
|
}
|
|
|
|
/* kwlook - look up the macro built-in names*/
|
|
/* Searches thru the built-in table for the name.*/
|
|
kwlook(name) /* returns keyword index or 0*/
|
|
char *name; /* keyword name to lookup*/
|
|
{
|
|
register struct builtin *bp;
|
|
|
|
for( bp = &btab[0]; bp->b_name; bp++ )
|
|
if( strcmp(bp->b_name,name) == 0 )
|
|
return(bp->b_type);
|
|
return(0);
|
|
}
|
|
|
|
/* getline - get input line handling macro statements*/
|
|
/* Checks for a preprocessor statement on the line and if there*/
|
|
/* is one there, it processes it. Note that most of the work is*/
|
|
/* in determining whether we need to skip the current line or not.*/
|
|
/* This is all handled with the condition stack and the skip variable.*/
|
|
/* The skip variable is non-zero if any condition on the condition*/
|
|
/* stack is SKIP.*/
|
|
getline() /* returns 0 for EOF, 1 otherwise*/
|
|
{
|
|
char token[TOKSIZE];
|
|
register int type, i;
|
|
register char *p;
|
|
|
|
initl();
|
|
if( (type=gettok(token)) == EOF )
|
|
return(0);
|
|
if( type == POUND ) {
|
|
if( (type=getntok(token)) == NEWL )
|
|
return(1);
|
|
switch( kwlook(token) ) {
|
|
|
|
case IFDEF:
|
|
if( getntok(token) == ALPHA && lookup(token) )
|
|
push(NOSKIP);
|
|
else {
|
|
push(SKIP);
|
|
skip++;
|
|
}
|
|
break;
|
|
|
|
case IFNDEF:
|
|
if( getntok(token) == ALPHA && lookup(token) ) {
|
|
push(SKIP);
|
|
skip++;
|
|
}
|
|
else
|
|
push(NOSKIP);
|
|
break;
|
|
|
|
case ENDIF:
|
|
if( (i=pop()) == SKIP )
|
|
skip--;
|
|
else if( i != NOSKIP )
|
|
error("invalid #endif");
|
|
break;
|
|
|
|
case ELSE:
|
|
if( (i=pop()) == SKIP ) {
|
|
skip--;
|
|
push(NOSKIP);
|
|
}
|
|
else if( i == NOSKIP ) {
|
|
skip++;
|
|
push(SKIP);
|
|
}
|
|
else
|
|
error("invalid #else");
|
|
break;
|
|
|
|
case DEFINE:
|
|
if( skip == 0 ) /*if in skip, don't do define*/
|
|
dodefine();
|
|
break;
|
|
|
|
case UNDEF:
|
|
if( skip == 0 ) { /*if in skip, don't undef*/
|
|
if( (type=getntok(token)) == ALPHA )
|
|
undefine(token);
|
|
}
|
|
break;
|
|
|
|
case INCLUDE:
|
|
if( skip == 0 ) /*if in skip, don't do include*/
|
|
doinclude();
|
|
break;
|
|
|
|
case IF:
|
|
if( cexpr() ) /*evaluate constant expression*/
|
|
push(NOSKIP); /*non-zero, so don't skip*/
|
|
else {
|
|
push(SKIP);
|
|
skip++;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
error("invalid preprocessor command");
|
|
break;
|
|
}
|
|
eatup();
|
|
}
|
|
else if( type == NEWL )
|
|
;
|
|
else if( skip )
|
|
eatup();
|
|
else {
|
|
for( ; type != NEWL && type != EOF ; type = gettok(token) ) {
|
|
if( type == ALPHA && (p=lookup(token)) )
|
|
expand(p);
|
|
else {
|
|
for( p = token; *p ; )
|
|
putl(*p++);
|
|
}
|
|
}
|
|
}
|
|
putl('\0');
|
|
return(1);
|
|
}
|
|
|
|
/* eatup - eat up the rest of the input line until a newline or EOF*/
|
|
/* Does gettok calls.*/
|
|
eatup() /* returns - none*/
|
|
{
|
|
register int type;
|
|
char token[TOKSIZE];
|
|
|
|
while( (type=gettok(token)) != NEWL && type != EOF )
|
|
;
|
|
}
|
|
|
|
/* putl - put a character to the current output line*/
|
|
/* Checks for line overflow.*/
|
|
putl(c) /* returns - none*/
|
|
int c; /* character to put on line*/
|
|
{
|
|
if( linep < &line[LINESIZE] )
|
|
*linep++ = c;
|
|
else if( loverflow == 0 ) {
|
|
loverflow++;
|
|
error("line overflow");
|
|
}
|
|
}
|
|
|
|
/* initl - initialize current line*/
|
|
/* Sets the line pointer and the line overflow flag.*/
|
|
initl() /* returns - none*/
|
|
{
|
|
*(linep= &line[0]) = '\0';
|
|
loverflow = 0;
|
|
}
|
|
|
|
/* putd - put a character to the define buffer*/
|
|
/* Does dynamic allocation for define buffer*/
|
|
putd(c) /* returns - none*/
|
|
int c; /* character to put in buffer*/
|
|
{
|
|
if( defcount == 0 ) {
|
|
if( sbrk(DEFSIZE) == -1 ) {
|
|
error("define table overflow");
|
|
cexit();
|
|
}
|
|
defcount = DEFSIZE;
|
|
}
|
|
defused++;
|
|
defcount--;
|
|
*defp++ = c;
|
|
}
|
|
|
|
/* undefine - does undef command*/
|
|
/* Sets the symbols definition to the null pointer*/
|
|
undefine(name) /* returns - none*/
|
|
char *name; /* pointer to name to undef*/
|
|
{
|
|
register struct symbol *sp;
|
|
|
|
sp = getsp(name);
|
|
if( sp->s_def )
|
|
sp->s_def = null;
|
|
}
|
|
|
|
/* dodefine - do #define processing*/
|
|
/* Checks the define name, collects formal arguements and saves*/
|
|
/* macro definition, substituting for formal arguments as it goes.*/
|
|
dodefine() /* returns - none*/
|
|
{
|
|
char token[TOKSIZE], *args[MAXARGS], argbuf[ARGBSIZE];
|
|
register char *abp, *p;
|
|
register int type, nargs, i;
|
|
register struct symbol *sp;
|
|
|
|
if( (type=getntok(token)) != ALPHA ) {
|
|
error("bad define name: %s",token);
|
|
return;
|
|
}
|
|
sp = getsp(token);
|
|
symcopy(token,sp->s_name);
|
|
sp->s_def = defp;
|
|
nargs = 0;
|
|
abp = argbuf;
|
|
if( (type=gettok(token)) == LPAREN ) {
|
|
for( ; (type=getfarg(token)) != RPAREN; nargs++ ) {
|
|
if( nargs >= MAXARGS ) {
|
|
error("too many arguments");
|
|
break;
|
|
}
|
|
args[nargs] = abp;
|
|
for( p = token; *abp++ = *p++; ) {
|
|
if( abp >= &argbuf[ARGBSIZE] ) {
|
|
error("argument buffer overflow");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
putd(nargs);
|
|
}
|
|
else {
|
|
pbtok(token);
|
|
putd(NOARGS);
|
|
}
|
|
type = getntok(token); /*get next non-white token*/
|
|
for( ; type != NEWL && type != EOF; type = gettok(token) ) {
|
|
if( type == ALPHA ) {
|
|
for( i = 0; i < nargs; i++ ) {
|
|
if( strcmp(args[i],token) == 0 )
|
|
break;
|
|
}
|
|
if( i < nargs ) { /*sub ARG marker for formal arg*/
|
|
putd(i+1);
|
|
putd(ARG);
|
|
continue;
|
|
}
|
|
}
|
|
else if( type == BSLASH ) {
|
|
if( (i=ngetch()) == '\n' ) { /*multi-line macro?*/
|
|
if( filep == 0 && pbp == pbbuf ) {
|
|
lineno++;
|
|
putc('\n',&outbuf);
|
|
}
|
|
}
|
|
putd(i);
|
|
continue;
|
|
}
|
|
for( p = token; *p ; )
|
|
putd(*p++);
|
|
}
|
|
pbtok(token);
|
|
putd('\0');
|
|
}
|
|
|
|
/* expand - expands the macro definition*/
|
|
/* Checks for define recursion and #define x x problems, collects*/
|
|
/* the actual arguments using getaarg, and then expands the macro*/
|
|
/* by pushing it onto the push back buffer, substituting arguments*/
|
|
/* as it goes.*/
|
|
expand(sp) /* returns - none*/
|
|
struct symbol *sp; /* pointer to macro to expand*/
|
|
{
|
|
char argbuf[ARGBSIZE], *args[MAXARGS], token[TOKSIZE];
|
|
register char *p, *abp, *mdef;
|
|
register int i, j, nargs, type;
|
|
|
|
if( pbflag++ > 100 ) {
|
|
error("define recursion");
|
|
return;
|
|
}
|
|
if( strcmp(sp->s_name,mdef=sp->s_def) == 0 ) { /*handle #define x x*/
|
|
while( *mdef )
|
|
putl(*mdef++);
|
|
return;
|
|
}
|
|
nargs = 0;
|
|
if( *mdef == NOARGS ) /*suppress grabbing of args*/
|
|
;
|
|
else if( gettok(token) != LPAREN )
|
|
pbtok(token);
|
|
else {
|
|
abp = &argbuf[0];
|
|
while( (type=getaarg(token)) != EOF ) {
|
|
if( nargs >= MAXARGS ) {
|
|
error("too many arguments");
|
|
return;
|
|
}
|
|
args[nargs++] = abp;
|
|
for( p = token; *abp++ = *p++; ) {
|
|
if( abp >= &argbuf[ARGBSIZE] ) {
|
|
error("argument buffer overflow");
|
|
return;
|
|
}
|
|
}
|
|
if( type == RPAREN )
|
|
break;
|
|
}
|
|
}
|
|
if( *mdef == NEWLABEL ) {
|
|
clabel = nlabel;
|
|
if( nargs == 0 )
|
|
nlabel++;
|
|
else
|
|
nlabel =+ atoi(args[0]);
|
|
}
|
|
else if( *mdef == LABEL ) {
|
|
if( nargs == 0 )
|
|
i = clabel;
|
|
else
|
|
i = clabel + atoi(args[0]);
|
|
pbnum(i);
|
|
pbtok("_L");
|
|
}
|
|
else {
|
|
mdef++; /*skip no. of args*/
|
|
for( p = mdef + strlen(mdef) - 1; p >= mdef; p-- ) {
|
|
if( *p == ARG ) {
|
|
if( (j= *--p) <= nargs )
|
|
pbtok(args[j-1]);
|
|
}
|
|
else
|
|
putback(*p);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* getfarg - get macro formal parameters*/
|
|
/* Skips blanks and handles "," and ")".*/
|
|
getfarg(token) /* returns token type*/
|
|
char *token; /* token returned*/
|
|
{
|
|
register int type;
|
|
|
|
if( (type=getntok(token)) == RPAREN || type == ALPHA )
|
|
return(type);
|
|
if( type != COMMA || (type=getntok(token)) != ALPHA )
|
|
error("bad argument:%s",token);
|
|
return(type);
|
|
}
|
|
|
|
/* getntok - get next token, suppressing white space*/
|
|
/* Merely gettok's until non-white space is there*/
|
|
getntok(token) /* returns token type*/
|
|
char *token; /* token returned*/
|
|
{
|
|
register int type;
|
|
|
|
while( (type=gettok(token)) == WHITE )
|
|
;
|
|
return(type);
|
|
}
|
|
|
|
/* getaarg - get macro actual argument*/
|
|
/* This handles the collecting of the macro's call arguments.*/
|
|
/* Note that you may have parenthesis as part of the macro argument,*/
|
|
/* hence you need to keep track of them.*/
|
|
getaarg(argp) /* returns token type*/
|
|
char *argp; /* argument returned*/
|
|
{
|
|
int type, plevel, i;
|
|
register char *p, *ap;
|
|
char token[TOKSIZE];
|
|
|
|
ap = argp;
|
|
*ap = '\0';
|
|
plevel = 0;
|
|
i = TOKSIZE;
|
|
while( ((type=gettok(token)) != COMMA && type != RPAREN) || plevel ) {
|
|
for( p = token; *ap = *p++; ap++ )
|
|
if( --i <= 0 ) {
|
|
error("macro argument too long");
|
|
return(EOF);
|
|
}
|
|
if( type == LPAREN )
|
|
plevel++;
|
|
else if( type == RPAREN )
|
|
plevel--;
|
|
else if( type == EOF ) {
|
|
error("unexpected EOF");
|
|
cexit();
|
|
}
|
|
}
|
|
if( ap == argp )
|
|
type = EOF;
|
|
return(type);
|
|
}
|
|
|
|
/* push - push a #ifdef condition value on condition stack*/
|
|
/* Checks for stack overflow.*/
|
|
push(val) /* returns - none*/
|
|
int val; /* value to push*/
|
|
{
|
|
if( cstkptr >= &cstack[CSTKSIZE] ) {
|
|
error("condition stack overflow");
|
|
cexit();
|
|
}
|
|
*cstkptr++ = val;
|
|
}
|
|
|
|
/* pop - pop the #ifdef, etc. condition stack*/
|
|
/* Checks for stack undeflow.*/
|
|
pop() /* returns - top of condition stack*/
|
|
{
|
|
if( cstkptr <= &cstack[0] )
|
|
return(-1);
|
|
return( *--cstkptr );
|
|
}
|
|
|
|
/* doinclude - handle #include command*/
|
|
/* Checks for file name or library file name and pushes file on*/
|
|
/* include file stack.*/
|
|
doinclude() /* returns - none*/
|
|
{
|
|
register int type, fd;
|
|
char token[TOKSIZE], fname[TOKSIZE];
|
|
register char *p, *q, c;
|
|
|
|
p = fname;
|
|
if( (type=getntok(token)) == SQUOTE || type == DQUOTE ) {
|
|
for( c = token[0], q = &token[1]; *q != c; )
|
|
*p++ = *q++;
|
|
*p = '\0';
|
|
}
|
|
else if( type != LESS ) {
|
|
error("bad include file");
|
|
return;
|
|
}
|
|
else {
|
|
for( q = stdincl; *p = *q++; p++ )
|
|
;
|
|
while( (type=gettok(token))!=GREAT && type!=NEWL && type!=EOF )
|
|
for( q = token; *p = *q++; p++ )
|
|
;
|
|
if( type != GREAT ) {
|
|
error("bad include file name");
|
|
pbtok(token);
|
|
return;
|
|
}
|
|
}
|
|
eatup(); /*need here...*/
|
|
if( filep >= NINCS-1 )
|
|
error("includes nested too deeply");
|
|
else {
|
|
filep++;
|
|
if( fopen(fname,&inbuf[filep],0) < 0 ) {
|
|
error("can't open %s",fname);
|
|
filep--;
|
|
}
|
|
}
|
|
putback('\n'); /*for eatup in domacro*/
|
|
}
|
|
|
|
install(name,def) /* returns - none*/
|
|
char *name; /* macro name*/
|
|
char def; /* pointer to definition*/
|
|
{
|
|
register struct symbol *sp;
|
|
|
|
sp = getsp(name);
|
|
symcopy(name,sp->s_name);
|
|
sp->s_def = defp;
|
|
putd(def);
|
|
putd('\0');
|
|
}
|
|
|
|
pbnum(num) /* returns - none*/
|
|
int num;
|
|
{
|
|
register int digit;
|
|
|
|
do {
|
|
digit = num % 10;
|
|
num =/ 10;
|
|
putback(digit+'0');
|
|
} while( num > 0 );
|
|
}
|