summary refs log tree commit diff
path: root/parse.c
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin@c9x.me>2021-10-18 21:04:10 +0200
committerQuentin Carbonneaux <quentin@c9x.me>2021-10-22 23:53:25 +0200
commitfcdef10dae54d7124aca9ccbefe53baa8e67267d (patch)
tree1215b60f1f3a31d38ee37228dd37bcc4a6a61f99 /parse.c
parent9858a12730717d9c5e5deec4264d7041d75fc947 (diff)
downloadroux-fcdef10dae54d7124aca9ccbefe53baa8e67267d.tar.gz
make variadic args explicit
Some abis, like the riscv one, treat
arguments differently depending on
whether they are variadic or not.
To prepare for the upcomming riscv
target, we change the variadic call
syntax and give meaning to the
location of the '...' marker.

  # new syntax
  %ret =w call $f(w %regular, ..., w %variadic)

By nature of their abis, the change
is backwards compatible for existing
targets.
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c48
1 files changed, 31 insertions, 17 deletions
diff --git a/parse.c b/parse.c
index da88f58..104ca1d 100644
--- a/parse.c
+++ b/parse.c
@@ -450,25 +450,44 @@ parsecls(int *tyn)
 static int
 parserefl(int arg)
 {
-	int k, ty, env, hasenv;
+	int k, ty, env, hasenv, vararg;
 	Ref r;
 
 	hasenv = 0;
+	vararg = 0;
 	expect(Tlparen);
-	while (peek() != Trparen && peek() != Tdots) {
+	while (peek() != Trparen) {
 		if (curi - insb >= NIns)
 			err("too many instructions (1)");
-		env = peek() == Tenv;
-		if (env) {
+		if (!arg && vararg)
+			err("no parameters allowed after '...'");
+		switch (peek()) {
+		case Tdots:
+			if (vararg)
+				err("only one '...' allowed");
+			vararg = 1;
+			if (arg) {
+				*curi = (Ins){.op = Oargv};
+				curi++;
+			}
+			next();
+			goto Next;
+		case Tenv:
+			if (hasenv)
+				err("only one environment allowed");
+			hasenv = 1;
+			env = 1;
 			next();
 			k = Kl;
-		} else
+			break;
+		default:
+			env = 0;
 			k = parsecls(&ty);
+			break;
+		}
 		r = parseref();
 		if (req(r, R))
 			err("invalid argument");
-		if (hasenv && env)
-			err("only one environment allowed");
 		if (!arg && rtype(r) != RTmp)
 			err("invalid function parameter");
 		if (k == 4)
@@ -487,16 +506,13 @@ parserefl(int arg)
 			else
 				*curi = (Ins){Opar, k, r, {R}};
 		curi++;
-		hasenv |= env;
+	Next:
 		if (peek() == Trparen)
 			break;
 		expect(Tcomma);
 	}
-	if (next() == Tdots) {
-		expect(Trparen);
-		return 1;
-	}
-	return 0;
+	expect(Trparen);
+	return vararg;
 }
 
 static Blk *
@@ -621,10 +637,8 @@ DoOp:
 	}
 	if (op == Tcall) {
 		arg[0] = parseref();
-		if (parserefl(1))
-			op = Ovacall;
-		else
-			op = Ocall;
+		parserefl(1);
+		op = Ocall;
 		expect(Tnl);
 		if (k == 4) {
 			k = Kl;