diff directive.c @ 160:d6e6b3940780

Fully implement #line.
author Joerg Sonnenberger <joerg@bec.de>
date Fri, 27 Feb 2015 02:06:49 +0100
parents 1cda505ddc78
children f14f5352956c
line wrap: on
line diff
--- a/directive.c	Fri Feb 27 00:41:46 2015 +0100
+++ b/directive.c	Fri Feb 27 02:06:49 2015 +0100
@@ -175,7 +175,7 @@
 
 static
 void
-d_if(struct place *p, struct place *p2, char *line)
+d_if(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	char *expr;
 	bool val;
@@ -200,7 +200,7 @@
 
 static
 void
-d_ifdef(struct place *p, struct place *p2, char *line)
+d_ifdef(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	uncomment(line);
 	oneword("#ifdef", p2, line);
@@ -209,7 +209,7 @@
 
 static
 void
-d_ifndef(struct place *p, struct place *p2, char *line)
+d_ifndef(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	uncomment(line);
 	oneword("#ifndef", p2, line);
@@ -218,7 +218,7 @@
 
 static
 void
-d_elif(struct place *p, struct place *p2, char *line)
+d_elif(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	char *expr;
 	struct place p3 = *p2;
@@ -247,7 +247,7 @@
 
 static
 void
-d_else(struct place *p, struct place *p2, char *line)
+d_else(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	(void)p2;
 	(void)line;
@@ -264,7 +264,7 @@
 
 static
 void
-d_endif(struct place *p, struct place *p2, char *line)
+d_endif(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	(void)p2;
 	(void)line;
@@ -282,7 +282,7 @@
 
 static
 void
-d_define(struct place *p, struct place *p2, char *line)
+d_define(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	size_t pos, argpos;
 	struct place p3, p4;
@@ -347,7 +347,7 @@
 
 static
 void
-d_undef(struct place *p, struct place *p2, char *line)
+d_undef(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	(void)p;
 
@@ -383,7 +383,7 @@
 
 static
 void
-d_include(struct place *p, struct place *p2, char *line)
+d_include(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	char *text;
 	size_t oldlen;
@@ -412,13 +412,63 @@
 
 static
 void
-d_line(struct place *p, struct place *p2, char *line)
+d_line(struct place *p, struct place *p2, struct place *np, char *line)
 {
-	(void)p2;
-	(void)line;
+	char *text;
+	size_t oldlen;
+	const char *token, *start_lineno, *start_filename;
+	size_t len_lineno, len_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);
 
-	/* XXX */
-	complain(p, "Sorry, no #line yet");
+	token = text;
+	token += strspn(token, ws);
+	start_lineno = token;
+	len_lineno = strspn(token, digits);
+	if (len_lineno == 0) {
+		goto illegal_line;
+	}
+	token += len_lineno;
+	token += strspn(ws, token);
+	if (*token == '"') {
+		++token;
+		start_filename = token;
+		len_filename = strcspn(token, "\"");
+		token += len_filename;
+		if (*token != '"' || len_filename == 0) {
+			goto illegal_line;
+		}
+		++token;
+		token += strspn(token, ws);
+		if (*token != '\0') {
+			goto illegal_line;
+		}
+	} else {
+		len_filename = 0;
+		token += strspn(token, ws);
+		if (*token != '\0') {
+			goto illegal_line;
+		}
+	}
+	np->line = atoi(start_lineno);
+	if (len_filename) {
+		char *filename = dostrndup(start_filename, len_filename);
+		place_setfile(np, filename);
+		dostrfree(filename);
+	}
+	dostrfree(text);
+	return;
+
+illegal_line:
+	complain(p, "Illegal #line directive");
+	complain(p, "Before macro expansion: #include %s", line);
+	complain(p, "After macro expansion: #include %s", text);
+	dostrfree(text);
 }
 
 ////////////////////////////////////////////////////////////
@@ -426,7 +476,7 @@
 
 static
 void
-d_warning(struct place *p, struct place *p2, char *line)
+d_warning(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	char *msg;
 
@@ -440,7 +490,7 @@
 
 static
 void
-d_error(struct place *p, struct place *p2, char *line)
+d_error(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	char *msg;
 
@@ -455,7 +505,7 @@
 
 static
 void
-d_pragma(struct place *p, struct place *p2, char *line)
+d_pragma(struct place *p, struct place *p2, struct place *np, char *line)
 {
 	(void)p2;
 
@@ -469,7 +519,8 @@
 static const struct {
 	const char *name;
 	bool ifskip;
-	void (*func)(struct place *, struct place *, char *line);
+	void (*func)(struct place *, struct place *, struct place *,
+		     char *line);
 } directives[] = {
 	{ "define",  true,  d_define },
 	{ "elif",    false, d_elif },
@@ -489,7 +540,7 @@
 
 static
 void
-directive_gotdirective(struct place *p, char *line)
+directive_gotdirective(struct place *p, struct place *np, char *line)
 {
 	struct place p2;
 	size_t len, skip;
@@ -512,7 +563,7 @@
 			if (len < strlen(line)) {
 				line[len] = '\0';
 			}
-			directives[i].func(p, &p2, line);
+			directives[i].func(p, &p2, np, line);
 			return;
 		}
 	}
@@ -574,7 +625,7 @@
 }
 
 void
-directive_gotline(struct place *p, char *line, size_t len)
+directive_gotline(struct place *p, struct place *np, char *line, size_t len)
 {
 	size_t skip;
 
@@ -588,7 +639,7 @@
 		assert(skip <= len);
 		p->column += skip;
 		assert(line[len] == '\0');
-		directive_gotdirective(p, line+skip /*, length = len-skip */);
+		directive_gotdirective(p, np, line+skip);
 		p->column += len-skip;
 	} else if (ifstate->curtrue) {
 		macro_sendline(p, line, len);