changeset 18:c08a947d8f30

deal with macro parameters
author David A. Holland
date Mon, 20 Dec 2010 01:51:47 -0500
parents 76da41da923f
children f9792a9ec704
files directive.c macro.c macro.h main.c utils.c utils.h
diffstat 6 files changed, 183 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/directive.c	Mon Dec 20 01:15:43 2010 -0500
+++ b/directive.c	Mon Dec 20 01:51:47 2010 -0500
@@ -171,8 +171,8 @@
 void
 d_define(struct place *p, struct place *p2, char *line, size_t len)
 {
-	size_t pos;
-	struct place p3;
+	size_t pos, argpos;
+	struct place p3, p4;
 
 	/*
 	 * line may be:
@@ -182,7 +182,8 @@
 
 	pos = strcspn(line, " \t\f\v(");
 	if (line[pos] == '(') {
-		pos++;
+		line[pos++] = '\0';
+		argpos = pos;
 		pos = pos + strcspn(line+pos, "()");
 		if (line[pos] == '(') {
 			p2->column += pos;
@@ -196,25 +197,35 @@
 			complain_fail();
 			return;
 		}
-		pos++;
+		line[pos++] = '\0';
 		if (!strchr(ws, line[pos])) {
 			p2->column += pos;
 			complain(p2, "Trash after macro parameter list");
 			complain_fail();
 			return;
 		}
-		line[pos++] = '\0';
 	} else if (line[pos] == '\0') {
-		/* nothing */
+		argpos = 0;
 	} else {
 		line[pos++] = '\0';
+		argpos = 0;
 	}
 
 	pos += strspn(line+pos, ws);
 
 	p3 = *p2;
-	p3.column += pos;
-	macro_define(p2, line, &p3, line + pos);
+	p3.column += argpos;
+
+	p4 = *p2;
+	p4.column += pos;
+
+	if (argpos) {
+		macro_define_params(p2, line, &p3,
+				    line + argpos, &p4,
+				    line + pos);
+	} else {
+		macro_define_plain(p2, line, &p4, line + pos);
+	}
 }
 
 static
@@ -337,16 +348,6 @@
 static const unsigned numdirectives = HOWMANY(directives);
 
 static
-size_t
-notrailingws(char *buf, size_t len)
-{
-	while (len > 0 && strchr(ws, buf[len-1])) {
-		buf[--len] = '\0';
-	}
-	return len;
-}
-
-static
 void
 directive_gotdirective(struct place *p, char *line, size_t linelen)
 {
--- a/macro.c	Mon Dec 20 01:15:43 2010 -0500
+++ b/macro.c	Mon Dec 20 01:51:47 2010 -0500
@@ -11,6 +11,8 @@
 	struct place expansionplace;
 	unsigned hash;
 	char *name;
+	bool hasparams;
+	struct stringarray params;
 	char *expansion;
 };
 DECLARRAY(macro);
@@ -27,8 +29,8 @@
 
 static
 struct macro *
-macro_create(struct place *p1, struct place *p2, unsigned hash,
-	     const char *name, const char *expansion)
+macro_create(struct place *p1, const char *name, unsigned hash,
+	     struct place *p2, const char *expansion)
 {
 	struct macro *m;
 
@@ -37,6 +39,8 @@
 	m->expansionplace = *p2;
 	m->hash = hash;
 	m->name = dostrdup(name);
+	m->hasparams = false;
+	stringarray_init(&m->params);
 	m->expansion = dostrdup(expansion);
 	return m;
 }
@@ -50,6 +54,41 @@
 	free(m);
 }
 
+static
+bool
+macro_eq(const struct macro *m1, const struct macro *m2)
+{
+	unsigned num1, num2, i;
+	const char *p1, *p2;
+
+	if (strcmp(m1->name, m2->name) != 0) {
+		return false;
+	}
+
+	if (m1->hasparams != m2->hasparams) {
+		return false;
+	}
+
+	if (strcmp(m1->expansion, m2->expansion) != 0) {
+		return false;
+	}
+
+	num1 = stringarray_num(&m1->params);
+	num2 = stringarray_num(&m2->params);
+	if (num1 != num2) {
+		return false;
+	}
+
+	for (i=0; i<num1; i++) {
+		p1 = stringarray_get(&m1->params, i);
+		p2 = stringarray_get(&m2->params, i);
+		if (strcmp(p1, p2) != 0) {
+			return false;
+		}
+	}
+	return true;
+}
+
 ////////////////////////////////////////////////////////////
 // macro table
 
@@ -238,28 +277,104 @@
 ////////////////////////////////////////////////////////////
 // external macro definition interface
 
