Root/expr.c

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

Archive Download this file

Branches:
master



interactive