602 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			602 lines
		
	
	
	
		
			12 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".
 | 
						|
 */
 | 
						|
/* $Id$ */
 | 
						|
/* PREPROCESSOR DRIVER */
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <system.h>
 | 
						|
#include <alloc.h>
 | 
						|
#include "preprocess.h"
 | 
						|
#include "input.h"
 | 
						|
#include "parameters.h"
 | 
						|
#include "arith.h"
 | 
						|
#include "LLlex.h"
 | 
						|
#include "class.h"
 | 
						|
#include "macro.h"
 | 
						|
#include "domacro.h"
 | 
						|
#include "replace.h"
 | 
						|
#include "idf.h"
 | 
						|
#include "error.h"
 | 
						|
#include "bits.h"
 | 
						|
#include "skip.h"
 | 
						|
 | 
						|
char _obuf[OBUFSIZE];
 | 
						|
#ifdef DOBITS
 | 
						|
char bits[128];
 | 
						|
#endif
 | 
						|
extern int InputLevel;
 | 
						|
 | 
						|
extern char* sprint();
 | 
						|
 | 
						|
void Xflush(void)
 | 
						|
{
 | 
						|
	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;
 | 
						|
 | 
						|
void do_pragma(void)
 | 
						|
{
 | 
						|
	register int size = ITEXTSIZE;
 | 
						|
	char* cur_line = Malloc((unsigned)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 (!InputLevel)
 | 
						|
			{
 | 
						|
				c = GetChar();
 | 
						|
				if (c == '*')
 | 
						|
				{
 | 
						|
					skipcomment();
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
				else if (c == '/')
 | 
						|
				{
 | 
						|
					skiplinecomment();
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
				*c_ptr++ = '/';
 | 
						|
			}
 | 
						|
		}
 | 
						|
		*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];
 | 
						|
 | 
						|
void preprocess(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, (int)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;
 | 
						|
						}
 | 
						|
						else if (c == '/')
 | 
						|
						{
 | 
						|
							skiplinecomment();
 | 
						|
							c = GetChar();
 | 
						|
							continue;
 | 
						|
						}
 | 
						|
						UnGetChar();
 | 
						|
						c = '/';
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				}
 | 
						|
				echo(c);
 | 
						|
				c = GetChar();
 | 
						|
			}
 | 
						|
 | 
						|
			if (c == '#')
 | 
						|
			{
 | 
						|
				domacro();
 | 
						|
				lineno++;
 | 
						|
				newline();
 | 
						|
				do_line_dir(lineno, fn);
 | 
						|
				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;
 | 
						|
				}
 | 
						|
				else if (c == '/')
 | 
						|
				{
 | 
						|
					skiplinecomment();
 | 
						|
					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(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;
 | 
						|
}
 |