shithub: scc

Download patch

ref: b8e51de07999a695f7e66bcfa1b270e61896dd5d
parent: 34f9e3e9ce1c23c5d0c4d8bf5a9728495604d629
parent: d3cf9edc145d0c14209dd4bb1339778a5c4436fb
author: Roberto E. Vargas Caballero <[email protected]>
date: Tue Oct 6 05:13:15 EDT 2015

Merge remote-tracking branch 'origin/master'

--- a/cc1/Makefile
+++ b/cc1/Makefile
@@ -12,6 +12,9 @@
 cc1: $(OBJS) ../lib/libcc.a
 	$(CC) $(LDFLAGS) $(OBJS) ../lib/libcc.a -o $@
 
+cpp: cc1
+	ln -f cc1 cpp
+
 test:
 	cd tests && ./chktest.sh
 
--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -46,6 +46,10 @@
 	} min;
 };
 
+struct keyword {
+	char *str;
+	unsigned char token, value;
+};
 
 struct type {
 	unsigned char op;           /* type builder operator */
@@ -345,9 +349,9 @@
 extern Symbol *install(int ns, Symbol *sym);
 extern Symbol *newsym(int ns);
 extern void pushctx(void), popctx(void);
-extern void ikeywords(void);
-extern void delmacro(Symbol *sym);
+extern void killsym(Symbol *sym);
 extern Symbol *newlabel(void);
+extern void keywords(struct keyword *key, int ns);
 
 /* stmt.c */
 extern void compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch);
@@ -396,6 +400,8 @@
 extern bool cpp(void);
 extern bool expand(char *begin, Symbol *sym);
 extern void incdir(char *dir);
