Appendix B: Floating Point
float-type-tracking

Track variable types. Add a type flag:

var var_types: [256]u8 = [_]u8{0} ** 256;    // 0 = i64, 1 = f64
var global_types: [256]u8 = [_]u8{0} ** 256;

When exec_stmt handles var x: f64 = 3.14;, set the type flag:

    // After reading the type name:
    const type_name: []const u8 = read_name();
    const is_float: bool = streq(type_name, "f64");
    // ... later, when storing:
    if (is_float) { var_types[num_vars] = 1; }

Write helpers to check types:

fn isFloat(name: []const u8) bool {
    for (0..num_vars) |i| {
        if (streq(var_names[i], name) and var_types[i] == 1) { return true; }
    }
    for (0..num_globals) |i| {
        if (streq(global_names[i], name) and global_types[i] == 1) { return true; }
    }
    return false;
}

### Float arithmetic

The interpreter needs to know which operations are float and which are integer. We track a "current expression type" -- integer by default, float if any operand is float.