shithub: scc

Download patch

ref: e5c045851833cfd6b4a8a3326131caf5a406410b
parent: 66ece20b08a2c9fc5ee1ae0bd8c3f2dc2042d168
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Wed Jan 11 06:17:11 EST 2017

[cc1] Add support for macro expansion in input buffers

We are going to implement the macro expansion using a push up/pop down of buffers.
It is important to keep a track of the symbol which generates the push up,
because this symbol becomes part of the hide set (see Prosser algorithm)
of the current expansion.

--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -307,6 +307,7 @@
 	Type *type;
 	unsigned short id;
 	unsigned char ctx;
+	unsigned char hide;
 	char ns;
 	unsigned char token;
 	short flags;
@@ -344,6 +345,7 @@
 struct input {
 	char *fname;
 	FILE *fp;
+	Symbol *hide;
 	char *line, *begin, *p;
 	struct input *next;
 	unsigned short nline;
@@ -392,7 +394,7 @@
 extern int moreinput(void);
 extern void expect(unsigned tok);
 extern void discard(void);
-extern int addinput(char *fname);
+extern int addinput(char *fname, Symbol *hide);
 extern void allocinput(char *fname, FILE *fp, char *line);
 extern void delinput(void);
 extern void setsafe(int type);
--- a/cc1/cpp.c
+++ b/cc1/cpp.c
@@ -238,14 +238,13 @@
 	error("macro expansion of \"%s\" too long", macroname);
 }
 
-#define BUFSIZE ((INPUTSIZ > FILENAME_MAX+2) ? INPUTSIZ : FILENAME_MAX+2)
 int
 expand(char *begin, Symbol *sym)
 {
-	size_t total, elen, rlen, llen, ilen;
+	size_t elen;
 	int n;
 	char *s = sym->u.s;
-	char *arglist[NR_MACROARG], arguments[INPUTSIZ], buffer[BUFSIZE];
+	char *arglist[NR_MACROARG], arguments[INPUTSIZ], buffer[INPUTSIZ];
 
 	macroname = sym->name;
 	if (sym == symfile) {
@@ -268,30 +267,12 @@
 
 substitute:
 	DBG("MACRO '%s' expanded to :'%s'", macroname, buffer);
-	rlen = strlen(input->p);      /* rigth length */
-	llen = begin - input->line;   /* left length */
-	ilen = input->p - begin;      /* invocation length */
-	total = llen + elen + rlen;
 
-	if (total >= LINESIZ)
-		error("macro expansion of \"%s\" too long", macroname);
-
-	/* cut macro invocation */
-	memmove(begin, begin + ilen, rlen);
-
-	/* paste macro expansion */
-	memmove(begin + elen, begin, rlen);
-	memcpy(begin, buffer, elen);
-	input->line[total] = '\0';
-
-	input->p = input->begin = begin;
-
-	if (!(sym->flags & SDECLARED))
-		killsym(sym);
-
+	addinput(NULL, sym);
+	memcpy(input->line, buffer, elen);
+	input->line[elen] = '\0';
 	return 1;
 }
-#undef BUFSIZE
 
 static int
 getpars(Symbol *args[NR_MACROARG])
@@ -449,7 +430,7 @@
 	memcpy(path+dirlen, file, filelen);
 	path[dirlen + filelen] = '\0';
 
-	return addinput(path);
+	return addinput(path, NULL);
 }
 
 static void
--- a/cc1/lex.c
+++ b/cc1/lex.c
@@ -2,6 +2,7 @@
 static char sccsid[] = "@(#) ./cc1/lex.c";
 #include <ctype.h>
 #include <errno.h>
+#include <limits.h>
 #include <setjmp.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -85,18 +86,32 @@
 }
 
 int
-addinput(char *fname)
+addinput(char *fname, Symbol *hide)
 {
 	FILE *fp;
+	unsigned nline = 0;
 
-	if (fname) {
+	if (hide) {
+		/* this is a macro expansion */
+		fp = NULL;
+		fname = xstrdup(input->fname);
+		nline = input->nline;
+		if (hide->hide == UCHAR_MAX)
+			die("Too many macro expansions");
+		++hide->hide;
+	} else  if (fname) {
+		/* a new file */
 		if ((fp = fopen(fname, "r")) == NULL)
 			return 0;
 	} else {
+		/* reading from stdin */
 		fp = stdin;
 		fname = "<stdin>";
 	}
 	allocinput(fname, fp, NULL);
+	input->hide = hide;
+	input->nline = nline;
+
 	return 1;
 }
 
@@ -104,6 +119,7 @@
 delinput(void)
 {
 	Input *ip = input;
+	Symbol *hide = ip->hide;
 
 	if (ip->fp) {
 		if (fclose(ip->fp))
@@ -112,6 +128,17 @@
 		if (!ip->next)
 			eof = 1;
 	}
+	if (hide) {
+		--hide->hide;
+		/*
+		 * If the symbol is not declared then it was
+		 * an extension due to a #if directive with
+		 * a non declared symbol (expanded to 0),
+		 * thus we have to kill the symbol
+		 */
+		if ((hide->flags & SDECLARED) == 0)
+			killsym(hide);
+	}
 	if (eof)
 		return;
 	input = ip->next;
@@ -179,14 +206,21 @@
 	char *bp, *lim;
 	char c, peekc = 0;
 
-repeat:
+repeat_from_file:
 	input->begin = input->p = input->line;
 	*input->line = '\0';
+
+repeat_from_expand:
 	if (eof)
 		return 0;
+
+	if (!input->fp) {
+		delinput();
+		goto repeat_from_expand;
+	}
 	if (feof(input->fp)) {
 		delinput();
-		goto repeat;
+		goto repeat_from_file;
 	}
 	lim = &input->line[INPUTSIZ-1];
 	for (bp = input->line; bp < lim; *bp++ = c) {
@@ -213,8 +247,10 @@
 	static char file[FILENAME_MAX];
 	static unsigned nline;
 	char *s;
+	int wasexpand;
 
 repeat:
+	wasexpand = input->hide != NULL;
 	if (!readline())
 		return 0;
 	while (isspace(*input->p))
@@ -225,7 +261,7 @@
 		goto repeat;
 	}
 
-	if (onlycpp) {
+	if (onlycpp && !wasexpand) {
 		putchar('\n');
 		if (strcmp(file, input->fname)) {
 			strcpy(file, input->fname);
@@ -497,7 +533,7 @@
 	input->p = p;
 	tok2str();
 	if ((sym = lookup(NS_CPP, yytext, NOALLOC)) != NULL) {
-		if (!disexpand && expand(begin, sym))
+		if (!disexpand && !sym->hide && expand(begin, sym))
 			return next();
 	}
 	sym = lookup(namespace, yytext, ALLOC);
--- a/cc1/main.c
+++ b/cc1/main.c
@@ -102,7 +102,7 @@
 	for (i = 0; i < uflags.n; ++i)
 		undefmacro(uflags.s[i]);
 
-	if (!addinput(*argv)) {
+	if (!addinput(*argv, NULL)) {
 		die("error: failed to open input file '%s': %s",
 		    *argv, strerror(errno));
 	}
--- a/cc1/symbol.c
+++ b/cc1/symbol.c
@@ -152,6 +152,7 @@
 		name = xstrdup(name);
 	sym->name = name;
 	sym->id = 0;
+	sym->hide = 0;
 	sym->ns = ns;
 	sym->ctx = (ns == NS_CPP) ? UCHAR_MAX : curctx;
 	sym->token = IDEN;