diff macro.c @ 18:c08a947d8f30

deal with macro parameters
author David A. Holland
date Mon, 20 Dec 2010 01:51:47 -0500
parents 76da41da923f
children f9792a9ec704
line wrap: on
line diff
--- 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