+extern void outcpp(void);
+extern Symbol *defmacro(char *s);
 
 /*
  * Definition of global variables
@@ -407,7 +413,7 @@
 extern int cppoff, disexpand;
 extern unsigned cppctx;
 extern Input *input;
-extern int lexmode, namespace;
+extern int lexmode, namespace, onlycpp;
 extern unsigned curctx;
 extern Symbol *curfun, *zero, *one;
 
--- a/cc1/cpp.c
+++ b/cc1/cpp.c
@@ -25,10 +25,23 @@
 unsigned cppctx;
 int disexpand;
 
-static Symbol *
+Symbol *
 defmacro(char *s)
 {
-	return install(NS_CPP, lookup(NS_CPP, s));
+	char *p, *q;
+	Symbol *sym;
+	size_t len;
+
+	if ((p = strchr(s, '=')) != NULL) {
+		*p++='\0';
+		len = strlen(p);
+		q = xmalloc(len+4);
+		sprintf(q, "-1#%s", p);
+		p = q;
+	}
+	sym = install(NS_CPP, lookup(NS_CPP, s));
+	sym->u.s = p;
+	return sym;
 }
 
 void
@@ -37,12 +50,27 @@
 	static char sdate[17], stime[14];
 	struct tm *tm;
 	time_t t;
-	char **bp, *list[] = {
+	static char **bp, *list[] = {
 		"__STDC__",
 		"__STDC_HOSTED__",
 		"__SCC__",
 		NULL
 	};
+	static struct keyword keys[] = {
+		{"define", DEFINE, DEFINE},
+		{"include", INCLUDE, INCLUDE},
+		{"line", LINE, LINE},
+		{"ifdef", IFDEF, IFDEF},
+		{"if", IF, IF},
+		{"elif", ELIF, ELIF},
+		{"else", ELSE, ELSE},
+		{"ifndef", IFNDEF, IFNDEF},
+		{"endif", ENDIF, ENDIF},
+		{"undef", UNDEF, UNDEF},
+		{"pragma", PRAGMA, PRAGMA},
+		{"error", ERROR, ERROR},
+		{NULL, 0, 0}
+	};
 
 	t = time(NULL);
 	tm = localtime(&t);
@@ -57,6 +85,7 @@
 
 	for (bp = list; *bp; ++bp)
 		defmacro(*bp)->u.s = "-1#1";
+	keywords(keys, NS_CPPCLAUSES);
 }
 
 static void
@@ -145,21 +174,39 @@
 	return 1;
 }
 
+/* FIXME: characters in the definition break the macro definition */
 static size_t
 copymacro(char *buffer, char *s, size_t bufsiz, char *arglist[])
 {
-	char prevc, c, *arg, *bp = buffer;
+	char prevc, c, *p, *arg, *bp = buffer;
+	size_t size;
 
 	for (prevc = '\0'; c = *s; prevc = c, ++s) {
 		if (c != '@') {
-			if (c == '#')
+			switch (c) {
+			case '$':
+				while (bp[-1] == ' ')
+					--bp, ++bufsiz;
+				while (s[1] == ' ')
+					++s;
+			case '#':
 				continue;
+			case '\"':
+				for (p = s; *++s != '"'; )
+					/* nothing */;
+				size = s - p + 1;
+				if (size > bufsiz)
+					goto expansion_too_long;
+				memcpy(bp, p, size);
+				bufsiz -= size;
+				bp += size;
+				continue;
+			// case '\'';
+			}
 			if (bufsiz-- == 0)
 				goto expansion_too_long;
 			*bp++ = c;
 		} else {
-			size_t size;
-
 			if (prevc == '#')
 				bufsiz -= 2;
 			arg = arglist[atoi(++s)];
@@ -194,7 +241,9 @@
 	char *arglist[NR_MACROARG], arguments[INPUTSIZ], buffer[BUFSIZE];
 
 	macroname = sym->name;
-	if (!(sym->flags & ISDECLARED)) {
+	if ((sym->flags & ISDECLARED) == 0) {
+		if (namespace == NS_CPP && !strcmp(sym->name, "defined"))
+			return 0;  /* we found a 'defined in an #if */
 		/*
 		 * This case happens in #if were macro not defined must
 		 * be expanded to 0
@@ -216,12 +265,12 @@
 	if (!parsepars(arguments, arglist, atoi(s)))
 		return 0;
 	for (n = 0; n < atoi(s); ++n)
-		DBG("MACRO par%d:%s\n", n, arglist[n]);
+		DBG("MACRO par%d:%s", n, arglist[n]);
 
 	elen = copymacro(buffer, s+3, INPUTSIZ-1, arglist);
 
 substitute:
-	DBG("MACRO '%s' expanded to :'%s'\n", macroname, buffer);
+	DBG("MACRO '%s' expanded to :'%s'", macroname, buffer);
 	rlen = strlen(input->p);      /* rigth length */
 	llen = begin - input->line;   /* left length */
 	ilen = input->p - begin;      /* invocation length */
@@ -241,7 +290,7 @@
 	input->p = input->begin = begin;
 
 	if (!(sym->flags & ISDECLARED))
-		delmacro(sym);
+		killsym(sym);
 
 	return 1;
 }
@@ -285,6 +334,11 @@
 	size_t len;
 	int prevc = 0, ispar;
 
+	if (yytoken == '$') {
+		cpperror("'##' cannot appear at either end of a macro expansion");
+		return 0;
+	}
+
 	for (;;) {
 		ispar = 0;
 		if (yytoken == IDEN && nargs >= 0) {
@@ -308,10 +362,15 @@
 			cpperror("too long macro");
 			return 0;
 		}
-		memcpy(bp, yytext, len);
-		bp += len;
-		bufsiz -= len;
-		if ((prevc = yytoken) != '#')
+		if (yytoken == '$') {
+			*bp++ = '$';
+			 --bufsiz;
+		} else {
+			memcpy(bp, yytext, len);
+			bp += len;
+			bufsiz -= len;
+		}
+		if ((prevc  = yytoken) != '#')
 			*bp++ = ' ';
 		next();
 	}
@@ -342,7 +401,7 @@
 		free(sym->u.s);
 	} else {
 		sym = install(NS_CPP, sym);
-		sym->flags |= ISDECLARED;
+		sym->flags |= ISDECLARED|ISSTRING;
 	}
 
 	namespace = NS_IDEN;       /* Avoid polution in NS_CPP */
@@ -353,11 +412,11 @@
 	if (!getdefs(args, n, buff+3, LINESIZ-3))
 		goto delete;
 	sym->u.s = xstrdup(buff);
-	DBG("MACRO '%s' defined as '%s'\n", sym->name, buff);
+	DBG("MACRO '%s' defined as '%s'", sym->name, buff);
 	return;
 
 delete:
-	delmacro(sym);
+	killsym(sym);
 }
 
 void
@@ -531,7 +590,7 @@
 		next();
 		status = (sym->flags & ISDECLARED) != 0;
 		if (!status)
-			delmacro(sym);
+			killsym(sym);
 	} else {
 		/* TODO: catch recovery here */
 		if ((expr = iconstexpr()) == NULL) {
@@ -589,6 +648,7 @@
 elif(void)
 {
 	elseclause();
+	--cppctx;
 	cppif();
 }
 
@@ -614,7 +674,7 @@
 		error("no macro name given in #undef directive");
 		return;
 	}
-	delmacro(yylval.sym);
+	killsym(yylval.sym);
 	next();
 }
 
@@ -670,3 +730,47 @@
 
 	return 1;
 }
