1File: MACRO.C                                                             Page       1
     1   /*
     2   	Copyright 1982
     3   	Alcyon Corporation
     4   	8716 Production Ave.
     5   	San Diego, Ca.  92121
     6   */
     7    
     8   #include "preproc.h"
     9    
    10   #define	CSTKSIZE	20
    11   #define FILESEP		'/'
    12   #define NINCL		10
    13    
    14   #ifdef UNIX
    15   char *stdincl "/usr/include/";		/*standard include directory*/
    16   #endif
    17   #ifdef VMS
    18   char *stdincl "lib:";
    19   #endif
    20   #ifdef CPM
    21   char *stdincl "";
    22   #endif
    23    
    24   int clabel 1000;
    25   int nlabel 1001;
    26   int nincl;
    27   char *incl[10];
    28   char tmp[6];
    29    
    30   struct builtin {
    31   	char *b_name;
    32   	int b_type;
    33   } btab[] {
    34   	"define",	DEFINE,
    35   	"include",	INCLUDE,
    36   	"undef",	UNDEF,
    37   	"ifdef",	IFDEF,
    38   	"ifndef",	IFNDEF,
    39   	"else",		ELSE,
    40   	"endif",	ENDIF,
    41   	"if",		IF,
    42   	0,
    43   };
    44    
    45   char *getinclude();
    46   char cstack[CSTKSIZE];
    47   char *cstkptr, inclname[TOKSIZE];
    48    
    49   /* domacro - do macro processing*/
    50   /*		Does the macro pre-processing on the input file and leaves the*/
    51   /*		result on the output file.*/
    52   domacro(infile,outfile,nd)		/* returns 1 if ok, 0 otherwise*/
    53   char *infile;						/* input file name*/
    54   char *outfile;						/* output file name*/
    55   int nd;								/* number of defines*/
    56   {
    57   	register struct builtin *bp;
    58   	register char *l;
    59   	register struct symbol *sp;
1File: MACRO.C                                                             Page       2
    60   	register int x, nonewline;	/* handle empty new lines with SOH */
    61   	register char *p;
    62   	filep = &filestack[0];
    63    
    64   	if( fopen(infile,&(filep->inbuf),0) < 0 ) { /* 3rd arg for versados */
    65   		error("can't open source file %s\n",infile);
    66   		return(0);
    67   	}
    68   	if( fcreat(outfile,&outbuf,0) < 0 ) {	/* 3rd arg for versados */
    69   		error("can't creat %s\n",outfile);
    70   		return(0);
    71   	}
    72   	for (sp= &symtab[0]; sp<= &symtab[HSIZE-1]; sp++) /*3.4*/
    73   		sp->s_def = null;	/* clear out symbol table */
    74   	if( !defap ) {
    75   		defp = defap = sbrk(1024);
    76   		defmax = defcount = 1024;
    77   	}
    78   	else {	/* multiple files, define area already exists */
    79   		defcount = defmax;
    80   		for (x = defmax, defp = defap; x>0; x--)
    81   			*defp++ = 0;
    82   		defp = defap;
    83   	}
    84   	lineno = 1;
    85   	nonewline = defused = mfail = 0;
    86   	pbp = &pbbuf[0];
    87   	cstkptr = &cstack[0];
    88   	install("Newlabel",NEWLABEL);
    89   	install("Label",LABEL);
    90   	while( --nd >= 0 )
    91   		dinstall(defs[nd].ptr,defs[nd].value);
    92   	while( getline(infile) ) {
    93   		l = line;
    94   		if( filep == &filestack[0] && pbp == &pbbuf[0] )
    95   			lineno++;
    96   		else if ( !pflag && !asflag ) {	/*[vlh] add fname & line#*/
    97   			if (*l) {
    98   				putc(SOH,&outbuf);
    99   				for (p = (filep)->ifile; *p; p++)
   100   					putc(*p,&outbuf);
   101   				putc(SOH,&outbuf);
   102   				itoa((filep)->lineno,tmp,5);
   103   				for (p = tmp; *p==' '; ) p++;
   104   				for ( ; *p; p++)
   105   					putc(*p,&outbuf);
   106   				putc(' ',&outbuf);
   107   				if (!(*l)) putc(' ',&outbuf);
   108   			}
   109   			else nonewline++;
   110   			(filep)->lineno++;
   111   		}
   112   		while( *l )
   113   			putc(*l++,&outbuf);
   114   		if (!nonewline) putc('\n',&outbuf);
   115   		else nonewline = 0;
   116   	}
   117   	if( cstkptr != &cstack[0] )
   118   		error("unmatched conditional");
1File: MACRO.C                                                             Page       3
   119   	if( defused > defmax )
   120   		defmax = defused;
   121   	v6flush(&outbuf);
   122   	close(outbuf.fd);
   123   	close(filep->inbuf.fd);
   124   	return(mfail==0);
   125   }
   126    
   127   install(name,def)
   128   char *name;
   129   int def;
   130   {
   131   	register struct symbol *sp;
   132    
   133   	sp = getsp(name);
   134   	symcopy(name,sp->s_name);
   135   	sp->s_def = defp;
   136   	putd(def);
   137   	putd('\0');
   138   }
   139    
   140   dinstall(name,def)					/* returns - none*/
   141   char *name;							/* macro name*/
   142   char *def;							/* pointer to definition*/
   143   {
   144   	register struct symbol *sp;
   145    
   146   	sp = getsp(name);
   147   	symcopy(name,sp->s_name);
   148   	sp->s_def = defp;
   149   	putd(NOARGS);
   150   	if (def)			/* [vlh] character strings... */
   151   		while(*def) putd(*def++);
   152   	else putd('1');		/* [vlh] default define value */
   153   	putd('\0');
   154   }
   155    
   156   /* kwlook - look up the macro built-in names*/
   157   /*		Searches thru the built-in table for the name.*/
   158   kwlook(name)						/* returns keyword index or 0*/
   159   char *name;							/* keyword name to lookup*/
   160   {
   161   	register struct builtin *bp;
   162    
   163   	for( bp = &btab[0]; bp->b_name; bp++ )
   164   		if( strcmp(bp->b_name,name) == 0 )
   165   			return(bp->b_type);
   166   	return(0);
   167   }
   168    
   169   /*
   170    * getline - get input line handling macro statements
   171    *		Checks for a preprocessor statement on the line and if there
   172    *		is one there, it processes it.  Note that most of the work is
   173    *		in determining whether we need to skip the current line or not.
   174    *		This is all handled with the condition stack and the skip variable.
   175    *		The skip variable is non-zero if any condition on the condition
   176    *		stack is SKIP.
   177    */
