238 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			238 lines
		
	
	
	
		
			5.6 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: MACRO-TEXT REPLACEMENT ROUTINES */
 | |
| 
 | |
| #include	"nopp.h"
 | |
| 
 | |
| #ifndef NOPP
 | |
| #include	"debug.h"	/* UF */
 | |
| #include	"pathlength.h"	/* UF */
 | |
| #include	"strsize.h"	/* UF */
 | |
| #include	<alloc.h>
 | |
| #include	"idf.h"
 | |
| #include	"input.h"
 | |
| #include	"macro.h"
 | |
| #include	"arith.h"
 | |
| #include	"LLlex.h"
 | |
| #include	"class.h"
 | |
| #include	"assert.h"
 | |
| #include	"interface.h"
 | |
| #include	"static.h"
 | |
| 
 | |
| char *strcpy(), *strcat();
 | |
| char *long2str();
 | |
| extern int InputLevel;
 | |
| 
 | |
| PRIVATE struct mlist	*ReplaceList;	/* list of currently active macros */
 | |
| 
 | |
| EXPORT int
 | |
| replace(idef)
 | |
| 	register struct idf *idef;
 | |
| {
 | |
| 	/*	replace() is called by the lexical analyzer to perform
 | |
| 		macro replacement.  "idef" is the description of the
 | |
| 		identifier which leads to the replacement.  If the
 | |
| 		optional actual parameters of the macro are OK, the text
 | |
| 		of the macro is prepared to serve as an input buffer,
 | |
| 		which is pushed onto the input stack.
 | |
| 		replace() returns 1 if the replacement succeeded and 0 if
 | |
| 		some error has occurred.
 | |
| 	*/
 | |
| 	register struct macro *mac = idef->id_macro;
 | |
| 	register struct mlist *repl;
 | |
| 	register int c;
 | |
| 	char **actpars, **getactuals();
 | |
| 	char *reptext, *macro2buffer();
 | |
| 	int size;
 | |
| 
 | |
| 	if (mac->mc_flag & NOREPLACE) {
 | |
| 		lexwarning("macro %s is recursive", idef->id_text);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	if (mac->mc_nps != -1) {	/* with parameter list	*/
 | |
| 		if (mac->mc_flag & FUNC) {
 | |
| 					/* must be "defined".
 | |
| 					   Unfortunately, the next assertion
 | |
| 					   will not compile ...
 | |
| 			ASSERT( ! strcmp("defined", idef->id_text));
 | |
| 					*/
 | |
| 			if (! AccDefined)
 | |
| 				return 0;
 | |
| 		}
 | |
| 		if (++mac->mc_count > 100) {
 | |
| 			/* 100 must be some number in Parameters */
 | |
| 			lexwarning("macro %s is assumed recursive",
 | |
| 				    idef->id_text);
 | |
| 			return 0;
 | |
| 		}
 | |
| 		LoadChar(c);
 | |
| 		c = skipspaces(c,! (mac->mc_flag & FUNC));
 | |
| 		if (c != '(') {		/* no replacement if no ()	*/
 | |
| 			PushBack();
 | |
| 			if (! (mac->mc_flag & FUNC)) {
 | |
| 				lexerror("(warning) macro %s needs arguments",
 | |
| 					idef->id_text);
 | |
| 				return 0;
 | |
| 			}
 | |
| 		}
 | |
| 		if (mac->mc_flag & FUNC) {
 | |
| 			struct idf *param;
 | |
| 			extern struct idf *GetIdentifier();
 | |
| 
 | |
| 			UnknownIdIsZero = 0;
 | |
| 			param = GetIdentifier();
 | |
| 			UnknownIdIsZero = 1;
 | |
| 			if (c == '(') {
 | |
| 				LoadChar(c);
 | |
| 				c = skipspaces(c,0);
 | |
| 				if (c != ')') error(") missing");
 | |
| 			}
 | |
| 			if (! param) {
 | |
| 				error("identifier missing");
 | |
| 			}
 | |
| 			repl = new_mlist();
 | |
| 			if (param && param->id_macro) 
 | |
| 				reptext = "1";
 | |
| 			else
 | |
| 				reptext = "0";
 | |
| 			InsertText(reptext, 1);
 | |
| 			InputLevel++;
 | |
| 			repl->m_level = InputLevel;
 | |
| 			repl->next = ReplaceList;
 | |
| 			ReplaceList = repl;
 | |
| 			repl->m_mac = mac;
 | |
| 			return 1;
 | |
| 		}
 | |
| 		actpars = getactuals(idef);	/* get act.param. list	*/
 | |
| 	}
 | |
| 	repl = new_mlist();
 | |
| 	repl->m_mac = mac;
 | |
| 	if (mac->mc_flag & FUNC) /* this macro leads to special action	*/
 | |
| 		macro_func(idef);
 | |
| 	if (mac->mc_nps <= 0) {
 | |
| 		reptext = mac->mc_text;
 | |
| 		size = mac->mc_length;
 | |
| 		mac->mc_flag |= NOREPLACE;
 | |
| 	}
 | |
| 	else {
 | |
| 		reptext = macro2buffer(idef, actpars, &size); /* create input buffer */
 | |
| 		repl->m_repl = reptext;
 | |
| 	}
 | |
| 	InsertText(reptext, size);
 | |
| 	InputLevel++;
 | |
| 	repl->m_level = InputLevel;
 | |
| 	repl->next = ReplaceList;
 | |
| 	ReplaceList = repl;
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| GSTATIC char FilNamBuf[PATHLENGTH];
 | |
| 
 | |
| PRIVATE
 | |
| macro_func(idef)
 | |
| 	register struct idf *idef;
 | |
| {
 | |
| 	/*	macro_func() performs the special actions needed with some
 | |
| 		macros.  These macros are __FILE__ and __LINE__ which
 | |
| 		replacement texts must be evaluated at the time they are
 | |
| 		used.
 | |
| 	*/
 | |
| 	register struct macro *mac = idef->id_macro;
 | |
| 
 | |
| 	switch (idef->id_text[2]) { /* This switch is very blunt... */
 | |
| 	case 'F' :			/* __FILE__	*/
 | |
| 		FilNamBuf[0] = '"';
 | |
| 		strcpy(&FilNamBuf[1], FileName);
 | |
| 		strcat(FilNamBuf, "\"");
 | |
| 		mac->mc_text = FilNamBuf;
 | |
| 		mac->mc_length = strlen(FilNamBuf);
 | |
| 		break;
 | |
| 	case 'L' :			/* __LINE__	*/
 | |
| 		mac->mc_text = long2str((long)LineNumber, 10);
 | |
| 		mac->mc_length = 1;
 | |
| 		break;
 | |
| 	default :
 | |
| 		crash("(macro_func)");
 | |
| 		/*NOTREACHED*/
 | |
| 	}
 | |
| }
 | |
| 
 | |
| PRIVATE char *
 | |
| macro2buffer(idef, actpars, siztext)
 | |
| 	struct idf *idef;
 | |
| 	char **actpars;
 | |
| 	int *siztext;
 | |
| {
 | |
| 	/*	Macro2buffer() turns the macro replacement text, as it is
 | |
| 		stored, into an input buffer, while each occurrence of the
 | |
| 		non-ascii formal parameter mark is replaced by its
 | |
| 		corresponding actual parameter specified in the actual
 | |
| 		parameter list actpars.  A pointer to the beginning of the
 | |
| 		constructed text is returned, while *siztext is filled
 | |
| 		with its length.
 | |
| 		If there are no parameters, this function behaves
 | |
| 		the same as strcpy().
 | |
| 	*/
 | |
| 	register int size = 8;
 | |
| 	register char *text = Malloc(size);
 | |
| 	register int pos = 0;
 | |
| 	register char *ptr = idef->id_macro->mc_text;
 | |
| 
 | |
| 	while (*ptr) {
 | |
| 		if (*ptr & FORMALP) {	/* non-asc formal param. mark	*/
 | |
| 			register int n = *ptr++ & 0177;
 | |
| 			register char *p;
 | |
| 
 | |
| 			ASSERT(n != 0);
 | |
| 			/*	copy the text of the actual parameter
 | |
| 				into the replacement text
 | |
| 			*/
 | |
| 			for (p = actpars[n - 1]; *p; p++) {
 | |
| 				text[pos++] = *p;
 | |
| 				if (pos == size)
 | |
| 					text = Srealloc(text, size += RSTRSIZE);
 | |
| 			}
 | |
| 		}
 | |
| 		else {
 | |
| 			text[pos++] = *ptr++;
 | |
| 			if (pos == size)
 | |
| 				text = Srealloc(text, size += RSTRSIZE);
 | |
| 		}
 | |
| 	}
 | |
| 	text[pos] = '\0';
 | |
| 	*siztext = pos;
 | |
| 	return text;
 | |
| }
 | |
| 
 | |
| EXPORT
 | |
| DoUnstack()
 | |
| {
 | |
| 	Unstacked = 1;
 | |
| }
 | |
| 
 | |
| EXPORT
 | |
| EnableMacros()
 | |
| {
 | |
| 	register struct mlist *p = ReplaceList, *prev = 0;
 | |
| 
 | |
| 	ASSERT(Unstacked > 0);
 | |
| 	while (p) {
 | |
| 		struct mlist *nxt = p->next;
 | |
| 
 | |
| 		if (p->m_level > InputLevel) {
 | |
| 			p->m_mac->mc_flag &= ~NOREPLACE;
 | |
| 			if (p->m_mac->mc_count) p->m_mac->mc_count--;
 | |
| 			if (p->m_repl) free(p->m_repl);
 | |
| 			if (! prev) ReplaceList = nxt;
 | |
| 			else prev->next = nxt;
 | |
| 			free_mlist(p);
 | |
| 		}
 | |
| 		else prev = p;
 | |
| 		p = nxt;
 | |
| 	}
 | |
| 	Unstacked = 0;
 | |
| }
 | |
| #endif NOPP
 |