456 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			456 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | |
|  * See the copyright notice in the ACK home directory, in the file "Copyright".
 | |
|  */
 | |
| /* $Header$ */
 | |
| /* PREPROCESSOR DRIVER */
 | |
| 
 | |
| #include	<system.h>
 | |
| #include	<alloc.h>
 | |
| #include	"input.h"
 | |
| #include	"obufsize.h"
 | |
| #include	"arith.h"
 | |
| #include	"LLlex.h"
 | |
| #include	"class.h"
 | |
| #include	"macro.h"
 | |
| #include	"idf.h"
 | |
| #include	"idfsize.h"
 | |
| #include	"bits.h"
 | |
| #include	"ln_prefix.h"
 | |
| #include	"textsize.h"
 | |
| 
 | |
| char	_obuf[OBUFSIZE];
 | |
| #ifdef DOBITS
 | |
| char	bits[128];
 | |
| #endif
 | |
| extern int InputLevel;
 | |
| 
 | |
| Xflush()
 | |
| {
 | |
| 	sys_write(STDOUT, _obuf, OBUFSIZE);
 | |
| }
 | |
| 
 | |
| static char *SkipComment();
 | |
| extern char options[];
 | |
| 
 | |
| /* #pragma directives are saved here and passed to the compiler later on.
 | |
|  */
 | |
| struct prag_info {
 | |
| 	int	pr_linnr;
 | |
| 	char	*pr_fil;
 | |
| 	char	*pr_text;
 | |
| };
 | |
| static struct prag_info *pragma_tab;
 | |
| static int pragma_nr;
 | |
| 
 | |
| do_pragma()
 | |
| {
 | |
| 	register int size = ITEXTSIZE;
 | |
| 	char *cur_line = Malloc(size);
 | |
| 	register char *c_ptr = cur_line;
 | |
| 	register int c = GetChar();
 | |
| 	register int delim = 0;
 | |
| 
 | |
| 	while(c != '\n') {
 | |
| 		if (c_ptr + 1 - cur_line == size) {
 | |
| 			cur_line = Realloc(cur_line, (unsigned)(size + ITEXTSIZE));
 | |
| 			c_ptr = cur_line + size - 1;
 | |
| 			size += ITEXTSIZE;
 | |
| 		}
 | |
| 		if (delim) {
 | |
| 			if (c == delim) {
 | |
| 				delim = 0;
 | |
| 			}
 | |
| 			else if (c == '\\') {
 | |
| 				*c_ptr++ = c;
 | |
| 				c = GetChar();
 | |
| 				if (c == '\n') break;
 | |
| 			}
 | |
| 		}
 | |
| 		else if (c == '\'' || c == '"') {
 | |
| 			delim = c;
 | |
| 		}
 | |
| 		else if (c == '/') {
 | |
| 			if ((c = GetChar()) != '*' || InputLevel) {
 | |
| 				*c_ptr++ = '/';
 | |
| 			}
 | |
| 			else {
 | |
| 				skipcomment();
 | |
| 				continue;
 | |
| 			}
 | |
| 		}
 | |
| 		*c_ptr++ = c;
 | |
| 		c = GetChar();
 | |
| 	}
 | |
| 	*c_ptr = '\0';
 | |
| 	if (!pragma_nr) {
 | |
| 		pragma_tab = (struct prag_info *)Malloc(sizeof(struct prag_info));
 | |
| 	} else {
 | |
| 		pragma_tab = (struct prag_info *)Realloc((char *)pragma_tab
 | |
| 				    , (unsigned)(sizeof(struct prag_info) * (pragma_nr+1)));
 | |
| 	}
 | |
| 	if (delim) {
 | |
| 		error("unclosed opening %c", delim);
 | |
| 	}
 | |
| 	pragma_tab[pragma_nr].pr_linnr = LineNumber;
 | |
| 	pragma_tab[pragma_nr].pr_fil = FileName;
 | |
| 	pragma_tab[pragma_nr].pr_text = cur_line;
 | |
| 	pragma_nr++;
 | |
| 	LineNumber++;
 | |
| }
 | |
| 
 | |
| char Xbuf[256];
 | |
| 
 | |
| preprocess(fn)
 | |
| 	char *fn;
 | |
