typestar

value_interp.c en C

Una maquinita de pila sobre una unión etiquetada, con aritmética tipada.

#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;
}

Cómo funciona

  1. Cada valor lleva su clase, así el switch se mantiene exhaustivo.
  2. La pila es un arreglo fijo con un contador de profundidad.
  3. Los errores de tipo se reportan en vez de convertirse en silencio.

Palabras clave y builtins usados aquí

El intento, en números

Líneas
93
Caracteres a escribir
1661
Tokens
509
Ritmo de tres estrellas
110 tpm

Al ritmo de tres estrellas de 110 tokens por minuto, este intento toma unos 278 segundos.

Escribe este fragmento

Paso 1 de 1 en Bis; paso 13 de 13 en Uniones, campos de bits y comportamiento indefinido.

← Anterior