Root/
Source at commit 484c06850de493b9c48ab46057425dc4998f8fbe created 13 years 5 months ago. By Xiangfu Liu, remove the Build-Depends ttf-liberation | |
---|---|
1 | /* |
2 | * unparse.c - Dump an expression tree into a string |
3 | * |
4 | * Written 2009 by Werner Almesberger |
5 | * Copyright 2009 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 | |
25 | enum prec { |
26 | prec_add, |
27 | prec_mult, |
28 | prec_unary, |
29 | prec_primary, |
30 | }; |
31 | |
32 | |
33 | static 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) |
43 | return prec_primary; |
44 | abort(); |
45 | } |
46 | |
47 | |
48 | static 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 | |
60 | static 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 | |
71 | static char *unparse_op(const struct expr *expr, enum prec prec); |
72 | |
73 | |
74 | static 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 | |
86 | static char *unparse_op(const struct expr *expr, enum prec prec) |
87 | { |
88 | char tmp[100]; |
89 | char *buf, *temp; |
90 | |
91 | |
92 | if (prec > precedence(expr->op)) { |
93 | temp = unparse_op(expr, prec_add); |
94 | buf = alloc_size(strlen(temp)+3); |
95 | sprintf(buf, "(%s)", temp); |
96 | free(temp); |
97 | return buf; |
98 | } |
99 | if (expr->op == op_num) { |
100 | snprintf(tmp, sizeof(tmp), "%lg%s", |
101 | expr->u.num.n, str_unit(expr->u.num)); |
102 | return stralloc(tmp); |
103 | } |
104 | if (expr->op == op_string) |
105 | return stralloc_printf("\"%s\"", expr->u.str); |
106 | if (expr->op == op_var) |
107 | return stralloc(expr->u.var); |
108 | if (expr->op == op_minus) |
109 | return merge2("-", unparse_op(expr->u.op.a, prec_unary)); |
110 | if (expr->op == op_add) |
111 | return merge3(unparse_op(expr->u.op.a, prec_add), "+", |
112 | unparse_op(expr->u.op.b, prec_add)); |
113 | if (expr->op == op_sub) |
114 | return merge3(unparse_op(expr->u.op.a, prec_add), "-", |
115 | unparse_op(expr->u.op.b, prec_mult)); |
116 | if (expr->op == op_mult) |
117 | return merge3(unparse_op(expr->u.op.a, prec_mult), "*", |
118 | unparse_op(expr->u.op.b, prec_mult)); |
119 | if (expr->op == op_div) |
120 | return merge3(unparse_op(expr->u.op.a, prec_mult), "/", |
121 | unparse_op(expr->u.op.b, prec_primary)); |
122 | if (expr->op == op_sin) |
123 | return unparse_fn("sin", expr); |
124 | if (expr->op == op_cos) |
125 | return unparse_fn("cos", expr); |
126 | if (expr->op == op_sqrt) |
127 | return unparse_fn("sqrt", expr); |
128 | abort(); |
129 | } |
130 | |
131 | |
132 | char *unparse(const struct expr *expr) |
133 | { |
134 | return expr ? unparse_op(expr, prec_add) : stralloc(""); |
135 | } |
136 |
Branches:
master