| {
 | |
| 	register int c;
 | |
| 	register char *op = _obuf;
 | |
| 	register char *ob = &_obuf[OBUFSIZE];
 | |
| 	int lineno = 0;
 | |
| 	int startline;
 | |
| 
 | |
| #define flush(X)	(sys_write(STDOUT,_obuf,X))
 | |
| #define echo(ch) 	if (op == ob) { Xflush(); op = _obuf; } *op++ = (ch);
 | |
| #define newline()	op--; while (op >= _obuf && (*op == ' ' || *op == '\t')) op--; op++; echo('\n')
 | |
| 
 | |
| 	if (!options['P']) {
 | |
| 		/* Generate a line directive communicating the
 | |
| 		   source filename
 | |
| 		*/
 | |
| 		register char *p = Xbuf;
 | |
| 
 | |
| 		sprint(p, "%s 1 \"%s\"\n",
 | |
| 			LINE_PREFIX,
 | |
| 			FileName);
 | |
| 		while (*p) {
 | |
| 			echo(*p++);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| #define	do_line_dir(lineno, fn)						\
 | |
| 		if (lineno != LineNumber || fn != FileName) {		\
 | |
| 			fn = FileName;					\
 | |
| 			lineno = LineNumber;				\
 | |
| 			if (! options['P']) {				\
 | |
| 				register char *p = Xbuf;		\
 | |
| 				sprint(Xbuf, "%s %d \"%s\"\n",		\
 | |
| 					LINE_PREFIX,			\
 | |
| 					LineNumber,			\
 | |
| 					FileName);			\
 | |
| 				op--;					\
 | |
| 				while (op >= _obuf			\
 | |
| 				       && (class(*op) == STSKIP		\
 | |
| 					   || *op == '\n')) op--;	\
 | |
| 				op++;					\
 | |
| 				newline();				\
 | |
| 				while (*p) {				\
 | |
| 					echo(*p++);			\
 | |
| 				}					\
 | |
| 			}						\
 | |
| 		}
 | |
| 
 | |
| 	for (;;) {
 | |
| 		LineNumber++;
 | |
| 		lineno++;
 | |
| 		startline = 1;
 | |
| 		c = GetChar();
 | |
| 		while (startline) {
 | |
| 		    /* first flush the saved pragma's */
 | |
| 		    if (pragma_nr) {
 | |
| 			register int i = 0;
 | |
| 			int LiNo = LineNumber;
 | |
| 			char *FiNam = FileName;
 | |
| 
 | |
| 			while (i < pragma_nr) {
 | |
| 			    register char *c_ptr = "#pragma";
 | |
| 
 | |
| 			    LineNumber = pragma_tab[i].pr_linnr;
 | |
| 			    FileName = pragma_tab[i].pr_fil;
 | |
| 			    do_line_dir(lineno, fn);
 | |
| 			    while (*c_ptr) { echo(*c_ptr++); }
 | |
| 			    c_ptr = pragma_tab[i].pr_text;
 | |
| 			    while (*c_ptr) { echo(*c_ptr++); }
 | |
| 			    newline(); lineno++;
 | |
| 			    free(pragma_tab[i].pr_text);
 | |
| 			    i++;
 | |
| 			}
 | |
| 			free((char *) pragma_tab);
 | |
| 			pragma_tab = (struct prag_info *)0;
 | |
| 			pragma_nr = 0;
 | |
| 			LineNumber = LiNo;
 | |
| 			FileName = FiNam;
 | |
| 			do_line_dir(lineno, fn);
 | |
| 		    }
 | |
| 
 | |
| 
 | |
| 		    while (class(c) == STSKIP || c == '/') {
 | |
| 			if (c == '/') {
 | |
| 			    if (!InputLevel) {
 | |
| 				c = GetChar();
 | |
| 				if (c == '*') {
 | |
| 				    op = SkipComment(op, &lineno);
 | |
| 				    if (!op) return;
 | |
| 				    if (!options['C']) { echo(' '); }
 | |
| 				    c = GetChar();
 | |
| 				    continue;
 | |
| 				}
 | |
| 				UnGetChar();
 | |
| 				c = '/';
 | |
| 			    }
 | |
| 			    break;
 | |
| 			}
 | |
| 			echo(c);
 | |
| 			c = GetChar();
 | |
| 		    }
 | |
| 
 | |
| 		    if (c == '#') {
 | |
| 			domacro();
 | |
| 			lineno++;
 | |
| 			newline();
 | |
| 			c = GetChar();
 | |
| 		    } else startline = 0;
 | |
| 		}
 | |
| 		do_line_dir(lineno, fn);
 | |
| 		for (;;) {
 | |
| 
 | |
| 			/* illegal character */
 | |
| 			if (c & 0200)  {
 | |
| 				if (c == EOI) {
 | |
| 					newline();
 | |
| 					flush((int)(op-_obuf));
 | |
| 					return;
 | |
| 				}
 | |
| 				fatal("non-ascii character read");
 | |
| 			}
 | |
| 
 | |
| 			/* comments */
 | |
| 			if (c == '/' && !InputLevel) {
 | |
| 				c = GetChar();
 | |
| 				if (c == '*') {
 | |
| 					op = SkipComment(op, &lineno);
 | |
| 					if (!op) return;
 | |
| 					if (!options['C']) { echo(' '); }
 | |
| 					c = GetChar();
 | |
| 					continue;
 | |
| 				}
 | |
| 				echo('/');
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			/* switch on character */
 | |
| 			switch(class(c)) {
 | |
| 			case STNL:
 | |
| 				newline();
 | |
| 				break;
 | |
| 			case STSTR:
 | |
| 			case STCHAR:
 | |
| 				{
 | |
| 				register int stopc = c;
 | |
| 				int escaped;
 | |
| 
 | |
| 				do {
 | |
| 					escaped = 0;
 | |
| 					echo(c);
 | |
| 					c = GetChar();
 | |
| 					if (c == '\n') {
 | |
| 					/* the compiler will complain */
 | |
| 						break;
 | |
| 					}
 | |
| 					else if (c == EOI) {
 | |
| 						newline();
 | |
| 						flush((int)(op-_obuf));
 | |
| 						return;
 | |
| 					}
 | |
| 					if (c == '\\') {
 | |
| 						echo(c);
 | |
| 						c = GetChar();
 | |
| 						if (c == '\n') {
 | |
| 							++LineNumber;
 | |
| 							lineno++;
 | |
| 						} else escaped = 1;
 | |
| 					}
 | |
| 				} while (escaped || c != stopc);
 | |
| 				echo(c);
 | |
| 				if (c == '\n')
 | |
| 					break;	/* Don't eat # */
 | |
| 				c = GetChar();
 | |
| 				continue;
 | |
| 				}
 | |
| 			case STNUM:
 | |
| 			/* The following code is quit ugly. This because
 | |
| 			 * ..3 == . .3 , whereas ...3 == ... 3
 | |
| 			 */
 | |
| 				echo(c);
 | |
| 				if (c == '.') {
 | |
| 					c = GetChar();
 | |
| 					if (c == '.') {
 | |
| 						if ((c = GetChar()) == '.') {
 | |
| 							echo('.'); echo('.');
 | |
| 							c = GetChar();
 | |
| 							continue;
 | |
| 						}
 | |
| 						UnGetChar();
 | |
| 						c = '.';
 | |
| 						continue;
 | |
| 					} else if (!is_dig(c)) {
 | |
| 						continue;
 | |
| 					} else { echo(c); }
 | |
| 				}
 | |
| 				c = GetChar();
 | |
| 				while (in_idf(c) || c == '.') {
 | |
| 					echo(c);
 | |
| 					if (c == 'e' || c == 'E') {
 | |
| 						c = GetChar();
 | |
| 						if (c == '+' || c == '-') {
 | |
| 							echo(c);
 | |
| 							c = GetChar();
 | |
| 						}
 | |
| 					} else	c = GetChar();
 | |
| 				}
 | |
| 				continue;
 | |
| 			case STELL:
 | |
| 				c = GetChar();
 | |
| 				UnGetChar();
 | |
| 				if (c == '"' || c == '\'') {
 | |
| 					echo('L');
 | |
| 					continue;
 | |
| 				}
 | |
| 				c = 'L';
 | |
| 			case STIDF: {
 | |
| 				extern int idfsize;		/* ??? */
 | |
| 				char buf[IDFSIZE + 1];
 | |
| 				register char *tg = &buf[0];
 | |
| 				register char *maxpos = &buf[idfsize];
 | |
| 				register struct idf *idef;
 | |
| 				int NoExpandNext = 0;
 | |
| 
 | |
| #define tstmac(bx)	if (!(bits[c] & bx)) goto nomac
 | |
| #define cpy		*tg++ = c
 | |
| #define load		c = GetChar(); if (!in_idf(c)) goto endidf
 | |
| 
 | |
| 				/* unstack macro's when allowed. */
 | |
| 				if (Unstacked)
 | |
| 					EnableMacros();
 | |
| 				if (c == NOEXPM) {
 | |
| 					NoExpandNext = 1;
 | |
| 					c = GetChar();
 | |
| 				}
 | |
| 
 | |
| #ifdef DOBITS
 | |
| 				cpy; tstmac(bit0); load;
 | |
| 				cpy; tstmac(bit1); load;
 | |
| 				cpy; tstmac(bit2); load;
 | |
| 				cpy; tstmac(bit3); load;
 | |
| 				cpy; tstmac(bit4); load;
 | |
| 				cpy; tstmac(bit5); load;
 | |
| 				cpy; tstmac(bit6); load;
 | |
| 				cpy; tstmac(bit7); load;
 | |
| #endif
 | |
| 
 | |
| 				for(;;) {
 | |
| 					if (tg < maxpos) {
 | |
| 						cpy;
 | |
| 					}
 | |
| 					load;
 | |
| 				}
 | |
| 			endidf:
 | |
| 				if (c != EOF) UnGetChar();
 | |
| 				*tg = '\0';	/* mark the end of the identifier */
 | |
| 				if ((idef = findidf(buf))
 | |
| 				    && idef->id_macro
 | |
| 				    && ReplaceMacros && !NoExpandNext) {
 | |
| 					if (replace(idef)) {
 | |
| 						echo(' ');
 | |
| 						c = GetChar();
 | |
| 						continue;
 | |
| 					}
 | |
| 					tg = buf;
 | |
| 					while (*tg) {
 | |
| 						echo(*tg++);
 | |
| 					}
 | |
| 					c = GetChar();
 | |
| 					if (in_idf(c)) { echo(' '); }
 | |
| 					continue;
 | |
| 				}
 | |
| 			nomac:
 | |
| 				*tg = '\0';
 | |
| 				tg = buf;
 | |
| 				while (*tg) {
 | |
| 					echo(*tg++);
 | |
| 				}
 | |
| 				c = GetChar();
 | |
| 				while (in_idf(c)) {
 | |
| 					echo(c);
 | |
| 					c = GetChar();
 | |
| 				}
 | |
| 				continue;
 | |
| 				}
 | |
| 			case STMSPEC:
 | |
| 				if (InputLevel) {
 | |
| 					echo(' ');	/* seperate tokens */
 | |
| 					c = GetChar();
 | |
| 					continue;
 | |
| 				}
 | |
| 				/* else fallthrough */
 | |
| 			default:
 | |
| 			    	echo(c);
 | |
| 			    	c = GetChar();
 | |
| 			    	continue;
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 	/*NOTREACHED*/
 | |
| }
 | |
| 
 | |
| static char *
 | |
| SkipComment(op, lineno)
 | |
| char *op;
 | |
| int *lineno;
 | |
| {
 | |
| 	char *ob = &_obuf[OBUFSIZE];
 | |
| 	register int c, oldc = '\0';
 | |
| 
 | |
| 	NoUnstack++;
 | |
| 	if (options['C']) {
 | |
| 		echo('/');
 | |
| 		echo('*');
 | |
| 	}
 | |
| 	c = GetChar();
 | |
| 	for(;;) {
 | |
| 		if (c == EOI) {
 | |
| 			newline();
 | |
| 			flush((int)(op - _obuf));
 | |
| 			op = 0;
 | |
| 			break;
 | |
| 		}
 | |
| 		if (options['C']) {
 | |
| 			echo(c);
 | |
| 		}
 | |
| 		if (c == '\n') {
 | |
| 			++LineNumber;
 | |
| 			++*lineno;
 | |
| 			if (!options['C']) {
 | |
| 				echo(c);
 | |
| 			}
 | |
| 		}
 | |
| 		if (c == '*') {
 | |
| 			c = GetChar();
 | |
| 			if (c == '/') {
 | |
| 				if (options['C']) {
 | |
| 					echo(c);
 | |
| 				}
 | |
| 				break;			/* for(;;) */
 | |
| 			} else if (oldc == '/') {
 | |
| 				warning("comment inside comment ?");
 | |
| 			}
 | |
| 			oldc = '*';
 | |
| 		} else {
 | |
| 			oldc = c;
 | |
| 			c = GetChar();
 | |
| 		}
 | |
| 	}
 | |
| 	NoUnstack--;
 | |
| 	return op;
 | |
| }
 |