1File: MACRO.C                                                             Page       4
   178   getline(infile)						/* returns 0 for EOF, 1 otherwise*/
   179   char *infile;						/* [vlh] for quoted include files */
   180   {
   181   	char token[TOKSIZE];
   182   	register int type, i;
   183   	register char *p;
   184    
   185   	initl();
   186   	if( (type=gettok(token)) == EOF )
   187   		return(0);
   188   	if( type == POUND ) {
   189   		if( (type=getntok(token)) == NEWL )
   190   			return(1);
   191   		switch( kwlook(token) ) {
   192    
   193   		case IFDEF:
   194   			if( getntok(token) == ALPHA && lookup(token) )
   195   				push(NOSKIP);
   196   			else {
   197   				push(SKIP);
   198   				skip++;
   199   			}
   200   			break;
   201    
   202   		case IFNDEF:
   203   			if( getntok(token) == ALPHA && lookup(token) ) {
   204   				push(SKIP);
   205   				skip++;
   206   			}
   207   			else
   208   				push(NOSKIP);
   209   			break;
   210    
   211   		case ENDIF:
   212   			if( (i=pop()) == SKIP )
   213   				skip--;
   214   			else if( i != NOSKIP )
   215   				error("invalid #endif");
   216   			break;
   217    
   218   		case ELSE:
   219   			if( (i=pop()) == SKIP ) {
   220   				skip--;
   221   				push(NOSKIP);
   222   			}
   223   			else if( i == NOSKIP ) {
   224   				skip++;
   225   				push(SKIP);
   226   			}
   227   			else
   228   				error("invalid #else");
   229   			break;
   230    
   231   		case DEFINE:
   232   			if( !skip )			/*if in skip, don't do define*/
   233   				dodefine();
   234   			break;
   235    
   236   		case UNDEF:
1File: MACRO.C                                                             Page       5
   237   			if( !skip ) {		/*if in skip, don't undef*/
   238   				if( (type=getntok(token)) == ALPHA )
   239   					undefine(token);
   240   			}
   241   			break;
   242    
   243   		case INCLUDE:
   244   			if( !skip )			/*if in skip, don't do include*/
   245   				doinclude(infile);
   246   			break;
   247    
   248   		case IF:
   249   			if( cexpr() )			/*evaluate constant expression*/
   250   				push(NOSKIP);		/*non-zero, so don't skip*/
   251   			else {
   252   				push(SKIP);
   253   				skip++;
   254   			}
   255   			break;
   256    
   257   		default:
   258   			error("invalid preprocessor command");
   259   			break;
   260   		}
   261   		eatup();
   262   	}
   263   	else if( type == NEWL )
   264   		;
   265   	else if( skip )
   266   		eatup();
   267   	else {
   268   		for( ; type != NEWL && type != EOF ; type = gettok(token) ) {
   269   			if( type == ALPHA && (p=lookup(token)) )
   270   				expand(p);
   271   			else {
   272   				for( p = token; *p ; )
   273   					putl(*p++);
   274   			}
   275   		}
   276   	}
   277   	putl('\0');
   278   	return(1);
   279   }
   280    
   281   /* eatup - eat up the rest of the input line until a newline or EOF*/
   282   /*		Does gettok calls.*/
   283   eatup()								/* returns - none*/
   284   {
   285   	register int type;
   286   	char etoken[TOKSIZE];
   287    
   288   	while( (type=gettok(etoken)) != NEWL && type != EOF )
   289   		;
   290   }
   291    
   292   /* putl - put a character to the current output line*/
   293   /*		Checks for line overflow.*/
   294   putl(c)								/* returns - none*/
   295   int c;								/* character to put on line*/
