value_interp.c in C
A tiny stack machine built on a tagged union, with typed arithmetic.
#include <stdio.h>
#include <string.h>
#define STACK_CAP 16
typedef enum { V_INT, V_DOUBLE, V_ERROR } Kind;
typedef struct {
Kind kind;
union {
long as_int;
double as_double;
const char *as_error;
} data;
} Value;
static Value make_int(long n) {
Value v = {V_INT, {.as_int = n}};
return v;
}
static Value make_double(double d) {
Value v;
v.kind = V_DOUBLE;
v.data.as_double = d;
return v;
}
static Value make_error(const char *message) {
Value v;
v.kind = V_ERROR;
v.data.as_error = message;
return v;
}
static double numeric(const Value *v, int *ok) {
switch (v->kind) {
case V_INT:
return (double) v->data.as_int;
case V_DOUBLE:
return v->data.as_double;
default:
*ok = 0;
return 0.0;
}
}
static Value add(Value a, Value b) {
if (a.kind == V_INT && b.kind == V_INT) {
return make_int(a.data.as_int + b.data.as_int);
}
int ok = 1;
double sum = numeric(&a, &ok) + numeric(&b, &ok);
return ok ? make_double(sum) : make_error("cannot add these");
}
static void print_value(const Value *v) {
switch (v->kind) {
case V_INT:
printf("int %ld\n", v->data.as_int);
break;
case V_DOUBLE:
printf("double %.3f\n", v->data.as_double);
break;
default:
printf("error: %s\n", v->data.as_error);
break;
}
}
int main(void) {
Value stack[STACK_CAP];
size_t depth = 0;
stack[depth++] = make_int(20);
stack[depth++] = make_int(22);
stack[depth++] = make_double(0.5);
stack[depth++] = make_error("bad input");
while (depth >= 2) {
Value b = stack[--depth];
Value a = stack[--depth];
Value result = add(a, b);
print_value(&result);
stack[depth++] = result;
if (result.kind == V_ERROR) {
break;
}
}
printf("depth %zu, union size %zu\n", depth, sizeof(Value));
return 0;
}
How it works
- Every value carries its kind, so the switch stays exhaustive.
- The stack is a fixed array with a depth counter.
- Type errors are reported rather than silently coerced.
Keywords and builtins used here
addbreakcasecharconstdefaultdoubleenumifintlongmainmake_doublemake_errormake_intnumericprint_valuereturnsize_tsizeofstaticstructswitchtypedefunionvoidwhile
The run, in numbers
- Lines
- 93
- Characters to type
- 1661
- Tokens
- 509
- Three-star pace
- 110 tpm
At the three-star pace of 110 tokens a minute, this run takes about 278 seconds.
Step 1 of 1 in Encore, step 13 of 13 in Unions, bitfields & undefined behavior.