From 4254c013951759048b750518f9cedee580a71492 Mon Sep 17 00:00:00 2001
From: John Brandwood <john.brandwood@telzey.com>
Date: Wed, 20 Nov 2024 11:01:47 -0500
Subject: [PATCH] Add the missing relational, bitwise, logical and remainder
 operators to HuCC's const_expr() parser that Uli added.

Change HuCC to use the const_expr() parser for "case" values.
---
 src/hucc/const.c   |   2 +-
 src/hucc/primary.c | 193 ++++++++++++++++++++++++++++++++++++++-------
 src/hucc/primary.h |   4 +-
 src/hucc/stmt.c    |  12 +--
 src/hucc/sym.c     |   4 +-
 5 files changed, 174 insertions(+), 41 deletions(-)

diff --git a/src/hucc/const.c b/src/hucc/const.c
index f02b89de..324ce932 100644
--- a/src/hucc/const.c
+++ b/src/hucc/const.c
@@ -161,7 +161,7 @@ int get_string_ptr (char typ)
 
 	if (typ == CINT || typ == CUINT)
 		error("incompatible pointer type");
-	if (qstr(&num))
+	if (quoted_str(&num))
 		return (-(num + 1024));
 	else
 		return (-1);
diff --git a/src/hucc/primary.c b/src/hucc/primary.c
index fae91cc7..22c5a742 100644
--- a/src/hucc/primary.c
+++ b/src/hucc/primary.c
@@ -447,9 +447,9 @@ int constant (int *val)
 {
 	if (number(val))
 		immed(T_VALUE, *val);
-	else if (pstr(val))
+	else if (quoted_chr(val))
 		immed(T_VALUE, *val);
-	else if (qstr(val)) {
+	else if (quoted_str(val)) {
 		immed(T_STRING, *val);
 		return (2);
 	}
@@ -507,7 +507,7 @@ bool number (int *val)
 	return (true);
 }
 
-static int parse0 (int *num)
+static int parse_const0 (int *num)
 {
 	if (!const_expr(num, ")", NULL))
 		return (0);
@@ -517,7 +517,7 @@ static int parse0 (int *num)
 	return (1);
 }
 
-static int parse3 (int *num)
+static int parse_const3 (int *num)
 {
 	int num2;
 	struct type_type t;
@@ -549,9 +549,9 @@ static int parse3 (int *num)
 	else
 		op = 0;
 
-	if (!(have_paren && parse0(&num2)) &&
+	if (!(have_paren && parse_const0(&num2)) &&
 	    !number(&num2) &&
-	    !pstr(&num2) &&
+	    !quoted_chr(&num2) &&
 	    !(symname(n) && find_enum(n, &num2)))
 		return (0);
 
@@ -590,11 +590,11 @@ static int parse3 (int *num)
 	return (1);
 }
 
-static int parse5 (int *num)
+static int parse_const5 (int *num)
 {
 	int num1, num2;
 
-	if (!parse3(&num1))
+	if (!parse_const3(&num1))
 		return (0);
 
 	for (;;) {
@@ -603,26 +603,30 @@ static int parse5 (int *num)
 			op = '*';
 		else if (match("/"))
 			op = '/';
+		else if (match("%"))
+			op = '%';
 		else {
 			*num = num1;
 			return (1);
 		}
 
-		if (!parse3(&num2))
+		if (!parse_const3(&num2))
 			return (0);
 
 		if (op == '*')
 			num1 *= num2;
-		else
+		else if (op == '/')
 			num1 /= num2;
+		else
+			num1 %= num2;
 	}
 }
 
-static int parse6 (int *num)
+static int parse_const6 (int *num)
 {
 	int num1, num2;
 
-	if (!parse5(&num1))
+	if (!parse_const5(&num1))
 		return (0);
 
 	for (;;) {
@@ -636,7 +640,7 @@ static int parse6 (int *num)
 			return (1);
 		}
 
-		if (!parse5(&num2))
+		if (!parse_const5(&num2))
 			return (0);
 
 		if (op == '-')
@@ -646,11 +650,11 @@ static int parse6 (int *num)
 	}
 }
 
-static int parse7 (int *num)
+static int parse_const7 (int *num)
 {
 	int num1, num2;
 
-	if (!parse6(&num1))
+	if (!parse_const6(&num1))
 		return (0);
 
 	for (;;) {
@@ -664,7 +668,7 @@ static int parse7 (int *num)
 			return (1);
 		}
 
-		if (!parse6(&num2))
+		if (!parse_const6(&num2))
 			return (0);
 
 		if (op == 'l')
@@ -674,11 +678,45 @@ static int parse7 (int *num)
 	}
 }
 
-static int parse9 (int *num)
+static int parse_const8 (int *num)
 {
 	int num1, num2;
 
-	if (!parse7(&num1))
+	if (!parse_const7(&num1))
+		return (0);
+
+	for (;;) {
+		char op;
+		if (match("<="))
+			op = 0;
+		else if (match(">="))
+			op = 1;
+		else if (match("<"))
+			op = 2;
+		else if (match(">"))
+			op = 3;
+		else {
+			*num = num1;
+			return (1);
+		}
+
+		if (!parse_const7(&num2))
+			return (0);
+
+		switch (op) {
+			case 0: num1 = (num1 <= num2); break;
+			case 1: num1 = (num1 >= num2); break;
+			case 2: num1 = (num1 < num2); break;
+			case 3: num1 = (num1 > num2); break;
+		}
+	}
+}
+
+static int parse_const9 (int *num)
+{
+	int num1, num2;
+
+	if (!parse_const8(&num1))
 		return (0);
 
 	for (;;) {
@@ -692,7 +730,7 @@ static int parse9 (int *num)
 			return (1);
 		}
 
-		if (!parse7(&num2))
+		if (!parse_const8(&num2))
 			return (0);
 
 		if (op == '=')
@@ -702,9 +740,109 @@ static int parse9 (int *num)
 	}
 }
 