1File: MACRO.C                                                             Page       6
   296   {
   297   	if( linep < &line[LINESIZE] )
   298   		*linep++ = c;
   299   	else if ( !loverflow ) {
   300   		loverflow++;
   301   		error("line overflow");
   302   	}
   303   }
   304    
   305   /* initl - initialize current line*/
   306   /*		Sets the line pointer and the line overflow flag.*/
   307   initl()								/* returns - none*/
   308   {
   309   	*(linep= &line[0]) = '\0';
   310   	loverflow = 0;
   311   }
   312    
   313   /* putd - put a character to the define buffer*/
   314   /*		Does dynamic allocation for define buffer*/
   315   putd(c)								/* returns - none*/
   316   int c;								/* character to put in buffer*/
   317   {
   318   	if( !defcount ) {
   319   		if( sbrk(DEFSIZE) == -1 ) {
   320   			error("define table overflow");
   321   			cexit();
   322   		}
   323   		defcount = DEFSIZE;
   324   	}
   325   	defused++;
   326   	defcount--;
   327   	*defp++ = c;
   328   }
   329    
   330   /* undefine - does undef command*/
   331   /*		Sets the symbols definition to the null pointer*/
   332   undefine(name)						/* returns - none*/
   333   char *name;							/* pointer to name to undef*/
   334   {
   335   	register struct symbol *sp;
   336    
   337   	sp = getsp(name);
   338   	if( sp->s_def )
   339   		sp->s_def = null;
   340   }
   341    
   342   /* dodefine - do #define processing*/
   343   /*		Checks the define name, collects formal arguements and saves*/
   344   /*		macro definition, substituting for formal arguments as it goes.*/
   345   dodefine()							/* returns - none*/
   346   {
   347   	char token[TOKSIZE], *args[MAXARGS], argbuf[ARGBSIZE];
   348   	register char *abp, *p;
   349   	register int type, nargs, i;
   350   	register struct symbol *sp;
   351    
   352   	if( (type=getntok(token)) != ALPHA ) {
   353   		error("bad define name: %s",token);
   354   		return;
1File: MACRO.C                                                             Page       7
   355   	}
   356   	sp = getsp(token);
   357   	symcopy(token,sp->s_name);
   358   	sp->s_def = defp;
   359   	nargs = 0;
   360   	abp = argbuf;
   361   	if( (type=gettok(token)) == LPAREN ) {
   362   		for( ; (type=getfarg(token)) != RPAREN; nargs++ ) {
   363   			if( nargs >= MAXARGS ) {
   364   				error("too many arguments");
   365   				break;
   366   			}
   367   			args[nargs] = abp;
   368   			for( p = token; *abp++ = *p++; ) {
   369   				if( abp >= &argbuf[ARGBSIZE] ) {
   370   					error("argument buffer overflow");
   371   					break;
   372   				}
   373   			}
   374   		}
   375   		putd(nargs);
   376   	}
   377   	else {
   378   		pbtok(token);
   379   		putd(NOARGS);
   380   	}
   381   	type = getntok(token);			/*get next non-white token*/
   382   	for( ; type != NEWL && type != EOF; type = gettok(token) ) {
   383   		if( type == ALPHA ) {
   384   			for( i = 0; i < nargs; i++ ) {
   385   				if( strcmp(args[i],token) == 0 )
   386   					break;
   387   			}
   388   			if( i < nargs ) {		/*sub ARG marker for formal arg*/
   389   				putd(i+1);
   390   				putd(ARG);
   391   				continue;
   392   			}
   393   		}
   394   		else if( type == BSLASH ) {
   395   			if( (i=ngetch()) == '\n' ) {	/*multi-line macro?*/
   396   				if( filep == &filestack[0] && pbp == &pbbuf[0] ) {
   397   					lineno++;
   398   					putc('\n',&outbuf);
   399   				}
   400   			}
   401   			putd(i);
   402   			continue;
   403   		}
   404   		for( p = token; *p ; )
   405   			putd(*p++);
   406   	}
   407   	pbtok(token);
   408   	putd('\0');
   409   }
   410    
   411   /* expand - expands the macro definition*/
   412   /*		Checks for define recursion and #define x x problems, collects*/
   413   /*		the actual arguments using getaarg, and then expands the macro*/
