Root/expr.c

Source at commit 809e8142b53ba7227241d39d2c4057f7201087a9 created 4 years 7 months ago.
By Werner Almesberger, gui.c (change_world): don't change color of the active frame
1/*
2 * expr.c - Expressions and values
3 *
4 * Written 2009, 2010, 2012 by Werner Almesberger
5 * Copyright 2009, 2010, 2012 by Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdlib.h>
15#include <string.h>
16#include <math.h>
17
18#include "util.h"
19#include "error.h"
20#include "obj.h"
21#include "unparse.h"
22#include "fpd.h"
23#include "expr.h"
24
25
26struct num undef = { .type = nt_none };
27
28
29/* ----- error reporting --------------------------------------------------- */
30
31
32void fail_expr(const struct expr *expr)
33{
34    char *s;
35
36    s = unparse(expr);
37    fail("in \"%s\" at line %d", s, expr->lineno);
38    free(s);
39}
40
41
42/* ----- unit conversion --------------------------------------------------- */
43
44
45/*
46 * If an expression contains a typo, we may get large exponents. Thus, we just
47 * "sprintf" in order to be able to handle any integer. Since the number of
48 * different exponents in a session will still be small, we use "unique" to
49 * give us a constant string, so that we don't have to worry about memory
50 * allocation.
51 */
52
53const char *str_unit(struct num n)
54{
55    const char *unit;
56    char buf[20]; /* @@@ plenty */
57
58    if (n.exponent == 0)
59        return "";
60    switch (n.type) {
61    case nt_mm:
62        unit = "mm";
63        break;
64    case nt_mil:
65        unit = "mil";
66        break;
67    default:
68        abort();
69    }
70    if (n.exponent == 1)
71        return unit;
72    sprintf(buf, "%s^%d", unit, n.exponent);
73    return unique(buf);
74}
75
76
77int to_unit(struct num *n)
78{
79    if (!is_distance(*n)) {
80        fail("%s^%d is not a distance",
81            n->type == nt_mm ? "mm" : n->type == nt_mil ? "mil" : "?",
82            n->exponent);
83        return 0;
84    }
85    switch (n->type) {
86    case nt_mil:
87        n->n = mil_to_units(n->n);
88        break;
89    case nt_mm:
90        n->n = mm_to_units(n->n);
91        break;
92    default:
93        abort();
94    }
95    return 1;
96}
97
98
99/* ----- number to string conversion (hackish) ----------------------------- */
100
101
102static char *num_to_string(struct num n)
103{
104    static char buf[100]; /* enough :-) */
105
106    snprintf(buf, sizeof(buf), "%lg%s", n.n, str_unit(n));
107    return buf;
108}
109
110
111/* ----- primary expressions ----------------------------------------------- */
112
113
114struct num op_string(const struct expr *self, const struct frame *frame)
115{
116    fail("cannot evaluate string");
117    return undef;
118}
119
120
121struct num op_num(const struct expr *self, const struct frame *frame)
122{
123    return self->u.num;
124}
125
126
127/*
128 * We have two modes of operation: during instantiation and editing, after
129 * instantiation. During instantiation, we follow curr_row and curr_parent.
130 * These pointers are NULL when instantiation finishes, and we use this as a
131 * signal that we're now in editing mode. In editing mode, the "active" values
132 * are used instead of the "current" ones.
133 */
134
135struct num eval_var(const struct frame *frame, const char *name)
136{
137    const struct table *table;
138    const struct loop *loop;
139    const struct value *value;
140    struct var *var;
141    struct num res;
142
143    for (table = frame->tables; table; table = table->next) {
144        value = table->curr_row ? table->curr_row->values :
145            table->active_row->values;
146        for (var = table->vars; var; var = var->next) {
147            if (!var->key && var->name == name) {
148                if (var->visited) {
149                    fail("recursive evaluation through "
150                        "\"%s\"", name);
151                    return undef;
152                }
153                var->visited = 1;
154                res = eval_num(value->expr, frame);
155                var->visited = 0;
156                return res;
157            }
158            value = value->next;
159        }
160    }
161    for (loop = frame->loops; loop; loop = loop->next)
162        if (loop->var.name == name) {
163            if (loop->curr_value == UNDEF)
164                return make_num(loop->n+loop->active);
165            if (!loop->initialized) {
166                fail("uninitialized loop \"%s\"", name);
167                return undef;
168            }
169            return make_num(loop->curr_value);
170        }
171    if (frame->curr_parent)
172        return eval_var(frame->curr_parent, name);
173    if (frame->active_ref)
174        return eval_var(frame->active_ref->frame, name);
175    return undef;
176}
177
178
179static const char *eval_string_var(const struct frame *frame, const char *name)
180{
181    const struct table *table;
182    const struct loop *loop;
183    const struct value *value;
184    struct var *var;
185    const char *res;
186
187    for (table = frame->tables; table; table = table->next) {
188        value = table->curr_row ? table->curr_row->values :
189            table->active_row->values;
190        for (var = table->vars; var; var = var->next) {
191            if (!var->key && var->name == name) {
192                if (var->visited)
193                    return NULL;
194                var->visited = 1;
195                res = eval_str(value->expr, frame);
196                var->visited = 0;
197                return res;
198            }
199            value = value->next;
200        }
201    }
202    for (loop = frame->loops; loop; loop = loop->next)
203        if (loop->var.name == name)
204            return NULL;
205    if (frame->curr_parent)
206        return eval_string_var(frame->curr_parent, name);
207    if (frame->active_ref)
208        return eval_string_var(frame->active_ref->frame, name);
209    return NULL;
210}
211
212
213struct num op_var(const struct expr *self, const struct frame *frame)
214{
215    struct num res;
216
217    res = eval_var(frame, self->u.var);
218    if (is_undef(res))
219        fail("undefined variable \"%s\"", self->u.var);
220    return res;
221}
222
223
224/* ----- Variable equivalence ---------------------------------------------- */
225
226
227static int num_eq(struct num a, struct num b)
228{
229    if (a.exponent != b.exponent)
230        return 0;
231    if (a.exponent && a.type != b.type) {
232        if (a.type == nt_mil)
233            return mil_to_mm(a.n, a.exponent) == b.n;
234        else
235            return a.n == mil_to_mm(b.n, b.exponent);
236    }
237    return a.n == b.n;
238}
239
240
241int var_eq(const struct frame *frame, const char *name,
242    const struct expr *expr)
243{
244    const char *vs, *es;
245    struct num vn, en;
246
247    vs = eval_string_var(frame, name);
248    if (!vs) {
249        vn = eval_var(frame, name);
250        if (is_undef(vn)) {
251            fail("undefined variable \"%s\"", name);
252            return -1;
253        }
254    }
255    es = eval_str(expr, frame);
256    if (!es) {
257        en = eval_num(expr, frame);
258        if (is_undef(en))
259            return -1;
260    }
261    if (vs || es) {
262        if (!vs)
263            vs = num_to_string(vn);
264        if (!es)
265            es = num_to_string(en);
266        return !strcmp(vs, es);
267    } else {
268        return num_eq(vn, en);
269    }
270}
271
272
273/* ----- arithmetic -------------------------------------------------------- */
274
275
276static struct num compatible_sum(struct num *a, struct num *b)
277{
278    struct num res;
279
280    if (a->type != b->type) {
281        if (a->type == nt_mil) {
282            a->type = nt_mm;
283            a->n = mil_to_mm(a->n, a->exponent);
284        }
285        if (b->type == nt_mil) {
286            b->type = nt_mm;
287            b->n = mil_to_mm(b->n, a->exponent);
288        }
289    }
290    if (a->exponent != b->exponent) {
291        fail("incompatible exponents (%d, %d)",
292            a->exponent, b->exponent);
293        return undef;
294    }
295    res.type = a->type;
296    res.exponent = a->exponent;
297    res.n = 0; /* keep gcc happy */
298    return res;
299}
300
301
302static struct num compatible_mult(struct num *a, struct num *b,
303    int exponent)
304{
305    struct num res;
306
307    if (a->type != b->type) {
308        if (a->type == nt_mil) {
309            a->type = nt_mm;
310            a->n = mil_to_mm(a->n, a->exponent);
311        }
312        if (b->type == nt_mil) {
313            b->type = nt_mm;
314            b->n = mil_to_mm(b->n, b->exponent);
315        }
316    }
317    res.type = a->type;
318    res.exponent = exponent;
319    res.n = 0; /* keep gcc happy */
320    return res;
321}
322
323
324static struct num sin_cos(const struct expr *self,
325    const struct frame *frame, double (*fn)(double arg))
326{
327    struct num res;
328
329    res = eval_num(self->u.op.a, frame);
330    if (is_undef(res))
331        return undef;
332    if (!is_dimensionless(res)) {
333        fail("angle must be dimensionless");
334        return undef;
335    }
336    res.n = fn(res.n/180.0*M_PI);
337    return res;
338}
339
340
341struct num op_sin(const struct expr *self, const struct frame *frame)
342{
343    return sin_cos(self, frame, sin);
344}
345
346
347struct num op_cos(const struct expr *self, const struct frame *frame)
348{
349    return sin_cos(self, frame, cos);
350}
351
352
353struct num op_sqrt(const struct expr *self, const struct frame *frame)
354{
355    struct num res;
356
357    res = eval_num(self->u.op.a, frame);
358    if (is_undef(res))
359        return undef;
360    if (res.exponent & 1) {
361        fail("exponent of sqrt argument must be a multiple of two");
362        return undef;
363    }
364    if (res.n < 0) {
365        fail("argument of sqrt must be positive");
366        return undef;
367    }
368    res.n = sqrt(res.n);
369    res.exponent >>= 1;
370    return res;
371}
372
373
374struct num op_minus(const struct expr *self, const struct frame *frame)
375{
376    struct num res;
377
378    res = eval_num(self->u.op.a, frame);
379    if (!is_undef(res))
380        res.n = -res.n;
381    return res;
382}
383
384
385struct num op_floor(const struct expr *self, const struct frame *frame)
386{
387    struct num res;
388
389    res = eval_num(self->u.op.a, frame);
390    if (!is_undef(res))
391        res.n = floor(res.n);
392    return res;
393}
394
395
396#define BINARY \
397    struct num a, b, res; \
398                            \
399    a = eval_num(self->u.op.a, frame); \
400    if (is_undef(a)) \
401        return undef; \
402    b = eval_num(self->u.op.b, frame); \
403    if (is_undef(b)) \
404        return undef;
405
406
407struct num op_add(const struct expr *self, const struct frame *frame)
408{
409    BINARY;
410    res = compatible_sum(&a, &b);
411    if (is_undef(res))
412        return undef;
413    res.n = a.n+b.n;
414    return res;
415}
416
417
418struct num op_sub(const struct expr *self, const struct frame *frame)
419{
420    BINARY;
421    res = compatible_sum(&a, &b);
422    if (is_undef(res))
423        return undef;
424    res.n = a.n-b.n;
425    return res;
426}
427
428
429struct num op_mult(const struct expr *self, const struct frame *frame)
430{
431    BINARY;
432    res = compatible_mult(&a, &b, a.exponent+b.exponent);
433    res.n = a.n*b.n;
434    return res;
435}
436
437
438struct num op_div(const struct expr *self, const struct frame *frame)
439{
440    BINARY;
441    if (!b.n) {
442        fail("division by zero");
443        return undef;
444    }
445    res = compatible_mult(&a, &b, a.exponent-b.exponent);
446    res.n = a.n/b.n;
447    return res;
448}
449
450
451/* ----- expression construction ------------------------------------------- */
452
453
454struct expr *new_op(op_type op)
455{
456    struct expr *expr;
457
458    expr = alloc_type(struct expr);
459    expr->op = op;
460    expr->lineno = lineno;
461    return expr;
462}
463
464
465struct expr *binary_op(op_type op, struct expr *a, struct expr *b)
466{
467    struct expr *expr;
468
469    expr = new_op(op);
470    expr->u.op.a = a;
471    expr->u.op.b = b;
472    return expr;
473}
474
475
476const char *eval_str(const struct expr *expr, const struct frame *frame)
477{
478    if (expr->op == op_string)
479        return expr->u.str;
480    if (expr->op == op_var)
481        return eval_string_var(frame, expr->u.var);
482    return NULL;
483}
484
485
486struct num eval_num(const struct expr *expr, const struct frame *frame)
487{
488    return expr->op(expr, frame);
489}
490
491
492/* ----- string expansion -------------------------------------------------- */
493
494
495char *expand(const char *name, const struct frame *frame)
496{
497    int len = strlen(name);
498    char *buf = alloc_size(len+1);
499    const char *s, *s0;
500    char *var;
501    const char *var_unique, *value_string;
502    struct num value;
503    int i, value_len;
504
505    i = 0;
506    for (s = name; *s; s++) {
507        if (*s != '$') {
508            buf[i++] = *s;
509            continue;
510        }
511        s0 = ++s;
512        if (*s != '{') {
513            while (is_id_char(*s, s == s0))
514                s++;
515            if (s == s0) {
516                if (*s) {
517                    goto invalid;
518                } else {
519                    fail("incomplete variable name");
520                    goto fail;
521                }
522            }
523            var = strnalloc(s0, s-s0);
524            len -= s-s0+1;
525            s--;
526        } else {
527            s++;
528            while (*s != '}') {
529                if (!*s) {
530                    fail("unfinished \"${...}\"");
531                    goto fail;
532                }
533                if (!is_id_char(*s, s == s0+1))
534                    goto invalid;
535                s++;
536            }
537            var = strnalloc(s0+1, s-s0-1);
538            len -= s-s0+2;
539        }
540        if (!frame)
541            continue;
542        var_unique = unique(var);
543        free(var);
544        value_string = eval_string_var(frame, var_unique);
545        if (!value_string) {
546            value = eval_var(frame, var_unique);
547            if (is_undef(value)) {
548                fail("undefined variable \"%s\"", var_unique);
549                goto fail;
550            }
551            value_string = num_to_string(value);
552        }
553        value_len = strlen(value_string);
554        len += value_len;
555        buf = realloc(buf, len+1);
556        if (!buf)
557            abort();
558        strcpy(buf+i, value_string);
559        i += value_len;
560    }
561    buf[i] = 0;
562    return buf;
563
564invalid:
565    fail("invalid character in variable name");
566fail:
567    free(buf);
568    return NULL;
569}
570
571
572/* ----- make a number -----------------------------------------------------*/
573
574
575struct expr *new_num(struct num num)
576{
577    struct expr *expr;
578
579    expr = new_op(op_num);
580    expr->u.num = num;
581    return expr;
582}
583
584
585/* ----- expression-only parser -------------------------------------------- */
586
587
588struct expr *parse_expr(const char *s)
589{
590    scan_expr(s);
591    return yyparse() ? NULL : expr_result;
592}
593
594
595static void vacate_op(struct expr *expr)
596{
597    if (expr->op == op_num || expr->op == op_var)
598        return;
599    if (expr->op == op_string) {
600        free(expr->u.str);
601        return;
602    }
603    if (expr->op == op_minus || expr->op == op_floor ||
604        expr->op == op_sin || expr->op == op_cos || expr->op == op_sqrt) {
605        free_expr(expr->u.op.a);
606        return;
607    }
608    if (expr->op == op_add || expr->op == op_sub ||
609        expr->op == op_mult || expr->op == op_div) {
610        free_expr(expr->u.op.a);
611        free_expr(expr->u.op.b);
612        return;
613    }
614    abort();
615}
616
617
618void free_expr(struct expr *expr)
619{
620    vacate_op(expr);
621    free(expr);
622}
623
624
625/* ----- [var =] value, ... shortcuts -------------------------------------- */
626
627
628int parse_var(const char *s, const char **id, struct value **values,
629    int max_values)
630{
631    const struct value *value;
632    int n;
633
634    scan_var(s);
635    if (yyparse())
636        return -1;
637    if (id)
638        *id = var_id;
639    *values = var_value_list;
640    n = 0;
641    for (value = var_value_list; value; value = value->next)
642        n++;
643    if (max_values == -1 || n <= max_values)
644        return n;
645    free_values(var_value_list, 0);
646    return -1;
647}
648
649
650int parse_values(const char *s, struct value **values)
651{
652    const struct value *value;
653    int n;
654
655    scan_values(s);
656    if (yyparse())
657        return -1;
658    *values = var_value_list;
659    n = 0;
660    for (value = var_value_list; value; value = value->next)
661        n++;
662    return n;
663}
664
665
666void free_values(struct value *values, int keep_expr)
667{
668    struct value *next;
669
670    while (values) {
671        next = values->next;
672        if (!keep_expr)
673            free_expr(values->expr);
674        free(values);
675        values = next;
676    }
677}
678

Archive Download this file

Branches:
master



interactive