🐐 Compiler fixes

This commit is contained in:
2026-04-24 17:14:08 +02:00
parent 6d4a456010
commit 37050e3e3b
5 changed files with 82 additions and 8 deletions

View File

@@ -129,7 +129,7 @@ def emit_expr(node, ctx):
if isinstance(node, UnaryMinus): if isinstance(node, UnaryMinus):
inner_lines, inner_var = emit_expr(node.expr, ctx) inner_lines, inner_var = emit_expr(node.expr, ctx)
tmp = ctx.fresh_tmp() tmp = ctx.fresh_tmp()
return inner_lines + [f"CentValue {tmp} = cent_int(-{inner_var}.ival);"], tmp return inner_lines + [f"CentValue {tmp} = cent_neg({inner_var});"], tmp
if isinstance(node, UnaryNot): if isinstance(node, UnaryNot):
inner_lines, inner_var = emit_expr(node.expr, ctx) inner_lines, inner_var = emit_expr(node.expr, ctx)

View File

@@ -92,6 +92,8 @@ def compile_program(program):
lines.append(" cent_init();") lines.append(" cent_init();")
if "MAGNVM" in ctx.modules: if "MAGNVM" in ctx.modules:
lines.append(" cent_magnvm = 1;") lines.append(" cent_magnvm = 1;")
if "SVBNVLLA" in ctx.modules:
lines.append(" cent_svbnvlla = 1;")
lines.append(" CentScope _scope = {0};") lines.append(" CentScope _scope = {0};")
lines.append(" CentValue _return_val = cent_null();") lines.append(" CentValue _return_val = cent_null();")

View File