+
+void
+outcpp(void)
+{
+	char c, *s, *t;
+
+	for (next(); yytoken != EOFTOK; next()) {
+		if (yytoken != CONSTANT || *yytext != '"') {
+			printf("%s ", yytext);
+			continue;
+		}
+		for (s = yylval.sym->u.s; c = *s; ++s) {
+			switch (c) {
+			case '\n':
+				t = "\\n";
+				goto print_str;
+			case '\v':
+				t = "\\v";
+				goto print_str;
+			case '\b':
+				t = "\\b";
+				goto print_str;
+			case '\t':
+				t = "\\t";
+				goto print_str;
+			case '\a':
+				t = "\\a";
+			print_str:
+				fputs(t, stdout);
+				break;
+			case '\\':
+				putchar('\\');
+			default:
+				if (!isprint(c))
+					printf("\\x%x", c);
+				else
+					putchar(c);
+				break;
+			}
+		}
+	}
+	putchar('\n');
+}
+
--- a/cc1/expr.c
+++ b/cc1/expr.c
@@ -496,6 +496,32 @@
 	}
 }
 
+static Symbol *
+notdefined(Symbol *sym)
+{
+	int isdef;
+
+	if (namespace == NS_CPP && !strcmp(sym->name, "defined")) {
+		disexpand = 1;
+		next();
+		expect('(');
+		sym = yylval.sym;
+		expect(IDEN);
+		expect(')');
+
+		isdef = (sym->flags & ISDECLARED) != 0;
+		sym = newsym(NS_IDEN);
+		sym->type = inttype;
+		sym->flags |= ISCONSTANT;
+		sym->u.i = isdef;
+		disexpand = 0;
+		return sym;
+	}
+	errorp("'%s' undeclared", yytext);
+	sym->type = inttype;
+	return install(sym->ns, yylval.sym);
+}
+
 /*************************************************************
  * grammar functions                                         *
  *************************************************************/
@@ -505,17 +531,18 @@
 	Node *np;
 	Symbol *sym;
 
