changeset 178:0d5b9651b240

Merge Joerg's changes into upstream. (now that they've been thrashed out a bit, include CHANGES entries, etc.)
author David A. Holland
date Fri, 12 Jun 2015 03:05:49 -0400
parents e8f7ae63844f (current diff) 6119608a9817 (diff)
children 8f5b326689da
files
diffstat 13 files changed, 314 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES	Fri Jun 12 03:04:48 2015 -0400
+++ b/CHANGES	Fri Jun 12 03:05:49 2015 -0400
@@ -1,4 +1,8 @@
 pending
+   - Fix output spacing behavior to match gcc when newlines appear in or
+     while looking for macro arguments. Partly from Joerg Sonnenberger.
+   - Implement __FILE__ and __LINE__ macros. Mostly from Joerg Sonnenberger.
+   - Implement #line. Partly from Joerg Sonnenberger.
    - Declare usage() with PF(). From wiz.
 
 release 0.4 (20130713)
--- a/directive.c	Fri Jun 12 03:04:48 2015 -0400
+++ b/directive.c	Fri Jun 12 03:05:49 2015 -0400
@@ -31,6 +31,8 @@
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
+#include <errno.h>
 
 #include "utils.h"
 #include "mode.h"
@@ -415,11 +417,63 @@
 void
 d_line(struct lineplace *lp, struct place *p2, char *line)
 {
-	(void)p2;
-	(void)line;
+	char *text;
+	size_t oldlen;
+	unsigned long val;
+	char *moretext;
+	size_t moretextlen;
+	char *filename;
+
+	text = macroexpand(p2, line, strlen(line), true);
+
+	oldlen = strlen(text);
+	uncomment(text);
+	/* trim to fit, so the malloc debugging won't complain */
+	text = dorealloc(text, oldlen + 1, strlen(text) + 1);
+
+	/*
+	 * What we should have here: either 1234 "file.c",
+	 * or just 1234.
+	 */
 
-	/* XXX */
-	complain(&lp->current, "Sorry, no #line yet");
+	errno = 0;
+	val = strtoul(text, &moretext, 10);
+	if (errno) {
+		complain(&lp->current, "No line number in #line directive");
+		goto fail;
+	}
+#if UINT_MAX < ULONG_MAX
+	if (val > UINT_MAX) {
+		complain(&lp->current,
+			 "Line number in #line directive too large");
+		goto fail;
+	}
+#endif
+	moretext += strspn(moretext, ws);
+	moretextlen = strlen(moretext);
+	lp->current.column += (moretext - text);
+
+	if (moretextlen > 2 &&
+	    moretext[0] == '"' && moretext[moretextlen-1] == '"') {
+		filename = dostrndup(moretext+1, moretextlen-2);
+		place_changefile(&lp->nextline, filename);
+		dostrfree(filename);
+	}
+	else if (moretextlen > 0) {
+		complain(&lp->current,
+			 "Invalid file name in #line directive");
+		goto fail;
+	}
+
+	lp->nextline.line = val;
+	dostrfree(text);
+	return;
+
+fail:
+	complain(&lp->current, "Before macro expansion: #line %s", line);
+	complain(&lp->current, "After macro expansion: #line %s", text);
+	complain_fail();
+	dostrfree(text);
 }
 
 ////////////////////////////////////////////////////////////
@@ -584,7 +638,7 @@
 	}
 
 	/* check if we have a directive line (# exactly in column 0) */
-	if (line[0] == '#') {
+	if (len > 0 && line[0] == '#') {
 		skip = 1 + strspn(line + 1, ws);
 		assert(skip <= len);
 		lp->current.column += skip;
--- a/files.c	Fri Jun 12 03:04:48 2015 -0400
+++ b/files.c	Fri Jun 12 03:05:49 2015 -0400
@@ -274,11 +274,8 @@
 		/* count how many commented-out newlines we swallowed */
 		places.nextline.line += countnls(buf, linestart, lineend);
 
-		/* if the line isn't empty, process it */
-		if (lineend > linestart) {
-			directive_gotline(&places,
-					  buf+linestart, lineend-linestart);
-		}
+		/* process the line (even if it's empty) */
+		directive_gotline(&places, buf+linestart, lineend-linestart);
 
 		linestart = nextlinestart;
 		lineend = findeol(buf, linestart, bufend);
--- a/macro.c	Fri Jun 12 03:04:48 2015 -0400
+++ b/macro.c	Fri Jun 12 03:05:49 2015 -0400
@@ -28,6 +28,7 @@
  */
 
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -38,10 +39,10 @@
 #include "output.h"
 
 struct expansionitem {
-	bool isstring;
+	enum { EI_STRING, EI_PARAM, EI_FILE, EI_LINE } itemtype;
 	union {
-		char *string;
-		unsigned param;
+		char *string;		/* EI_STRING */
+		unsigned param;		/* EI_PARAM */
 	};
 };
 DECLARRAY(expansionitem, static UNUSED);
@@ -76,7 +77,7 @@
 	struct expansionitem *ei;
 
 	ei = domalloc(sizeof(*ei));
-	ei->isstring = true;
+	ei->itemtype = EI_STRING;
 	ei->string = dostrdup(string);
 	return ei;
 }
@@ -88,7 +89,7 @@
 	struct expansionitem *ei;
 
 	ei = domalloc(sizeof(*ei));
-	ei->isstring = true;
+	ei->itemtype = EI_STRING;
 	ei->string = dostrndup(string, len);
 	return ei;
 }
