shithub: mc

Download patch

ref: 2a76c9fc491ab08492491ddce7fb26d953879791
parent: 16bbf82067cacf44828b5f5023bdd6ec3b80b570
author: Ori Bernstein <ori@eigenstate.org>
date: Thu Feb 25 10:28:14 EST 2016

Fix forward labels in nested blocks.

    Fixes #91

--- a/parse/gram.y
+++ b/parse/gram.y
@@ -19,6 +19,8 @@
 
 
 Stab *curscope;
+static Node **lbls;
+static size_t nlbls;
 
 void yyerror(const char *s);
 int yylex(void);
@@ -783,10 +785,30 @@
 	}
 	;
 
-funclit : Tobrace params Tendln blkbody Tcbrace
-	{$$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($3->loc), $4);}
-	| Tobrace params Tret type Tendln blkbody Tcbrace
-	{$$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $6);}
+funclit : Tobrace params Tendln blkbody Tcbrace {
+		size_t i;
+		Node *fn, *lit;
+
+		$$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($3->loc), $4);
+		fn = $$->lit.fnval;
+		for (i = 0; i < nlbls; i++) {
+			lit = lbls[i]->expr.args[0];
+			putlbl(fn->func.scope, lit->lit.lblname, lbls[i]);
+		}
+		lfree(&lbls, &nlbls);
+	}
+	| Tobrace params Tret type Tendln blkbody Tcbrace {
+		size_t i;
+		Node *fn, *lit;
+
+		$$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $6);
+		fn = $$->lit.fnval;
+		for (i = 0; i < nlbls; i++) {
+			lit = lbls[i]->expr.args[0];
+			putlbl(fn->func.scope, lbls[i]->lit.lblname, lbls[i]);
+		}
+		lfree(&lbls, &nlbls);
+	}
 	;
 
 params  : fnparam {
@@ -981,6 +1003,7 @@
 		genlblstr(buf, sizeof buf, $2->id);
 		$$ = mklbl($2->loc, buf);
 		$$->expr.args[0]->lit.lblname = strdup($2->id);
+		lappend(&lbls, &nlbls, $$);
 	}
 	;
 
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1795,20 +1795,6 @@
 	free(k);
 }
 
-static void addlbl(Inferstate *st, Node *n)
-{
-	Node *lit;
-
-	if (n->type != Nexpr)
-		return;
-	if (exprop(n) != Olit)
-		return;
-	lit = n->expr.args[0];
-	if (lit->lit.littype != Llbl)
-		return;
-	putlbl(curstab(), lit->lit.lblname, n);
-}
-
 static void infernode(Inferstate *st, Node **np, Type *ret, int *sawret)
 {
 	size_t i, nbound;
@@ -1844,8 +1830,6 @@
 		setsuper(n->block.scope, curstab());
 		pushstab(n->block.scope);
 		inferstab(st, n->block.scope);
-		for (i = 0; i < n->block.nstmts; i++)
-			addlbl(st, n->block.stmts[i]);
 		for (i = 0; i < n->block.nstmts; i++)
 			infernode(st, &n->block.stmts[i], ret, sawret);
 		popstab();
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -184,10 +184,7 @@
 
 void putlbl(Stab *st, char *name, Node *lbl)
 {
-	while (st && !st->isfunc)
-		st = st->super;
-	if (!st) 
-		fatal(lbl, "label %s defined outside function\n", name);
+	assert(st && st->isfunc);
 	if (hthas(st->lbl, name))
 		fatal(lbl, "duplicate label %s, first defined on line %d\n", name, lbl->loc.line);
 	htput(st->lbl, name, lbl);