juegos

Juegos de terminal de Pancho: Catan (TUI, GUI, web, servidor, PicoCalc), ajedrez, calculadora y minijuegos
git clone https://git.lu3dhn.xyz/juegos.git
Log | Files | Refs

compile.c (10573B)


      1 /* compile.c - de tokens a RPN, con las precedencias de la Casio:
      2  *   =  <  + -  <  × ÷  <  nPr nCr  <  multiplicacion implicita  <  - unario
      3  *      <  potencia y postfijos (x², x⁻¹, !, %)  <  funciones, plantillas, parentesis
      4  * Asi -2² = -4 y 1÷2π = 1/(2π). La recursion esta acotada (MAX_NEST). */
      5 #include <string.h>
      6 #include "eval.h"
      7 
      8 #define MAX_NEST 24
      9 
     10 static const Expr *E;
     11 static const EvalCtx *CX;
     12 static Prog *P;
     13 static int I, END_, ERR, EPOS, DEPTH;
     14 
     15 static int peek(void)
     16 {
     17     while (I < END_ && E->t[I] == ' ') I++;          /* los espacios no cuentan */
     18     return I < END_ ? E->t[I] : 0;
     19 }
     20 
     21 static void fail(int code, int pos)
     22 {
     23     if (!ERR) { ERR = code; EPOS = pos; }
     24 }
     25 
     26 static void emit(int op, int arg, int pos, int nargs)
     27 {
     28     if (P->n >= PROG_MAX) { fail(CE_STACK, pos); return; }
     29     Code *c = &P->c[P->n++];
     30     c->op = (uint8_t)op; c->arg = (uint8_t)arg; c->pos = (uint8_t)(pos < 255 ? pos : 255); c->nargs = (uint8_t)nargs; c->len = 0;
     31 }
     32 
     33 static void emit_num(Num v, int pos)
     34 {
     35     if (P->nk >= PROG_CONSTS) { fail(CE_STACK, pos); return; }
     36     P->k[P->nk] = v;
     37     emit(OP_NUM, P->nk++, pos, 0);
     38 }
     39 
     40 static void parse_expr(void);
     41 
     42 /* fin del campo actual: SEP, END o el final */
     43 static bool at_field_end(void) { int t = peek(); return !t || t == T_SEP || t == T_END; }
     44 
     45 /* parsea un campo de plantilla que empieza en I (hasta SEP/END) y lo consume */
     46 static void parse_field(void)
     47 {
     48     int save_end = END_;
     49     if (at_field_end()) { fail(CE_SYNTAX, I); return; }      /* casilla vacia */
     50     parse_expr();
     51     if (!at_field_end()) fail(CE_SYNTAX, I);
     52     END_ = save_end;
     53     if (I < END_ && (E->t[I] == T_SEP || E->t[I] == T_END)) I++;
     54 }
     55 
     56 static bool is_digit(int t) { return (t >= '0' && t <= '9') || t == '.'; }
     57 static bool is_hex(int t) { return (t >= '0' && t <= '9') || (t >= 'A' && t <= 'F'); }
     58 
     59 static void parse_number(void)
     60 {
     61     int pos = I;
     62     char buf[48];
     63     int k = 0, exp10 = 0;
     64     if (CX && CX->prog) {
     65         /* entero en la base de entrada */
     66         int64_t v = 0;
     67         bool any = false;
     68         while (is_hex(peek())) {
     69             int t = peek(), d = t <= '9' ? t - '0' : t - 'A' + 10;
     70             if (d >= CX->base) { fail(CE_SYNTAX, I); return; }
     71             v = (int64_t)((uint64_t)v * (uint64_t)CX->base + (uint64_t)d);
     72             any = true;
     73             I++;
     74         }
     75         if (!any) { fail(CE_SYNTAX, I); return; }
     76         emit_num(num_int(v), pos);
     77         return;
     78     }
     79     int dots = 0;
     80     while (is_digit(peek()) && k < 40) {
     81         if (peek() == '.' && ++dots > 1) { fail(CE_SYNTAX, I); return; }
     82         buf[k++] = (char)E->t[I++];
     83     }
     84     if (!k) buf[k++] = '1';                       /* "×10^3" solo = 1×10^3 */
     85     buf[k] = 0;
     86     if (k == 1 && buf[0] == '.') { fail(CE_SYNTAX, pos); return; }
     87     if (peek() == T_E10) {
     88         I++;
     89         bool neg = false;
     90         if (peek() == '-') { neg = true; I++; }
     91         int nd = 0;
     92         while (peek() >= '0' && peek() <= '9') { exp10 = exp10 * 10 + (E->t[I++] - '0'); if (++nd > 3) break; }
     93         if (!nd) { fail(CE_SYNTAX, I); return; }
     94         if (neg) exp10 = -exp10;
     95     }
     96     Num v = num_lit(buf, exp10);
     97     if (num_bad(&v)) fail(CE_MATH, pos);
     98     emit_num(v, pos);
     99 }
    100 
    101 static void parse_fn(void)
    102 {
    103     int pos = I, f = E->t[I++] - T_FN;
    104     int args = 0;
    105     if (!(peek() == ')' || at_field_end())) {
    106         for (;;) {
    107             parse_expr();
    108             args++;
    109             if (peek() == ',') { I++; continue; }
    110             break;
    111         }
    112     }
    113     if (peek() == ')') I++;
    114     else if (!at_field_end()) fail(CE_SYNTAX, I);
    115     if (args != FN_INFO[f].args) { fail(CE_SYNTAX, pos); return; }
    116     emit(OP_FN, f, pos, args);
    117 }
    118 
    119 static void parse_primary(void)
    120 {
    121     int t = peek(), pos = I;
    122     if (!t || t == T_SEP || t == T_END) { fail(CE_SYNTAX, I); return; }
    123     if (++DEPTH > MAX_NEST) { fail(CE_STACK, I); return; }
    124     if (is_digit(t) || t == T_E10 || (CX && CX->prog && is_hex(t))) parse_number();
    125     else if (t == '(') {
    126         I++;
    127         parse_expr();
    128         if (peek() == ')') I++;
    129         else if (!at_field_end()) fail(CE_SYNTAX, I);
    130     } else if (t >= T_FN && t < T_FN + FN_COUNT) parse_fn();
    131     else if (t == T_PI) { I++; emit(OP_PI, 0, pos, 0); }
    132     else if (t == T_E) { I++; emit(OP_E, 0, pos, 0); }
    133     else if (t == T_ANS) { I++; emit(OP_ANS, 0, pos, 0); }
    134     else if (t == T_PREANS) { I++; emit(OP_PREANS, 0, pos, 0); }
    135     else if (t == T_RAN) { I++; emit(OP_RAN, 0, pos, 0); }
    136     else if (t >= T_MAT && t <= T_MATANS) { I++; emit(OP_MAT, t - T_MAT, pos, 0); }
    137     else if (t >= T_VCT && t <= T_VCTANS) { I++; emit(OP_VCT, t - T_VCT, pos, 0); }
    138     else if (t >= T_VAR && t < T_VAR + NVARS) { I++; emit(OP_VAR, t - T_VAR, pos, 0); }
    139     else if (t >= 'a' && t <= 'z') {
    140         I++;
    141         if (t == 'e') emit(OP_E, 0, pos, 0);
    142         else if (t == 'i' && CX && CX->cplx) emit(OP_IMAG, 0, pos, 0);
    143         else {
    144             const char *v = strchr(VAR_NAMES, t - 'a' + 'A');
    145             if (v) emit(OP_VAR, (int)(v - VAR_NAMES), pos, 0);
    146             else fail(CE_SYNTAX, pos);
    147         }
    148     } else if (tok_is_frac(t)) {
    149         I++;
    150         parse_field();
    151         parse_field();
    152         emit(OP_DIV, 0, pos, 2);
    153     } else if (t == T_SQRT) { I++; parse_field(); emit(OP_SQRT, 0, pos, 1); }
    154     else if (t == T_ROOT) { I++; parse_field(); parse_field(); emit(OP_ROOT, 0, pos, 2); }
    155     else if (t == T_LOGB) { I++; parse_field(); parse_field(); emit(OP_LOGB, 0, pos, 2); }
    156     else if (t == T_ABS) { I++; parse_field(); emit(OP_ABS, 0, pos, 1); }
    157     else if (t == T_MIXED) { I++; parse_field(); parse_field(); parse_field(); emit(OP_MIXED, 0, pos, 3); }
    158     else if (t == T_INTEG || t == T_SUM || t == T_PROD || t == T_DERIV) {
    159         /* el cuerpo se compila en un tramo que la ejecucion normal saltea (OP_SKIP);
    160          * la operacion lo corre con distintos valores de X */
    161         I++;
    162         if (t != T_DERIV) { parse_field(); parse_field(); }
    163         int skip = P->n;
    164         emit(OP_SKIP, 0, pos, 0);
    165         int start = P->n;
    166         parse_field();
    167         int len = P->n - start;
    168         if (!ERR) P->c[skip].len = (uint8_t)len;
    169         if (t == T_DERIV) parse_field();
    170         int op = t == T_INTEG ? OP_INTEG : t == T_SUM ? OP_SUM : t == T_PROD ? OP_PROD : OP_DERIV;
    171         emit(op, start, pos, t == T_DERIV ? 1 : 2);
    172         if (!ERR) P->c[P->n - 1].len = (uint8_t)len;
    173     }
    174     else fail(CE_SYNTAX, pos);
    175     DEPTH--;
    176 }
    177 
    178 static void parse_postfix(void)
    179 {
    180     parse_primary();
    181     for (;;) {
    182         int t = peek(), pos = I;
    183         if (tok_is_pow(t)) { I++; parse_field(); emit(OP_POW, 0, pos, 2); }
    184         else if (t == T_INV) { I++; emit(OP_INV, 0, pos, 1); }
    185         else if (t == '!') { I++; emit(OP_FACT, 0, pos, 1); }
    186         else if (t == '%') { I++; emit(OP_PCT, 0, pos, 1); }
    187         else if (t == T_DEGS) {
    188             /* sexagesimal: a°b°c° = a + b/60 + c/3600 (exacto) */
    189             I++;
    190             for (int k = 60; k <= 3600; k *= 60) {
    191                 int save = I;
    192                 if (!is_digit(peek())) break;
    193                 while (is_digit(peek())) I++;
    194                 bool more = peek() == T_DEGS;
    195                 I = save;
    196                 if (!more) break;
    197                 parse_number();
    198                 I++;
    199                 emit_num(num_int(k), pos);
    200                 emit(OP_DIV, 0, pos, 2);
    201                 emit(OP_ADD, 0, pos, 2);
    202             }
    203         }
    204         else break;
    205     }
    206 }
    207 
    208 static void parse_unary(void)
    209 {
    210     int t = peek(), pos = I;
    211     if (t == '-') { I++; parse_unary(); emit(OP_NEG, 0, pos, 1); return; }
    212     if (t == '+') { I++; parse_unary(); return; }
    213     if (t == T_FN + FN_NOT || t == T_FN + FN_NEG) { parse_postfix(); return; }
    214     parse_postfix();
    215 }
    216 
    217 /* un atomo puede empezar aca (para la multiplicacion implicita) */
    218 static bool starts_atom(int t)
    219 {
    220     if (!t || t == T_SEP || t == T_END) return false;
    221     if (CX && CX->prog) return false;                        /* en programador no hay implicita */
    222     return is_digit(t) || t == '(' || t == T_PI || t == T_E || t == T_ANS || t == T_PREANS ||
    223            t == T_RAN || t == T_E10 || (t >= T_MAT && t <= T_VCTANS) || (t >= T_VAR && t < T_VAR + NVARS) || (t >= T_FN && t < T_FN + FN_COUNT) ||
    224            (t >= 'a' && t <= 'z') || (tok_is_tpl(t) && !tok_is_pow(t));
    225 }
    226 
    227 static void parse_implicit(void)
    228 {
    229     parse_unary();
    230     while (!ERR && starts_atom(peek())) {
    231         int pos = I;
    232         parse_postfix();
    233         emit(OP_MUL, 0, pos, 2);
    234     }
    235 }
    236 
    237 static void parse_comb(void)
    238 {
    239     parse_implicit();
    240     for (;;) {
    241         int t = peek(), pos = I;
    242         if (t != T_NPR && t != T_NCR && t != T_ANGLE) break;
    243         I++;
    244         parse_implicit();
    245         emit(t == T_NPR ? OP_NPR : t == T_NCR ? OP_NCR : OP_POLAR, 0, pos, 2);
    246     }
    247 }
    248 
    249 static void parse_prod(void)
    250 {
    251     parse_comb();
    252     for (;;) {
    253         int t = peek(), pos = I;
    254         if (t != T_MUL && t != T_DIV) break;
    255         I++;
    256         parse_comb();
    257         emit(t == T_MUL ? OP_MUL : OP_DIV, 0, pos, 2);
    258     }
    259 }
    260 
    261 static void parse_sum(void)
    262 {
    263     parse_prod();
    264     for (;;) {
    265         int t = peek(), pos = I;
    266         if (t != '+' && t != '-') break;
    267         I++;
    268         parse_prod();
    269         emit(t == '+' ? OP_ADD : OP_SUB, 0, pos, 2);
    270     }
    271 }
    272 
    273 /* programador: and/or/xor/xnor escritos como palabras, mas bajos que + - */
    274 static int word_op(void)
    275 {
    276     static const char *const W[] = { "xnor", "and", "xor", "or" };
    277     static const int OPS[] = { OP_XNOR, OP_AND, OP_XOR, OP_OR };
    278     for (int w = 0; w < 4; w++) {
    279         int l = (int)strlen(W[w]);
    280         if (I + l > END_) continue;
    281         int k = 0;
    282         while (k < l && E->t[I + k] == (uint8_t)W[w][k]) k++;
    283         if (k == l) { I += l; return OPS[w]; }
    284     }
    285     return -1;
    286 }
    287 
    288 static void parse_logic(void)
    289 {
    290     parse_sum();
    291     while (CX && CX->prog && !ERR) {
    292         peek();
    293         int pos = I, op = word_op();
    294         if (op < 0) break;
    295         parse_sum();
    296         emit(op, 0, pos, 2);
    297     }
    298 }
    299 
    300 static void parse_expr(void)
    301 {
    302     if (++DEPTH > MAX_NEST) { fail(CE_STACK, I); return; }
    303     parse_logic();
    304     if (peek() == '=') {
    305         int pos = I;
    306         I++;
    307         parse_logic();
    308         emit(OP_EQ, 0, pos, 2);
    309         P->has_eq = true;
    310     }
    311     DEPTH--;
    312 }
    313 
    314 int compile(const Expr *e, const EvalCtx *cx, Prog *p, int *pos)
    315 {
    316     E = e; CX = cx; P = p;
    317     I = 0; END_ = e->n; ERR = 0; EPOS = 0; DEPTH = 0;
    318     p->n = p->nk = 0;
    319     p->has_eq = false;
    320     if (!e->n) { if (pos) *pos = 0; return CE_SYNTAX; }
    321     parse_expr();
    322     if (!ERR && I < e->n) fail(CE_SYNTAX, I);
    323     if (pos) *pos = EPOS;
    324     return ERR;
    325 }