summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--lisc/lisc.h9
-rw-r--r--lisc/parse.c147
2 files changed, 115 insertions, 41 deletions
diff --git a/lisc/lisc.h b/lisc/lisc.h
index 2211183..0ae7c53 100644
--- a/lisc/lisc.h
+++ b/lisc/lisc.h
@@ -75,6 +75,7 @@ enum {
 	RTmp,
 	RCon,
 	RSlot,
+	RTyp,
 	NRef = (1<<14) - 1
 };
 
@@ -83,6 +84,7 @@ enum {
 #define CON(x)   (Ref){RCon, x}
 #define CON_Z    CON(0)          /* reserved zero constant */
 #define SLOT(x)  (Ref){RSlot, x}
+#define TYP(x)   (Ref){RTyp, x}
 
 static inline int req(Ref a, Ref b)
 { return a.type == b.type && a.val == b.val; }
@@ -132,8 +134,13 @@ enum Op {
 	OCopy,
 	NPubOp,
 
+	/* function instructions */
+	OArg = NPubOp,
+	OArgc,
+	OCall,
+
 	/* reserved instructions */
-	ONop = NPubOp,
+	ONop,
 	OAddr,
 	OSwap,
 	OSign,
diff --git a/lisc/parse.c b/lisc/parse.c
index aba1e7b..e23cbb2 100644
--- a/lisc/parse.c
+++ b/lisc/parse.c
@@ -37,6 +37,9 @@ OpDesc opdesc[NOp] = {
 	[OXCmp]   = { "xcmp",   2, 1 },
 	[OXTest]  = { "xtest",  2, 1 },
 	[OAddr]   = { "addr",   1, 0 },
+	[OArg]    = { "arg",    1, 0 },
+	[OArgc]   = { "argc",   1, 0 },
+	[OCall]   = { "call",    1, 0 },
 	[OAlloc]   = { "alloc4",  1, 1 },
 	[OAlloc+1] = { "alloc8",  1, 1 },
 	[OAlloc+2] = { "alloc16", 1, 1 },
@@ -58,6 +61,7 @@ typedef enum {
 
 enum {
 	TXXX = NPubOp,
+	TCall,
 	TPhi,
 	TJmp,
 	TJnz,
@@ -146,6 +150,7 @@ lex()
 		char *str;
 		int tok;
 	} tmap[] = {
+		{ "call", TCall },
 		{ "phi", TPhi },
 		{ "jmp", TJmp },
 		{ "jnz", TJnz },
@@ -278,6 +283,29 @@ nextnl()
 	return t;
 }
 
+static void
+expect(int t)
+{
+	static char *names[] = {
+		[TLbl] = "label",
+		[TComma] = ",",
+		[TEq] = "=",
+		[TNL] = "newline",
+		[TEOF] = 0,
+	};
+	char buf[128], *s1, *s2;
+	int t1;
+
+	t1 = next();
+	if (t == t1)
+		return;
+	s1 = names[t] ? names[t] : "??";
+	s2 = names[t1] ? names[t1] : "??";
+	snprintf(buf, sizeof buf,
+		"%s expected (got %s instead)", s1, s2);
+	err(buf);
+}
+
 Blk *
 blocka()
 {
@@ -338,6 +366,54 @@ parseref()
 	}
 }
 
+static int
+parsecls(char *ty)
+{
+	switch (next()) {
+	default:
+		err("invalid class specifier");
+	case TW:
+		return 0;
+	case TL:
+		return 1;
+	case TTyp:
+		strcpy(ty, tokval.str);
+		return 2;
+	}
+}
+
+static void
+parseargl()
+{
+	char ty[NString];
+	int w, t;
+	Ref r;
+
+	expect(TLParen);
+	if (peek() == TRParen) {
+		next();
+		return;
+	}
+	for (;;) {
+		if (curi - insb >= NIns)
+			err("too many instructions (1)");
+		w = parsecls(ty);
+		r = parseref();
+		if (req(r, R))
+			err("invalid reference argument");
+		if (w == 2)
+			*curi = (Ins){OArgc, 0, R, {TYP(0), r}};
+		else
+			*curi = (Ins){OArg, w, R, {r, R}};
+		curi++;
+		t = next();
+		if (t == TRParen)
+			break;
+		if (t != TComma)
+			err(", or ) expected");
+	}
+}
+
 static Blk *
 findblk(char *name)
 {
@@ -357,29 +433,6 @@ findblk(char *name)
 }
 
 static void
-expect(int t)
-{
-	static char *names[] = {
-		[TLbl] = "label",
-		[TComma] = "comma",
-		[TEq] = "=",
-		[TNL] = "newline",
-		[TEOF] = 0,
-	};
-	char buf[128], *s1, *s2;
-	int t1;
-
-	t1 = next();
-	if (t == t1)
-		return;
-	s1 = names[t] ? names[t] : "??";
-	s2 = names[t1] ? names[t1] : "??";
-	snprintf(buf, sizeof buf,
-		"%s expected (got %s instead)", s1, s2);
-	err(buf);
-}
-
-static void
 closeblk()
 {
 	curb->nins = curi - insb;
@@ -398,6 +451,7 @@ parseline(PState ps)
 	Ref r;
 	Blk *b;
 	int t, op, i, w;
+	char ty[NString];
 
 	t = nextnl();
 	if (ps == PLbl && t != TLbl && t != TRBrace)
@@ -407,6 +461,7 @@ parseline(PState ps)
 		if (OStorel <= t && t <= OStoreb) {
 			/* operations without result */
 			r = R;
+			w = 0;
 			op = t;
 			goto DoOp;
 		}
@@ -457,16 +512,7 @@ parseline(PState ps)
 	}
 	r = tmpref(tokval.str, 0);
 	expect(TEq);
-	switch (next()) {
-	case TW:
-		w = 0;
-		break;
-	case TL:
-		w = 1;
-		break;
-	default:
-		err("class expected after =");
-	}
+	w = parsecls(ty);
 	op = next();
 DoOp:
 	if (op == TPhi) {
@@ -474,6 +520,21 @@ DoOp:
 			err("unexpected phi instruction");
 		op = -1;
 	}
+	if (op == TCall) {
+		/* do eet! */
+		arg[0] = parseref();
+		parseargl();
+		expect(TNL);
+		op = OCall;
+		if (w == 2) {
+			w = 0;
+			arg[1] = TYP(0);
+		} else
+			arg[1] = R;
+		goto Ins;
+	}
+	if (w == 2)
+		err("size class must be w or l");
 	if (op >= NPubOp)
 		err("invalid instruction");
 	i = 0;
@@ -493,15 +554,16 @@ DoOp:
 			if (t == TNL)
 				break;
 			if (t != TComma)
-				err("comma or end of line expected");
+				err(", or end of line expected");
 			next();
 		}
 	next();
 	if (op != -1 && i != opdesc[op].arity)
 		err("invalid arity");
 	if (op != -1) {
+	Ins:
 		if (curi - insb >= NIns)
-			err("too many instructions in block");
+			err("too many instructions (2)");
 		curi->op = op;
 		curi->wide = w;
 		curi->to = r;
@@ -708,6 +770,9 @@ printref(Ref r, Fn *fn, FILE *f)
 	case RSlot:
 		fprintf(f, "S%d", r.val);
 		break;
+	case RTyp:
+		fprintf(f, ":%d", r.val);
+		break;
 	}
 }
 
@@ -748,17 +813,19 @@ printfn(Fn *fn, FILE *f)
 			if (!req(i->to, R)) {
 				printref(i->to, fn, f);
 				fprintf(f, " =");
+				fprintf(f, i->wide ? "l " : "w ");
 			}
 			assert(opdesc[i->op].name);
-			if (OStorel > i->op || i->op > OStoreb)
-				fprintf(f, i->wide ? "l " : "w ");
 			fprintf(f, "%s", opdesc[i->op].name);
-			n = opdesc[i->op].arity;
-			if (n > 0) {
+			if (req(i->to, R))
+			if (i->op < OStorel || i->op > OStoreb)
+			if (i->op != OArgc)
+				fprintf(f, i->wide ? "l" : "w");
+			if (!req(i->arg[0], R)) {
 				fprintf(f, " ");
 				printref(i->arg[0], fn, f);
 			}
-			if (n > 1) {
+			if (!req(i->arg[1], R)) {
 				fprintf(f, ", ");
 				printref(i->arg[1], fn, f);
 			}