@@ -15,6 +15,7 @@
CentArena *cent_arena; CentArena *cent_arena;
int cent_magnvm = 0; int cent_magnvm = 0;
int cent_svbnvlla = 0;
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/* Portable xorshift32 RNG (matches Python _CentRng) */ /* Portable xorshift32 RNG (matches Python _CentRng) */
@@ -181,7 +182,15 @@ void cent_int_to_roman(long n, char *buf, size_t bufsz) {
if (bufsz > 6) { memcpy(buf, "NVLLVS", 6); buf[6] = '\0'; } if (bufsz > 6) { memcpy(buf, "NVLLVS", 6); buf[6] = '\0'; }
return; return;
} }
if (n < 0 || (n > 3999 && !cent_magnvm)) if (n < 0) {
if (!cent_svbnvlla)
cent_runtime_error("number out of range for Roman numerals");
if (bufsz < 2) cent_runtime_error("Roman numeral buffer overflow");
buf[0] = '-';
cent_int_to_roman(-n, buf + 1, bufsz - 1);
return;
}
if (n > 3999 && !cent_magnvm)
cent_runtime_error("number out of range for Roman numerals"); cent_runtime_error("number out of range for Roman numerals");
size_t pos = 0; size_t pos = 0;
if (n > 3999) { if (n > 3999) {
@@ -271,8 +280,13 @@ static int write_val(CentValue v, char *buf, int bufsz) {
case CENT_FRAC: { case CENT_FRAC: {
long num = v.fval.num, den = v.fval.den; long num = v.fval.num, den = v.fval.den;
if (den < 0) { num = -num; den = -den; } if (den < 0) { num = -num; den = -den; }
if (num < 0) int negative = 0;
if (num < 0) {
if (!cent_svbnvlla)
cent_runtime_error("cannot display negative numbers without SVBNVLLA"); cent_runtime_error("cannot display negative numbers without SVBNVLLA");
negative = 1;
num = -num;
}
long int_part = num / den; long int_part = num / den;
long rem_num = num % den; long rem_num = num % den;
@@ -297,11 +311,13 @@ static int write_val(CentValue v, char *buf, int bufsz) {
for (int i = 0; i < (int)((level_int % 6) % 2); i++) frac_buf[frac_pos++] = '.'; for (int i = 0; i < (int)((level_int % 6) % 2); i++) frac_buf[frac_pos++] = '.';
} }
n = int_len + frac_pos; n = int_len + frac_pos + (negative ? 1 : 0);
if (buf && n < bufsz) { if (buf && n < bufsz) {
memcpy(buf, int_buf, int_len); int pos = 0;
memcpy(buf + int_len, frac_buf, frac_pos); if (negative) buf[pos++] = '-';
buf[n] = '\0'; memcpy(buf + pos, int_buf, int_len); pos += int_len;
memcpy(buf + pos, frac_buf, frac_pos); pos += frac_pos;
buf[pos] = '\0';
} }
return n; return n;
} }
@@ -391,6 +407,13 @@ static void to_frac(CentValue v, long *num, long *den) {
else { *num = v.fval.num; *den = v.fval.den; } else { *num = v.fval.num; *den = v.fval.den; }
} }
CentValue cent_neg(CentValue v) {
if (v.type == CENT_INT) return cent_int(-v.ival);
if (v.type == CENT_FRAC) return frac_reduce(-v.fval.num, v.fval.den);
cent_type_error("Unary minus requires a number");
return cent_null();
}
CentValue cent_add(CentValue a, CentValue b) { CentValue cent_add(CentValue a, CentValue b) {
if (a.type == CENT_INT && b.type == CENT_INT) if (a.type == CENT_INT && b.type == CENT_INT)
return cent_int(a.ival + b.ival); return cent_int(a.ival + b.ival);

View File

@@ -97,6 +97,9 @@ extern CentArena *cent_arena;
/* Set to 1 when CVM MAGNVM is active; enables extended numeral display */ /* Set to 1 when CVM MAGNVM is active; enables extended numeral display */
extern int cent_magnvm; extern int cent_magnvm;
/* Set to 1 when CVM SVBNVLLA is active; enables negative number display */
extern int cent_svbnvlla;
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/* Value constructors */ /* Value constructors */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
@@ -197,6 +200,7 @@ char *cent_make_string(CentValue v);
/* Arithmetic and comparison operators */ /* Arithmetic and comparison operators */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
CentValue cent_neg(CentValue v); /* unary minus: INT or FRAC */
CentValue cent_add(CentValue a, CentValue b); /* INT+INT or FRAC+FRAC/INT */ CentValue cent_add(CentValue a, CentValue b); /* INT+INT or FRAC+FRAC/INT */
CentValue cent_array_concat(CentValue a, CentValue b); /* @ operator: concatenate two arrays */ CentValue cent_array_concat(CentValue a, CentValue b); /* @ operator: concatenate two arrays */
CentValue cent_concat(CentValue a, CentValue b); /* & operator: coerce all types to str */ CentValue cent_concat(CentValue a, CentValue b); /* & operator: coerce all types to str */

View File

@@ -1747,6 +1747,51 @@ class TestMAGNVM(unittest.TestCase):
run_test(self, source, nodes, value, output) run_test(self, source, nodes, value, output)
# --- SVBNVLLA module (display of negatives) ---
svbnvlla_display_tests = [
# DIC prints a negative numeral
("CVM SVBNVLLA\nDIC(- III)",
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("DIC", [UnaryMinus(Numeral("III"))]))]),
ValStr("-III"), "-III\n"),
# Concat operator & with a negative numeral
('CVM SVBNVLLA\nDIC("x: " & - V)',
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("DIC", [BinOp(String("x: "), UnaryMinus(Numeral("V")), "SYMBOL_AMPERSAND")]))]),
ValStr("x: -V"), "x: -V\n"),
# String interpolation of a negative numeral
('CVM SVBNVLLA\nDIC("val: {- X}")',
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("DIC", [InterpolatedString([String("val: "), UnaryMinus(Numeral("X"))])]))]),
ValStr("val: -X"), "val: -X\n"),
# DIC of LITTERA(negative numeral)
("CVM SVBNVLLA\nDIC(LITTERA(- III))",
Program([ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("LITTERA", [UnaryMinus(Numeral("III"))])]))]),
ValStr("-III"), "-III\n"),
# Combined with MAGNVM: negative of a number > 3999
("CVM MAGNVM\nCVM SVBNVLLA\nDIC(- (M + M + M + M))",
Program([ModuleCall("MAGNVM"), ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("DIC", [UnaryMinus(BinOp(BinOp(BinOp(Numeral("M"), Numeral("M"), "SYMBOL_PLUS"), Numeral("M"), "SYMBOL_PLUS"), Numeral("M"), "SYMBOL_PLUS"))]))]),
ValStr("-MV_"), "-MV_\n"),
# Negative fraction via int / -int
("CVM FRACTIO\nCVM SVBNVLLA\nDIC(V / - II)",
Program([ModuleCall("FRACTIO"), ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("DIC", [BinOp(Numeral("V"), UnaryMinus(Numeral("II")), "SYMBOL_DIVIDE")]))]),
ValStr("-IIS"), "-IIS\n"),
# Negative pure fraction (no integer part)
("CVM FRACTIO\nCVM SVBNVLLA\nDIC(I / - II)",
Program([ModuleCall("FRACTIO"), ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("DIC", [BinOp(Numeral("I"), UnaryMinus(Numeral("II")), "SYMBOL_DIVIDE")]))]),
ValStr("-S"), "-S\n"),
("CVM FRACTIO\nCVM SVBNVLLA\nDIC(- S)",
Program([ModuleCall("FRACTIO"), ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("DIC", [UnaryMinus(Fractio("S"))]))]),
ValStr("-S"), "-S\n"),
("CVM FRACTIO\nCVM SVBNVLLA\nDIC(- IIS)",
Program([ModuleCall("FRACTIO"), ModuleCall("SVBNVLLA")], [ExpressionStatement(BuiltIn("DIC", [UnaryMinus(Fractio("IIS"))]))]),
ValStr("-IIS"), "-IIS\n"),
]
class TestSVBNVLLADisplay(unittest.TestCase):
@parameterized.expand(svbnvlla_display_tests)
def test_svbnvlla_display(self, source, nodes, value, output=""):
run_test(self, source, nodes, value, output)
# --- ET and AVT (boolean and/or) --- # --- ET and AVT (boolean and/or) ---
et_avt_tests = [ et_avt_tests = [