@@ -100,17 +101,45 @@
 	struct expansionitem *ei;
 
 	ei = domalloc(sizeof(*ei));
-	ei->isstring = false;
+	ei->itemtype = EI_PARAM;
 	ei->param = param;
 	return ei;
 }
 
 static
+struct expansionitem *
+expansionitem_create_file(void)
+{
+	struct expansionitem *ei;
+
+	ei = domalloc(sizeof(*ei));
+	ei->itemtype = EI_FILE;
+	return ei;
+}
+
+static
+struct expansionitem *
+expansionitem_create_line(void)
+{
+	struct expansionitem *ei;
+
+	ei = domalloc(sizeof(*ei));
+	ei->itemtype = EI_LINE;
+	return ei;
+}
+
+static
 void
 expansionitem_destroy(struct expansionitem *ei)
 {
-	if (ei->isstring) {
+	switch (ei->itemtype) {
+	    case EI_STRING:
 		dostrfree(ei->string);
+		break;
+	    case EI_PARAM:
+	    case EI_FILE:
+	    case EI_LINE:
+		break;
 	}
 	dofree(ei, sizeof(*ei));
 }
@@ -120,17 +149,23 @@
 expansionitem_eq(const struct expansionitem *ei1,
 		 const struct expansionitem *ei2)
 {
-	if (ei1->isstring != ei2->isstring) {
+	if (ei1->itemtype != ei2->itemtype) {
 		return false;
 	}
-	if (ei1->isstring) {
+	switch (ei1->itemtype) {
+	    case EI_STRING:
 		if (strcmp(ei1->string, ei2->string) != 0) {
 			return false;
 		}
-	} else {
+		break;
+	    case EI_PARAM:
 		if (ei1->param != ei2->param) {
 			return false;
 		}
+		break;
+	    case EI_FILE:
+	    case EI_LINE:
+		break;
 	}
 	return true;
 }
@@ -587,6 +622,24 @@
 }
 
 void
+macro_define_magic(struct place *p, const char *macro)
+{
+	struct macro *m;
+	struct expansionitem *ei;
+
+	m = macro_define_common_start(p, macro, p);
+	if (!strcmp(macro, "__FILE__")) {
+		ei = expansionitem_create_file();
+	}
+	else {
+		assert(!strcmp(macro, "__LINE__"));
+		ei = expansionitem_create_line();
+	}
+	expansionitemarray_add(&m->expansion, ei, NULL);
+	macro_define_common_end(m);
+}
+
+void
 macro_undef(const char *macro)
 {
 	struct macro *m;
@@ -624,7 +677,7 @@
 static struct expstate mainstate;
 
 static void doexpand(struct expstate *es, struct place *p,
-		     char *buf, size_t len);
+		     const char *buf, size_t len);
 
 static
 void
@@ -705,7 +758,7 @@
 
 static
 void
-expand_newarg(struct expstate *es, char *buf, size_t len)
+expand_newarg(struct expstate *es, const char *buf, size_t len)
 {
 	char *text;
 
@@ -715,7 +768,7 @@
 
 static
 void
-expand_appendarg(struct expstate *es, char *buf, size_t len)
+expand_appendarg(struct expstate *es, const char *buf, size_t len)
 {
 	unsigned num;
 	char *text;
@@ -742,6 +795,7 @@
 	char *arg;
 	char *ret;
 	unsigned numargs, numparams;
+	char numbuf[64];
 
 	numargs = stringarray_num(&es->args);
 	numparams = stringarray_num(&es->curmacro->params);
@@ -766,11 +820,20 @@
 	num = expansionitemarray_num(&es->curmacro->expansion);
 	for (i=0; i<num; i++) {
 		ei = expansionitemarray_get(&es->curmacro->expansion, i);
-		if (ei->isstring) {
+		switch (ei->itemtype) {
+		    case EI_STRING:
 			len += strlen(ei->string);
-		} else {
+			break;
+		    case EI_PARAM:
 			arg = stringarray_get(&es->args, ei->param);
 			len += strlen(arg);
+			break;
+		    case EI_FILE:
+			len += strlen(place_getname(p)) + 2;
+			break;
+		    case EI_LINE:
+			len += snprintf(numbuf, sizeof(numbuf), "%u", p->line);
+			break;
 		}
 	}
 
@@ -778,11 +841,23 @@
 	*ret = '\0';
 	for (i=0; i<num; i++) {
 		ei = expansionitemarray_get(&es->curmacro->expansion, i);
-		if (ei->isstring) {
+		switch (ei->itemtype) {
+		    case EI_STRING:
 			strcat(ret, ei->string);
-		} else {
+			break;
+		    case EI_PARAM:
 			arg = stringarray_get(&es->args, ei->param);
 			strcat(ret, arg);
+			break;
+		    case EI_FILE:
+			strcat(ret, "\"");
+			strcat(ret, place_getname(p));
+			strcat(ret, "\"");
+			break;
+		    case EI_LINE:
+			snprintf(numbuf, sizeof(numbuf), "%u", p->line);
+			strcat(ret, numbuf);
+			break;
 		}
 	}
 
@@ -846,7 +921,8 @@
 
 static
 void
-expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_ws(struct expstate *es, struct place *p,
+	      const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -868,7 +944,8 @@
 
 static
 void
-expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_word(struct expstate *es, struct place *p,
+		const char *buf, size_t len)
 {
 	struct macro *m;
 
@@ -917,7 +994,8 @@
 
 static
 void
-expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_lparen(struct expstate *es, struct place *p,
+		  const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -940,7 +1018,8 @@
 
 static
 void
-expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_rparen(struct expstate *es, struct place *p,
+		  const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -975,7 +1054,8 @@
 
 static
 void
-expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_comma(struct expstate *es, struct place *p,
+		 const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -1003,7 +1083,8 @@
 
 static
 void
-expand_got_other(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_other(struct expstate *es, struct place *p,
+		 const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -1055,7 +1136,7 @@
 
 static
 void
-doexpand(struct expstate *es, struct place *p, char *buf, size_t len)
+doexpand(struct expstate *es, struct place *p, const char *buf, size_t len)
 {
 	char *s;
 	size_t x;
@@ -1144,7 +1225,7 @@
 }
 
 char *
-macroexpand(struct place *p, char *buf, size_t len, bool honordefined)
+macroexpand(struct place *p, const char *buf, size_t len, bool honordefined)
 {
 	struct expstate es;
 	char *ret;
@@ -1166,10 +1247,30 @@
 }
 
 void
-macro_sendline(struct place *p, char *buf, size_t len)
+macro_sendline(struct place *p, const char *buf, size_t len)
 {
 	doexpand(&mainstate, p, buf, len);
-	output(p, "\n", 1);
+	switch (mainstate.state) {
+	    case ES_NORMAL:
+		/*
+		 * If we were sent a blank line, don't emit a newline
+		 * for it. This matches the prior behavior of tradcpp.
+		 */
+		if (len > 0) {
+			output(p, "\n", 1);
+		}
+		break;
+	    case ES_WANTLPAREN:
+	    case ES_NOARG:
+	    case ES_HAVEARG:
+		/*
+		 * Apparently to match gcc's -traditional behavior we
+		 * need to emit a space for each newline that appears
+		 * while processing macro args.
+		 */
+		expand_got_ws(&mainstate, p, " ", 1);
+		break;
+	}
 }
 
 void
--- a/macro.h	Fri Jun 12 03:04:48 2015 -0400
+++ b/macro.h	Fri Jun 12 03:05:49 2015 -0400
@@ -40,10 +40,12 @@
 void macro_define_params(struct place *, const char *macro,
 			 struct place *, const char *params,
 			 struct place *, const char *expansion);
+void macro_define_magic(struct place *, const char *macro);
 void macro_undef(const char *macro);
 bool macro_isdefined(const char *macro);
 
-char *macroexpand(struct place *, char *buf, size_t len, bool honordefined);
+char *macroexpand(struct place *, const char *buf, size_t len,
+		  bool honordefined);
 
-void macro_sendline(struct place *, char *buf, size_t len);
+void macro_sendline(struct place *, const char *buf, size_t len);
 void macro_sendeof(struct place *);
--- a/main.c	Fri Jun 12 03:04:48 2015 -0400
+++ b/main.c	Fri Jun 12 03:05:49 2015 -0400
@@ -195,6 +195,16 @@
 
 static
 void
+apply_magic_macro(unsigned num, const char *name)
+{
+	struct place p;
+
+	place_setbuiltin(&p, num);
+	macro_define_magic(&p, name);
+}
+
+static
+void
 apply_builtin_macro(unsigned num, const char *name, const char *val)
 {
 	struct place p;
@@ -209,6 +219,9 @@
 {
 	unsigned n = 1;
 
+	apply_magic_macro(n++, "__FILE__");
+	apply_magic_macro(n++, "__LINE__");
+
 #ifdef CONFIG_OS
 	apply_builtin_macro(n++, CONFIG_OS, "1");
 #endif
--- a/place.c	Fri Jun 12 03:04:48 2015 -0400
+++ b/place.c	Fri Jun 12 03:05:49 2015 -0400
@@ -53,7 +53,7 @@
 static const char *myprogname;
 
 ////////////////////////////////////////////////////////////
-// seenfiles
+// placefiles
 
 static
 struct placefile *
@@ -101,6 +101,58 @@
 	return place->file->dir;
 }
 
+static
+bool
+place_eq(const struct place *a, const struct place *b)
+{
+	if (a->type != b->type) {
+		return false;
+	}
+	if (a->file != b->file) {
+		return false;
+	}
+	if (a->line != b->line || a->column != b->column) {
+		return false;
+	}
+	return true;
+}
+
+static
+struct placefile *
+placefile_find(const struct place *incfrom, const char *name)
+{
+	unsigned i, num;
+	struct placefile *pf;
+
+	num = placefilearray_num(&placefiles);
+	for (i=0; i<num; i++) {
+		pf = placefilearray_get(&placefiles, i);
+		if (place_eq(incfrom, &pf->includedfrom) &&
+		    !strcmp(name, pf->name)) {
+			return pf;
+		}
+	}
+	return NULL;
+}
+
+void
+place_changefile(struct place *p, const char *name)
+{
+	struct placefile *pf;
+
+	assert(p->type == P_FILE);
+	if (!strcmp(name, p->file->name)) {
+		return;
+	}
+	pf = placefile_find(&p->file->includedfrom, name);
+	if (pf == NULL) {
+		pf = placefile_create(&p->file->includedfrom, name,
+				      p->file->fromsystemdir);
+		placefilearray_add(&placefiles, pf, NULL);
+	}
+	p->file = pf;
+}
+
 const struct placefile *
 place_addfile(const struct place *place, const char *file, bool issystem)
 {
@@ -154,7 +206,6 @@
 	p->column = 1;
 }
 
-static
 const char *
 place_getname(const struct place *p)
 {
--- a/place.h	Fri Jun 12 03:04:48 2015 -0400
+++ b/place.h	Fri Jun 12 03:05:49 2015 -0400
@@ -53,8 +53,11 @@
 void place_setcommandline(struct place *p, unsigned word, unsigned column);
 void place_setfilestart(struct place *p, const struct placefile *pf);
 
+const char *place_getname(const struct place *);
 const char *place_getparsedir(const struct place *incplace);
 
+void place_changefile(struct place *p, const char *name);
+
 const struct placefile *place_addfile(const struct place *incplace,
 				      const char *name, bool fromsystemdir);
 
--- a/tests/Makefile	Fri Jun 12 03:04:48 2015 -0400
+++ b/tests/Makefile	Fri Jun 12 03:05:49 2015 -0400
@@ -4,7 +4,7 @@
 TESTS=\
 	t01 t02 t03 t04 t05 t06 t07 t08 t09 t10 t11 t12 t13 t14 t15 t16 \
 	t17 t18 t19 t20 t21 t22 t23 t24 t25 t26 t27 t28 t29 t30 t31 t32 \
-	t33 t34 t35 t36 t37
+	t33 t34 t35 t36 t37 t38 t39
 
 all: run-tests .WAIT show-diffs
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/t38.c	Fri Jun 12 03:05:49 2015 -0400
@@ -0,0 +1,9 @@
+#define m() __FILE__:__LINE__
+__LINE__
+__FILE__
+__LINE__
+m()
+#line 500
+m()
+#line 600 "foo.c"
+m()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/t38.good	Fri Jun 12 03:05:49 2015 -0400
@@ -0,0 +1,6 @@
+2
+"t38.c"
+4
+"t38.c":5
+"t38.c":500
+"foo.c":600
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/t39.c	Fri Jun 12 03:05:49 2015 -0400
@@ -0,0 +1,21 @@
+#define m(a,b) a::b
+=m(123,
+456)
+   ------
+=m
+(123, 456)
+   ------
+=m(
+123, 456)
+   ------
+=m(
+123,
+456
+)
+   ------
+=m(123,
+
+456)
+   ------
+=m(123,
+   456)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/t39.good	Fri Jun 12 03:05:49 2015 -0400
@@ -0,0 +1,11 @@
+=123:: 456
+   ------
+=123:: 456
+   ------
+= 123:: 456
+   ------
+= 123:: 456 
+   ------
+=123::  456
+   ------
+=123::    456