1File: MACRO.C                                                             Page       8
   414   /*		by pushing it onto the push back buffer, substituting arguments*/
   415   /*		as it goes.*/
   416   expand(sp)							/* returns - none*/
   417   struct symbol *sp;					/* pointer to macro to expand*/
   418   {
   419   	char argbuf[ARGBSIZE], *args[MAXARGS], token[TOKSIZE];
   420   	register char *p, *abp, *mdef;
   421   	register int i, j, nargs, type;
   422    
   423   	if( pbflag++ > 100 ) {
   424   		error("define recursion");
   425   		return;
   426   	}
   427   	if( strcmp(sp->s_name,mdef=sp->s_def) == 0 ) {	/*handle #define x x*/
   428   		while( *mdef )
   429   			putl(*mdef++);
   430   		return;
   431   	}
   432   	nargs = 0;
   433   	if( *mdef == NOARGS )					/*suppress grabbing of args*/
   434   		;
   435   	else if( gettok(token) != LPAREN )
   436   		pbtok(token);
   437   	else {
   438   		abp = &argbuf[0];
   439   		while( (type=getaarg(token)) != EOF ) {
   440   			if( nargs >= MAXARGS ) {
   441   				error("too many arguments");
   442   				return;
   443   			}
   444   			args[nargs++] = abp;
   445   			for( p = token; *abp++ = *p++; ) {
   446   				if( abp >= &argbuf[ARGBSIZE] ) {
   447   					error("argument buffer overflow");
   448   					return;
   449   				}
   450   			}
   451   			if( type == RPAREN )
   452   				break;
   453   		}
   454   	}
   455   	if( *mdef == NEWLABEL ) {
   456   		clabel = nlabel;
   457   		if( !nargs )
   458   			nlabel++;
   459   		else
   460   			nlabel =+ atoi(args[0]);
   461   	}
   462   	else if( *mdef == LABEL ) {
   463   		if( !nargs )
   464   			i = clabel;
   465   		else
   466   			i = clabel + atoi(args[0]);
   467   		pbnum(i);
   468   		pbtok("_L");
   469   	}
   470   	else {
   471   		mdef++;						/*skip no. of args*/
   472   		for( p = mdef + strlen(mdef) - 1; p >= mdef; p-- ) {
1File: MACRO.C                                                             Page       9
   473   			if( *p == ARG ) {
   474   				if( (j= *--p) <= nargs )
   475   					pbtok(args[j-1]);
   476   			}
   477   			else
   478   				putback(*p);
   479   		}
   480   	}
   481   }
   482    
   483   /* getfarg - get macro formal parameters*/
   484   /*		Skips blanks and handles "," and ")".*/
   485   getfarg(token)						/* returns token type*/
   486   char *token;						/* token returned*/
   487   {
   488   	register int type;
   489    
   490   	if( (type=getntok(token)) == RPAREN || type == ALPHA )
   491   		return(type);
   492   	if( type != COMMA || (type=getntok(token)) != ALPHA )
   493   		error("bad argument:%s",token);
   494   	return(type);
   495   }
   496    
   497   /* getntok - get next token, suppressing white space*/
   498   /*		Merely gettok's until non-white space is there*/
   499   getntok(token)						/* returns token type*/
   500   char *token;						/* token returned*/
   501   {
   502   	register int type;
   503    
   504   	while( (type=gettok(token)) == WHITE )
   505   		;
   506   	return(type);
   507   }
   508    
   509   /* getaarg - get macro actual argument*/
   510   /*		This handles the collecting of the macro's call arguments.*/
   511   /*		Note that you may have parenthesis as part of the macro argument,*/
   512   /*		hence you need to keep track of them.*/
   513   getaarg(argp)						/* returns token type*/
   514   char *argp;							/* argument returned*/
   515   {
   516   	int type, plevel, i;
   517   	register char *p, *ap;
   518   	char token[TOKSIZE];
   519   	
   520   	ap = argp;
   521   	*ap = '\0';
   522   	plevel = 0;
   523   	i = TOKSIZE;
   524   	while( ((type=gettok(token)) != COMMA && type != RPAREN) || plevel ) {
   525   		for( p = token; *ap = *p++; ap++ )
   526   			if( --i <= 0 ) {
   527   				error("macro argument too long");
   528   				return(EOF);
   529   			}
   530   		if( type == LPAREN )
   531   			plevel++;
1File: MACRO.C                                                             Page      10
   532   		else if( type == RPAREN )
   533   			plevel--;
   534   		else if( type == EOF ) {
   535   			error("unexpected EOF");
   536   			cexit();
   537   		}
   538   	}
   539   	if( ap == argp )
   540   		type = EOF;
   541   	return(type);
   542   }
   543    
   544   /* push - push a #ifdef condition value on condition stack*/
   545   /*		Checks for stack overflow.*/
   546   push(val)							/* returns - none*/
   547   int val;							/* value to push*/
   548   {
   549   	if( cstkptr >= &cstack[CSTKSIZE] ) {
   550   		error("condition stack overflow");
   551   		cexit();
   552   	}
   553   	*cstkptr++ = val;
   554   }
   555    
   556   /* pop - pop the #ifdef, etc. condition stack*/
   557   /*		Checks for stack undeflow.*/
   558   pop()								/* returns - top of condition stack*/
   559   {
   560   	if( cstkptr <= &cstack[0] )
   561   		return(-1);
   562   	return( *--cstkptr );
   563   }
   564    
   565   /* doinclude - handle #include command*/
   566   /*		Checks for file name or library file name and pushes file on*/
   567   /*		include file stack.*/
   568   doinclude(infile)					/* returns - none*/
   569   char *infile;						/* [vlh] for quoted include files */
   570   {
   571   	register int type, fd;
   572   	char token[TOKSIZE], fname[TOKSIZE];
   573   	register char *p, *q, c, *ptr1, *ptr2;
   574   	int i, j;
   575    
   576   	p = fname;
   577   	if( (type=getntok(token)) == SQUOTE || type == DQUOTE ) {
   578   		for( c = token[0], q = &token[1]; *q != c; )
   579   			*p++ = *q++;
   580   		*p = '\0';
   581   		p = getinclude(fname,infile);
   582   	}
   583   	else if( type != LESS ) {
   584   		error("bad include file");
   585   		return;
   586   	}
   587   	else {
   588   		while( (type=gettok(token))!=GREAT && type!=NEWL && type!=EOF )
   589   			for( q = token; *p = *q++; p++ )
   590   				;
1File: MACRO.C                                                             Page      11
   591   		if( type != GREAT ) {
   592   			error("bad include file name");
   593   			pbtok(token);
   594   			return;
   595   		}
   596   		p = getinclude(fname,0L);
   597   	}
   598   	eatup();					/*need here...*/
   599   	filep++;
   600   	if( filep >= &filestack[FSTACK] )
   601   		error("includes nested too deeply");
   602   	else {
   603   		if( fopen(p,&(filep->inbuf),0) < 0 )/* 3rd arg for versados */
   604   			error("can't open include file %s\n",p);
   605   		else {
   606   			filep->ifd = fd;
   607   			filep->lineno = 0;		/* [vlh] */
   608   			doifile(p);
   609   		}
   610   	}
   611   	putback('\n');				/*for eatup in domacro*/
   612   }
   613    
   614   doifile(p)	/* [vlh] */
   615   char *p;
   616   {
   617   	register char *iptr;
   618   	register int ndx;
   619    
   620   	while ((ndx = index(p,FILESEP)) >= 0) p =+ ndx+1;
   621   	for( iptr = filep->ifile; *p; ) *iptr++ = *p++;
   622   	*iptr = 0;
   623   }
   624    
   625   /* getinclude - get include file full pathname */
   626   char *
   627   getinclude(fname,parent)	/* [vlh] */
   628   char *fname;
   629   char *parent;				/* search parent-file home directory ? */
   630   {
   631   	register char *q, *t;
   632   	register int i, fd, ndx;
   633    
   634   	if (parent) {	/* include filename surrounded by quotes */
   635   		q = (filep == &filestack[0]) ? parent : (filep)->ifile;
   636   		t = &inclname;
   637   		while ((ndx = index(q,FILESEP)) >= 0) {
   638   			ndx++;
   639   			while (ndx--) *t++ = *q++;
   640   		}
   641   		for (q=fname; *t++ = *q++; );
   642   		*t = 0;
   643   		if ((fd = open(inclname,0)) >= 0) {	/* found it */
   644   			close(fd);
   645   			return(&inclname);
   646   		}
   647   	}
   648   	for (i=0; i<nincl; i++) {
   649   		for(t=inclname, q=incl[i]; *t++ = *q++; ) ;
1File: MACRO.C                                                             Page      12
   650   		for(q=fname, --t; *t++ = *q++; ) ;
   651   		*t = 0;
   652   		if ((fd = open(inclname,0)) >= 0) {
   653   			close(fd);
   654   			return(&inclname);
   655   		}
   656   	}
   657   	for(t=inclname, q=stdincl; *t++ = *q++; ) ;
   658   	for(q=fname, --t; *t++ = *q++; ) ;
   659   	*t = 0;
   660   	return(&inclname);
   661   }
   662    
   663   pbnum(num)							/* returns - none*/
   664   int num;
   665   {
   666   	register int digit;
   667    
   668   	do {
   669   		digit = num % 10;
   670   		num =/ 10;
   671   		putback(digit+'0');
   672   	} while( num > 0 );
   673   }
