Root/unparse.c

Source at commit 5fdea0e99a2e8543a59d508cf28e1f2ff3607f18 created 4 years 7 months ago.
By Werner Almesberger, gui_canvas.c (key_press_event): make / rotate through packages as well
1/*
2 * unparse.c - Dump an expression tree into a string
3 *
4 * Written 2009, 2012 by Werner Almesberger
5 * Copyright 2009, 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 * This is crazily inefficient but who cares :-)
15 */
16
17#include <stdlib.h>
18#include <stdio.h>
19
20#include "util.h"
21#include "expr.h"
22#include "unparse.h"
23
24
25enum prec {
26    prec_add,
27    prec_mult,
28    prec_unary,
29    prec_primary,
30};
31
32
33static int precedence(op_type op)
34{
35    if (op == op_add || op == op_sub)
36        return prec_add;
37    if (op == op_mult || op == op_div)
38        return prec_mult;
39    if (op == op_minus)
40        return prec_unary;
41    if (op == op_num || op == op_string || op == op_var ||
42        op == op_sin || op == op_cos || op == op_sqrt || op == op_floor)
43        return prec_primary;
44    abort();
45}
46
47
48static char *merge3(char *a, const char *op, char *b)
49{
50    char *buf;
51
52    buf = alloc_size(strlen(op)+strlen(a)+strlen(b)+1);
53    sprintf(buf, "%s%s%s", a, op, b);
54    free(a);
55    free(b);
56    return buf;
57}
58
59
60static char *merge2(const char *op, char *a)
61{
62    char *buf;
63
64    buf = alloc_size(strlen(op)+strlen(a)+1);
65    sprintf(buf, "%s%s", op, a);
66    free(a);
67    return buf;
68}
69
70
71static char *unparse_op(const struct expr *expr, enum prec prec);
72
73
74static char *unparse_fn(const char *name, const struct expr *expr)
75{
76    char *buf, *tmp;
77
78    tmp = unparse_op(expr->u.op.a, prec_add);
79    buf = alloc_size(strlen(name)+strlen(tmp)+3);
80    sprintf(buf, "%s(%s)", name, tmp);
81    free(tmp);
82    return buf;
83}
84
85
86static char *unparse_op(const struct expr *expr, enum prec prec)
87{
88    char tmp[100];
89    char *buf, *temp;
90
91    if (prec > precedence(expr->op)) {
92        temp = unparse_op(expr, prec_add);
93        buf = alloc_size(strlen(temp)+3);
94        sprintf(buf, "(%s)", temp);
95        free(temp);
96        return buf;
97    }
98    if (expr->op == op_num) {
99        snprintf(tmp, sizeof(tmp), "%lg%s",
100            expr->u.num.n, str_unit(expr->u.num));
101        return stralloc(tmp);
102    }
103    if (expr->op == op_string)
104        return stralloc_printf("\"%s\"", expr->u.str);
105    if (expr->op == op_var)
106        return stralloc(expr->u.var);
107    if (expr->op == op_minus)
108        return merge2("-", unparse_op(expr->u.op.a, prec_unary));
109    if (expr->op == op_add)
110        return merge3(unparse_op(expr->u.op.a, prec_add), "+",
111            unparse_op(expr->u.op.b, prec_add));
112    if (expr->op == op_sub)
113        return merge3(unparse_op(expr->u.op.a, prec_add), "-",
114            unparse_op(expr->u.op.b, prec_mult));
115    if (expr->op == op_mult)
116        return merge3(unparse_op(expr->u.op.a, prec_mult), "*",
117            unparse_op(expr->u.op.b, prec_mult));
118    if (expr->op == op_div)
119        return merge3(unparse_op(expr->u.op.a, prec_mult), "/",
120            unparse_op(expr->u.op.b, prec_primary));
121    if (expr->op == op_sin)
122        return unparse_fn("sin", expr);
123    if (expr->op == op_cos)
124        return unparse_fn("cos", expr);
125    if (expr->op == op_sqrt)
126        return unparse_fn("sqrt", expr);
127    if (expr->op == op_floor)
128        return unparse_fn("floor", expr);
129    abort();
130}
131
132
133char *unparse(const struct expr *expr)
134{
135    return expr ? unparse_op(expr, prec_add) : stralloc("");
136}
137

Archive Download this file

Branches:
master



interactive