+	sym = yylval.sym;
 	switch (yytoken) {
 	case CONSTANT:
-		np = constnode(yylval.sym);
+		np = constnode(sym);
 		next();
 		break;
 	case IDEN:
-		sym = yylval.sym;
-		if ((sym->flags & ISDECLARED) == 0) {
-			errorp("'%s' undeclared", yytext);
-			sym->type = inttype;
-			install(sym->ns, yylval.sym);
+		if ((sym->flags & ISDECLARED) == 0)
+			sym = notdefined(sym);
+		if (sym->flags & ISCONSTANT) {
+			np = constnode(sym);
+			break;
 		}
 		sym->flags |= ISUSED;
 		np = varnode(sym);
@@ -566,8 +593,6 @@
 					arg = convert(arg, doubletype, 1);
 				break;
 			}
-			if (arg->type->op == INT)
-				arg = promote(arg);
 			par = node(OPAR, arg->type, par, arg);
 			continue;
 		}
--- a/cc1/fold.c
+++ b/cc1/fold.c
@@ -480,6 +480,11 @@
 	return NULL;
 }
 
+/*
+ * TODO: transform simplify in a recursivity
+ * function, because we are losing optimization
+ * chances
+ */
 Node *
 simplify(int op, Type *tp, Node *lp, Node *rp)
 {
--- a/cc1/lex.c
+++ b/cc1/lex.c
@@ -39,6 +39,44 @@
 void
 ilex(char *fname)
 {
+	static struct keyword keys[] = {
+		{"auto", SCLASS, AUTO},
+		{"break", BREAK, BREAK},
+		{"_Bool", TYPE, BOOL},
+		{"case", CASE, CASE},
+		{"char", TYPE, CHAR},
+		{"const", TQUALIFIER, CONST},
+		{"continue", CONTINUE, CONTINUE},
+		{"default", DEFAULT, DEFAULT},
+		{"do", DO, DO},
+		{"double", TYPE, DOUBLE},
+		{"else", ELSE, ELSE},
+		{"enum", TYPE, ENUM},
+		{"extern", SCLASS, EXTERN},
+		{"float", TYPE, FLOAT},
+		{"for", FOR, FOR},
+		{"goto", GOTO, GOTO},
+		{"if", IF, IF},
+		{"inline", TQUALIFIER, INLINE},
+		{"int", TYPE, INT},
+		{"long", TYPE, LONG},
+		{"register", SCLASS, REGISTER},
+		{"restrict", TQUALIFIER, RESTRICT},
+		{"return", RETURN, RETURN},
+		{"short", TYPE, SHORT},
+		{"signed", TYPE, SIGNED},
+		{"sizeof", SIZEOF, SIZEOF},
+		{"static", SCLASS, STATIC},
+		{"struct", TYPE, STRUCT},
+		{"switch", SWITCH, SWITCH},
+		{"typedef", SCLASS, TYPEDEF},
+		{"union", TYPE, UNION},
+		{"unsigned", TYPE, UNSIGNED},
+		{"void", TYPE, VOID},
+		{"volatile", TQUALIFIER, VOLATILE},
+		{"while", WHILE, WHILE},
+		{NULL, 0, 0},
+	};
 	FILE *fp;
 
 	if (!fname) {
@@ -52,6 +90,7 @@
 	}
 	allocinput(fname, fp);
 	*input->begin = '\0';
+	keywords(keys, NS_KEYWORD);
 }
 
 bool
@@ -176,6 +215,10 @@
 bool
 moreinput(void)
 {
+	static char file[FILENAME_MAX];
+	static unsigned nline;
+	char *s;
+
 repeat:
 	if (!readline())
 		return 0;
@@ -187,6 +230,19 @@
 		goto repeat;
 	}
 
+	if (onlycpp) {
+		putchar('\n');
+		if (strcmp(file, input->fname)) {
+			strcpy(file, input->fname);
+			s = "#line %u %s\n";
+		} else if (nline+1 != input->nline) {
+			s = "#line %u\n";
+		} else {
+			s = "";
+		}
+		nline = input->nline;
+		printf(s, nline, file);
+	}
 	input->begin = input->p;
 	return 1;
 }
@@ -525,6 +581,7 @@
 	case '*': t = follow('=', MUL_EQ, '*'); break;
 	case '/': t = follow('=', DIV_EQ, '/'); break;
 	case '!': t = follow('=', NE, '!'); break;