+static int parse_const10 (int *num)
+{
+	int num1, num2;
+
+	if (!parse_const9(&num1))
+		return (0);
+
+	for (;;) {
+		if (!match("&")) {
+			*num = num1;
+			return (1);
+		}
+
+		if (!parse_const9(&num2))
+			return (0);
+
+		num1 = num1 & num2;
+	}
+}
+
+static int parse_const11 (int *num)
+{
+	int num1, num2;
+
+	if (!parse_const10(&num1))
+		return (0);
+
+	for (;;) {
+		if (!match("^")) {
+			*num = num1;
+			return (1);
+		}
+
+		if (!parse_const10(&num2))
+			return (0);
+
+		num1 = num1 ^ num2;
+	}
+}
+
+static int parse_const12 (int *num)
+{
+	int num1, num2;
+
+	if (!parse_const11(&num1))
+		return (0);
+
+	for (;;) {
+		if (!match("|")) {
+			*num = num1;
+			return (1);
+		}
+
+		if (!parse_const11(&num2))
+			return (0);
+
+		num1 = num1 | num2;
+	}
+}
+
+static int parse_const13 (int *num)
+{
+	int num1, num2;
+
+	if (!parse_const12(&num1))
+		return (0);
+
+	for (;;) {
+		if (!match("&&")) {
+			*num = num1;
+			return (1);
+		}
+
+		if (!parse_const12(&num2))
+			return (0);
+
+		num1 = num1 && num2;
+	}
+}
+
+static int parse_const14 (int *num)
+{
+	int num1, num2;
+
+	if (!parse_const13(&num1))
+		return (0);
+
+	for (;;) {
+		if (!match("||")) {
+			*num = num1;
+			return (1);
+		}
+
+		if (!parse_const13(&num2))
+			return (0);
+
+		num1 = num1 || num2;
+	}
+}
+
 bool const_expr (int *num, char *end1, char *end2)
 {
-	if (!parse9(num)) {
+	if (!parse_const14(num)) {
 		error("failed to evaluate constant expression");
 		return (false);
 	}
@@ -717,11 +855,10 @@ bool const_expr (int *num, char *end1, char *end2)
 }
 
 /*
- *         pstr
- * pstr parses a character than can eventually be 'double' i.e. like 'a9'
- * returns 0 in case of failure else 1
+ * Test if we have one char enclosed in single quotes
+ * return 0 in case of failure else 1
  */
-bool pstr (int *val)
+bool quoted_chr (int *val)
 {
 	int k;
 	char c;
@@ -739,11 +876,11 @@ bool pstr (int *val)
 }
 
 /*
- *         qstr
- * qstr parses a double quoted string into litq
- * return 0 in case of failure and 1 else
+ * Test if we have string enclosed in double quotes. e.g. "abc".
+ * Load the string into literal pool.
+ * return 0 in case of failure else 1
  */
-bool qstr (int *val)
+bool quoted_str (int *val)
 {
 	char c;
 
diff --git a/src/hucc/primary.h b/src/hucc/primary.h
index 651b02c8..3fdb1368 100644
--- a/src/hucc/primary.h
+++ b/src/hucc/primary.h
@@ -12,8 +12,8 @@ void result (LVALUE lval[], LVALUE lval2[]);
 int constant (int *val);
 bool number (int *val);
 bool const_expr (int *num, char *, char *);
-bool pstr (int *val);
-bool qstr (int *val);
+bool quoted_chr (int *val);
+bool quoted_str (int *val);
 bool const_str (int *val, const char *str);
 bool readqstr (void);
 bool readstr (void);
diff --git a/src/hucc/stmt.c b/src/hucc/stmt.c
index 71a9ba32..a27c1341 100644
--- a/src/hucc/stmt.c
+++ b/src/hucc/stmt.c
@@ -406,15 +406,11 @@ void doswitch (void)
  */
 void docase (void)
 {
-	int val;
-	char n[NAMESIZE];
-
-	val = 0;
+	int val = 0;
 	if (readswitch()) {
-		if (!number(&val))
-			if (!pstr(&val))
-				if (!(symname(n) && find_enum(n, &val)))
-					error("bad case label");
+		if (!const_expr(&val, ":", NULL)) {
+			error("case label must be constant");
+		}
 		addcase(val);
 		if (!match(":"))
 			error("missing colon");
diff --git a/src/hucc/sym.c b/src/hucc/sym.c
index 4e2ae5c9..6bb216b7 100644
--- a/src/hucc/sym.c
+++ b/src/hucc/sym.c
@@ -43,7 +43,7 @@ static int init (char *symbol_name, int type, int identity, int *dim, TAG_SYMBOL
 		return (0);
 	}
 
-	if (qstr(&value)) {
+	if (quoted_str(&value)) {
 		if ((identity == VARIABLE) || (type != CCHAR && type != CUCHAR))
 			error("found string: must assign to char pointer or array");	/* XXX: make this a warning? */
 		if (identity == POINTER) {
@@ -65,7 +65,7 @@ static int init (char *symbol_name, int type, int identity, int *dim, TAG_SYMBOL
 		add_data_initials(symbol_name, CINT, value, tag);
 		*dim = *dim - 1;
 	}
-	else if (qstr(&value)) {
+	else if (quoted_str(&value)) {
 		add_data_initials(symbol_name, CCHAR, value, tag);
 		*dim = *dim - 1;
 	}