shithub: scc

Download patch

ref: e87b3ab194e7cf293c90f555b96a9278c1698215
parent: cd6d1548bbb6365822d9b690bb85b2b582778b2e
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Sat May 23 06:04:08 EDT 2015

Add expansion of macros

--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -1,4 +1,5 @@
 
+#define INPUTSIZ 120
 
 /*
  * Definition of structures
@@ -271,7 +272,7 @@
 extern unsigned short getfline(void);
 extern void setfname(char *name);
 extern void setfline(unsigned short line);
-extern bool addinput(char *fname);
+extern char *addinput(char *fname);
 extern void setnamespace(int ns);
 extern void setsafe(int type);
 #define accept(t) ((yytoken == (t)) ? next() : 0)
@@ -289,6 +290,7 @@
 
 /* cpp.c */
 extern char *preprocessor(char *s);
+extern bool expand(Symbol *sym);
 
 /*
  * Definition of global variables
@@ -296,6 +298,7 @@
 extern struct yystype yylval;
 extern char yytext[];
 extern unsigned yytoken;
+extern unsigned short yylen;
 
 extern Type *voidtype, *pvoidtype, *booltype,	
             *uchartype,   *chartype,
--- a/cc1/cpp.c
+++ b/cc1/cpp.c
@@ -11,6 +11,138 @@
 
 /* TODO: preprocessor error must not rise recover */
 
+static char *argp;
+static unsigned arglen;
+static Symbol *lastmacro;
+
+static void
+nextcpp(void)
+{
+	next();
+	if (yytoken == EOFTOK) {
+		error("unterminated argument list invoking macro \"%s\"",
+		      lastmacro->name);
+	}
+	if (yylen + 1 > arglen) {
+		error("argument overflow invoking macro \"%s\"",
+		      lastmacro->name);
+	}
+	memcpy(argp, yytext, yylen);
+	argp += yylen;
+	*argp++ = ' ';
+	arglen -= yylen + 1;
+}
+
+static void
+paren(void)
+{
+	for (;;) {
+		nextcpp();
+		switch (yytoken) {
+		case ')':
+			return;
+		case '(':
+			paren();
+			break;
+		}
+	}
+}
+
+static void
+parameter(void)
+{
+	for (;;) {
+		nextcpp();
+		switch (yytoken) {
+		case ')':
+		case ',':
+			argp -= 2;
+			*argp++ = '\0';
+			return;
+		case '(':
+			paren();
+			break;
+		}
+	}
+}
+
+static bool
+parsepars(char *buffer, char **listp, int nargs)
+{
+	int n;
+
+	if (nargs == -1)
+		return 1;
+
+	if (ahead() != '(')
+		return 0;
+	next();
+
+	n = 0;
+	argp = buffer;
+	arglen = INPUTSIZ;
+	if (ahead() != ')') {
+		do {
+			*listp++ = argp;
+			parameter();
+		} while (++n < NR_MACROARG && yytoken == ',');
+	}
+
+	if (n == NR_MACROARG)
+		error("too much parameters in macro \"%s\"", lastmacro->name);
+	if (n != nargs) {
+		error("macro \"%s\" passed %d arguments, but it takes %d",
+		      lastmacro->name, n, nargs);
+	}
+	return 1;
+}
+
+/*
+ * sym->u.s is a string with the following format:
+ * 	dd#string
+ * where dd is the number of arguments of the macro
+ * (-1 if it is a macro without arguments), and string
+ * is the macro definition, where @dd@ indicates the
+ * parameter number dd
+ */
+bool
+expand(Symbol *sym)
+{
+	unsigned len;
+	char *arglist[NR_MACROARG], buffer[INPUTSIZ];
+	char c, *bp, *arg, *s = sym->u.s;
+
+	lastmacro = sym;
+	if (!parsepars(buffer, arglist, atoi(s)))
+		return 0;
+
+	bp = addinput(NULL);
+	len = INPUTSIZ-1;
+	for (s += 3; c = *s; ++s) {
+		if (c != '@') {
+			if (len-- == 0)
+				goto expansion_too_long;
+			*bp++ = c;
+		} else {
+			unsigned size;
+
+			arg = arglist[atoi(++s)];
+			size = strlen(arg);
+			if (size > len)
+				goto expansion_too_long;
+			memcpy(bp, arg, size);
+			bp += size;
+			len -= size;
+			s += 2;
+		}
+	}
+	*bp = '\0';
+	return 1;
+
+expansion_too_long:
+	error("expansion of macro \"%s\" is too long", lastmacro->name);
+}
+
 /*
  * Parse an argument list (par0, par1, ...) and creates
  * an array with pointers to all the arguments in the
--- a/cc1/lex.c
+++ b/cc1/lex.c
@@ -11,7 +11,6 @@
 #include "../inc/cc.h"
 #include "cc1.h"
 
-#define INPUTSIZ 120
 
 typedef struct input Input;
 
@@ -32,7 +31,7 @@
 static int safe, eof, incomment;
 static Input *input;
 
-bool
+char *
 addinput(char *fname)
 {
 	Input *ip;
@@ -44,7 +43,7 @@
 
 	if (fname) {
 		if ((fp = fopen(fname, "r")) == NULL)
-			return 0;
+			return NULL;
 		fname = xstrdup(fname);
 	} else if (!input) {
 		fp = stdin;
@@ -63,7 +62,7 @@
 	ip->nline = nline;
 	ip->fp = fp;
 	input = ip;
-	return 1;
+	return input->line;
 }
 
 static void
@@ -386,6 +385,8 @@
 	input->p = p;
 	tok2str();
 	yylval.sym = lookup(lex_ns);
+	if (yylval.sym->ns == NS_CPP && expand(yylval.sym))
+		return 0;
 	if (yylval.sym->token != IDEN)
 		yylval.token = yylval.sym->u.token;
 	return yylval.sym->token;
@@ -511,6 +512,7 @@
 {
 	char c;
 
+repeat:
 	skipspaces();
 	if (eof) {
 		strcpy(yytext, "<EOF>");
@@ -528,6 +530,10 @@
 		yytoken = character();
 	else
 		yytoken = operator();
+
+	if (!yytoken)
+		goto repeat;
+
 	lex_ns = NS_IDEN;
 	return yytoken;
 }