-void
-macro_define(struct place *p1, const char *macro,
-	     struct place *p2, const char *expansion)
+static
+struct macro *
+macro_define_common_start(struct place *p1, const char *macro,
+			  struct place *p2, const char *expansion)
 {
 	struct macro *m;
 
-	m = macrotable_find(macro, false);
-	if (m != NULL) {
-		if (!strcmp(expansion, m->expansion)) {
-			complain(p1, "Warning: redefinition of %s", macro);
+	if (!is_identifier(macro)) {
+		complain(p1, "Invalid macro name %s", macro);
+		complain_fail();
+	}
+
+	m = macro_create(p1, macro, hashfunc(macro), p2, expansion);
+	return m;
+}
+
+static
+void
+macro_define_common_end(struct macro *m)
+{
+	struct macro *oldm;
+	bool ok;
+
+	oldm = macrotable_find(m->name, false);
+	if (oldm != NULL) {
+		ok = macro_eq(m, oldm);
+		if (ok) {
+			complain(&m->defplace,
+				 "Warning: redefinition of %s", m->name);
 			if (mode.werror) {
 				complain_fail();
 			}
-			return;
+		} else {
+			complain(&m->defplace,
+				 "Redefinition of %s is not identical",
+				 m->name);
+			complain_fail();
 		}
-		complain(p1, "Redefinition of %s is not identical", macro);
-		complain_fail();
+		complain(&oldm->defplace, "Previous definition was here");
+		macro_destroy(m);
 		return;
 	}
+	macrotable_add(m);
+}
 
-	m = macro_create(p1, p2, hashfunc(macro), macro, expansion);
-	macrotable_add(m);
+static
+void
+macro_parse_parameters(struct macro *m, struct place *p, const char *params)
+{
+	size_t len;
+	const char *s;
+	char *param;
+
+	while (params != NULL) {
+		len = strspn(params, ws);
+		params += len;
+		p->column += len;
+		s = strchr(params, ',');
+		if (s) {
+			len = s-params;
+			param = dostrndup(params, len);
+			s++;
+		} else {
+			len = strlen(params);
+			param = dostrndup(params, len);
+		}
+		notrailingws(param, strlen(param));
+		if (!is_identifier(param)) {
+			complain(p, "Invalid macro parameter name %s", param);
+			complain_fail();
+		} else {
+			stringarray_add(&m->params, param, NULL);
+		}
+		params = s;
+		p->column += len;
+	}
+}
+
+void
+macro_define_plain(struct place *p1, const char *macro,
+		   struct place *p2, const char *expansion)
+{
+	struct macro *m;
+
+	m = macro_define_common_start(p1, macro, p2, expansion);
+	macro_define_common_end(m);
+}
+
+void
+macro_define_params(struct place *p1, const char *macro,
+		    struct place *p2, const char *params,
+		    struct place *p3, const char *expansion)
+{
+	struct macro *m;
+
+	m = macro_define_common_start(p1, macro, p3, expansion);
+	macro_parse_parameters(m, p2, params);
+	macro_define_common_end(m);
 }
 
 void
--- a/macro.h	Mon Dec 20 01:15:43 2010 -0500
+++ b/macro.h	Mon Dec 20 01:51:47 2010 -0500
@@ -6,8 +6,11 @@
 void macros_init(void);
 void macros_cleanup(void);
 
-void macro_define(struct place *, const char *macro,
-		  struct place *, const char *expansion);
+void macro_define_plain(struct place *, const char *macro,
+			struct place *, const char *expansion);
+void macro_define_params(struct place *, const char *macro,
+			 struct place *, const char *params,
+			 struct place *, const char *expansion);
 void macro_undef(const char *macro);
 bool macro_isdefined(const char *macro);
 
--- a/main.c	Mon Dec 20 01:15:43 2010 -0500
+++ b/main.c	Mon Dec 20 01:51:47 2010 -0500
@@ -133,8 +133,8 @@
 	for (i=0; i<num; i++) {
 		cm = array_get(&commandline_macros, i);
 		if (cm->expansion != NULL) {
-			macro_define(&cm->where, cm->macro,
-				     &cm->where2, cm->expansion);
+			macro_define_plain(&cm->where, cm->macro,
+					   &cm->where2, cm->expansion);
 		} else {
 			macro_undef(cm->macro);
 		}
@@ -150,7 +150,7 @@
 	struct place p;
 
 	place_setbuiltin(&p, num);
-	macro_define(&p, name, &p, val);
+	macro_define_plain(&p, name, &p, val);
 }
 
 static
--- a/utils.c	Mon Dec 20 01:15:43 2010 -0500
+++ b/utils.c	Mon Dec 20 01:51:47 2010 -0500
@@ -108,3 +108,26 @@
 	return ret;
 }
 
+size_t
+notrailingws(char *buf, size_t len)
+{
+	while (len > 0 && strchr(ws, buf[len-1])) {
+		buf[--len] = '\0';
+	}
+	return len;
+}
+
+bool
+is_identifier(const char *str)
+{
+	size_t len;
+
+	len = strlen(str);
+	if (len != strspn(str, alnum)) {
+		return false;
+	}
+	if (str[0] >= '0' && str[0] <= '9') {
+		return false;
+	}
+	return true;
+}
--- a/utils.h	Mon Dec 20 01:15:43 2010 -0500
+++ b/utils.h	Mon Dec 20 01:51:47 2010 -0500
@@ -16,6 +16,10 @@
 char *dostrdup(const char *s);
 char *dostrdup2(const char *s, const char *t);
 char *dostrdup3(const char *s, const char *t, const char *u);
+char *dostrndup(const char *s, size_t len);
+
+size_t notrailingws(char *buf, size_t len);
+bool is_identifier(const char *str);
 
 /* in place.c */
 void complain(const struct place *, const char *fmt, ...);