+	case '#': t = follow('#', '$', '#'); break;
 	case '-': t = minus(); break;
 	case '+': t = plus(); break;
 	case '.': t = dot(); break;
@@ -576,7 +633,7 @@
 		yytoken = operator();
 
 exit:
-	DBG("TOKEN %s\n", yytext);
+	DBG("TOKEN %s", yytext);
 	return yytoken;
 }
 
--- a/cc1/main.c
+++ b/cc1/main.c
@@ -12,8 +12,8 @@
 int warnings;
 jmp_buf recover;
 
-static char *output;
-static int onlycpp;
+static char *output, *arg0;
+int onlycpp;
 
 static void
 clean(void)
@@ -27,7 +27,9 @@
 static void
 usage(void)
 {
-	fputs("usage: cc1 [-w] [-o output] [input]\n", stderr);
+	fprintf(stderr,
+	        "usage: %s [-E] [-Dmacro[=value]] [-Idir] [-w] [-d] [-o output] [input]\n",
+	        arg0);
 	exit(1);
 }
 
@@ -38,6 +40,10 @@
 
 	atexit(clean);
 
+	arg0 = (cp = strrchr(*argv, '/')) ? cp+1 : *argv;
+	if (!strcmp(arg0, "cpp"))
+		onlycpp = 1;
+
 	for (;;) {
 	nextiter:
 		--argc, ++argv;
@@ -51,6 +57,12 @@
 			case 'E':
 				onlycpp = 1;
 				break;
+			case 'D':
+				defmacro(cp+1);
+				goto nextiter;
+			case 'd':
+				DBGON();
+				break;
 			case 'I':
 				incdir(cp+1);
 				goto nextiter;
@@ -72,12 +84,10 @@
 		usage();
 
 	icpp();
-	ikeywords();
 	ilex(*argv);
 
 	if (onlycpp) {
-		for (next(); yytoken != EOFTOK; next())
-			printf("%s ", yytext);
+		outcpp();
 	} else {
 		for (next(); yytoken != EOFTOK; decl())
 			/* nothing */;
--- a/cc1/symbol.c
+++ b/cc1/symbol.c
@@ -76,7 +76,7 @@
 		error("too much nested blocks");
 }
 
-static void
+void
 killsym(Symbol *sym)
 {
 	short f;
@@ -87,14 +87,14 @@
 		free(sym->u.s);
 	if (sym->ns == NS_TAG)
 		sym->type->defined = 0;
-	if ((name = sym->name) != NULL) {
-		unlinkhash(sym);
+	unlinkhash(sym);
+	if ((name = sym->name) != NULL && sym->ns != NS_CPP) {
 		if ((f & (ISUSED|ISGLOBAL|ISDECLARED)) == ISDECLARED)
 			warn("'%s' defined but not used", name);
 		if ((f & ISDEFINED) == 0 && sym->ns == NS_LABEL)
 			errorp("label '%s' is not defined", name);
-		free(name);
 	}
+	free(name);
 	free(sym);
 }
 
@@ -168,7 +168,6 @@
 {
 	Symbol *p, *prev;
 
-	sym->flags |= ISDECLARED;
 	switch (sym->ns) {
 	case NS_CPP:
 		return sym;
@@ -198,7 +197,6 @@
 	Symbol **h, *p, *prev;
 
 	h = &htab[hash(sym->name)];
-
 	for (prev = p = *h; p; prev = p, p = p->hash) {
 		if (p->ctx <= sym->ctx)
 			break;
@@ -214,6 +212,7 @@
 
 	if (sym->ns != NS_CPP)
 		sym->id = newid();
+	sym->flags |= ISDECLARED;
 	return linksym(sym);
 }
 
@@ -220,10 +219,7 @@
 Symbol *
 newsym(int ns)
 {
-	Symbol *sym;
-
-	sym = linksym(allocsym(ns, NULL));
-	return sym;
+	return linksym(allocsym(ns, NULL));
 }
 
 Symbol *
@@ -253,15 +249,6 @@
 	return allocsym(ns, name);
 }
 
-void
-delmacro(Symbol *sym)
-{
-	unlinkhash(sym);
-	free(sym->name);
-	free(sym->u.s);
-	free(sym);
-}
-
 Symbol *
 nextsym(Symbol *sym, int ns)
 {
@@ -296,77 +283,14 @@
 }
 
 void
-ikeywords(void)
+keywords(struct keyword *key, int ns)
 {
-	static struct {
-		char *str;
-		unsigned char token, value;
-	} *bp, keywords[] = {
-		{"auto", SCLASS, AUTO},
-		{"break", BREAK, BREAK},
-		{"_Bool", TYPE, BOOL},
-		{"case", CASE, CASE},
-		{"char", TYPE, CHAR},
-		{"const", TQUALIFIER, CONST},
-		{"continue", CONTINUE, CONTINUE},
-		{"default", DEFAULT, DEFAULT},
-		{"do", DO, DO},
-		{"double", TYPE, DOUBLE},
-		{"else", ELSE, ELSE},
-		{"enum", TYPE, ENUM},
-		{"extern", SCLASS, EXTERN},
-		{"float", TYPE, FLOAT},
-		{"for", FOR, FOR},
-		{"goto", GOTO, GOTO},
-		{"if", IF, IF},
-		{"inline", TQUALIFIER, INLINE},
-		{"int", TYPE, INT},
-		{"long", TYPE, LONG},
-		{"register", SCLASS, REGISTER},
-		{"restrict", TQUALIFIER, RESTRICT},
-		{"return", RETURN, RETURN},
-		{"short", TYPE, SHORT},
-		{"signed", TYPE, SIGNED},
-		{"sizeof", SIZEOF, SIZEOF},
-		{"static", SCLASS, STATIC},
-		{"struct", TYPE, STRUCT},
-		{"switch", SWITCH, SWITCH},
-		{"typedef", SCLASS, TYPEDEF},
-		{"union", TYPE, UNION},
-		{"unsigned", TYPE, UNSIGNED},
-		{"void", TYPE, VOID},
-		{"volatile", TQUALIFIER, VOLATILE},
-		{"while", WHILE, WHILE},
-		{NULL, 0, 0},
-	}, cppclauses[] = {
-		{"define", DEFINE, DEFINE},
-		{"include", INCLUDE, INCLUDE},
-		{"line", LINE, LINE},
-		{"ifdef", IFDEF, IFDEF},
-		{"if", IF, IF},
-		{"elif", ELIF, ELIF},
-		{"else", ELSE, ELSE},
-		{"ifndef", IFNDEF, IFNDEF},
-		{"endif", ENDIF, ENDIF},
-		{"undef", UNDEF, UNDEF},
-		{"pragma", PRAGMA, PRAGMA},
-		{"error", ERROR, ERROR},
-		{NULL, 0, 0}
-	}, *list[] = {
-		keywords,
-		cppclauses,
-		NULL
-	}, **lp;
 	Symbol *sym;
-	int ns = NS_KEYWORD;
 
-	for (lp = list; *lp; ++lp) {
-		for (bp = *lp; bp->str; ++bp) {
-			sym = linkhash(allocsym(ns, bp->str));
-			sym->token = bp->token;
-			sym->u.token = bp->value;
-		}
-		ns = NS_CPPCLAUSES;
+	for ( ; key->str; ++key) {
+		sym = linkhash(allocsym(ns, key->str));
+		sym->token = key->token;
+		sym->u.token = key->value;
 	}
 	/*
 	 * Remove all the predefined symbols from * the symbol list. It
--- /dev/null
+++ b/cc1/tests/test031.c
@@ -1,0 +1,33 @@
+
+/*
+name: TEST031
+description: Test concatenation in preprocessor
+output:
+F5	I
+G6	F5	main
+{
+\
+A7	I	foo
+A8	I	bar
+A9	I	foobar
+	A9	A7	A8	+I	:I
+	A9	A7	A8	+I	:I
+	r	#I0
+}
+*/
+
+#define CAT(x,y) x ## y
+#define XCAT(x,y) CAT(x,y)
+#define FOO foo
+#define BAR bar
+
+int
+main(void)
+{
+	int foo, bar, foobar;
+
+	CAT(foo,bar) = foo + bar;
+	XCAT(FOO,BAR) = foo + bar;
+	return 0;
+}
+
--- /dev/null
+++ b/cc1/tests/test032.c
@@ -1,0 +1,25 @@
+
+/*
+name: TEST032
+description: test special characters @ and $ in macro definitions
+output:
+F3	I
+G4	F3	main
+{
+\
+A6	P	p
+	A6	"54686973206973206120737472696E672024206F722023206F72202323616E64206974206973206F6B2021	'P	:P
+	r	A6	#P0	!I
+}
+*/
+
+#define M1(x) "This is a string $ or # or ##" ## #x
+
+int
+main(void)
+{
+	char *p = M1(and it is ok!);
+
+	return p != 0;
+}
+
--- /dev/null
+++ b/cc1/tests/test033.c
@@ -1,0 +1,17 @@
+/*
+name: TEST033
+description: test for #if defined()
+output:
+G1	I	c
+*/
+
+#if defined(FOO)
+int a;
+#elif !defined(FOO) && defined(BAR)
+int b;
+#elif !defined(FOO) && !defined(BAR)
+int c;
+#else
+int d;
+#endif
+
--- a/cc1/tests/update.sh
+++ b/cc1/tests/update.sh
@@ -1,8 +1,26 @@
 #!/bin/sh
 
+update()
+{
+	(echo '/^output/+;/^\*\//-c'
+	../cc1 -I./ -w $1 2>&1
+	printf ".\nw\n") | ed -s $1
+}
+
+
+case $# in
+1)
+	update $1
+	exit
+	;;
+*)
+	echo "usage: update.sh [test]" >&2
+	exit 1
+	;;
+esac
+
+
 for i in *.c
 do
-	(echo '/^output/+;/^\*\//-c'
-	../cc1 -w $i 2>&1
-	printf ".\nw\n") | ed -s $i
+	update $i
 done
--- a/inc/cc.h
+++ b/inc/cc.h
@@ -8,9 +8,12 @@
 #endif
 
 #ifndef NDEBUG
-#define DBG(...) fprintf(stderr, __VA_ARGS__)
+extern int debug;
+#define DBG(fmt, ...) dbg(fmt, __VA_ARGS__)
+#define DBGON() (debug = 1)
 #else
 #define DBG(...)
+#define DBGON()
 #endif
 
 #define L_INT8      'C'
@@ -39,8 +42,8 @@
 #define L_EXTERN    'X'
 
 extern void die(const char *fmt, ...);
+extern void dbg(const char *fmt, ...);
 extern void *xmalloc(size_t size);
 extern void *xcalloc(size_t nmemb, size_t size);
 extern char *xstrdup(const char *s);
 extern void *xrealloc(void *buff, register size_t size);
-
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,6 +1,6 @@
 include ../config.mk
 
-OBJS = die.o xcalloc.o xmalloc.o xrealloc.o xstrdup.o
+OBJS = die.o xcalloc.o xmalloc.o xrealloc.o xstrdup.o debug.o
 
 all: libcc.a
 
--- /dev/null
+++ b/lib/debug.c
@@ -1,0 +1,20 @@
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "../inc/cc.h"
+
+int debug;
+
+void
+dbg(const char *fmt, ...)
+{
+	if (!debug)
+		return;
+	va_list va;
+	va_start(va, fmt);
+	vfprintf(stderr, fmt, va);
+	putc('\n', stderr);
+	va_end(va);
+	return;
+}