Rev 185 | Rev 198 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | toby | 1 | /* |
18 | toby | 2 | This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop |
192 | daniel-mar | 3 | Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au |
4 | Copyright (C) 2018-2019 Daniel Marschall, ViaThinkSoft |
||
2 | toby | 5 | |
6 | This program is free software; you can redistribute it and/or modify |
||
150 | dmarschall | 7 | it under the terms of the GNU General Public License as published by |
2 | toby | 8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. |
||
10 | |||
11 | This program is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | GNU General Public License for more details. |
||
15 | |||
150 | dmarschall | 16 | You should have received a copy of the GNU General Public License |
2 | toby | 17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
19 | */ |
||
20 | |||
21 | #include <stdlib.h> |
||
22 | #include <stdio.h> |
||
23 | #include <math.h> |
||
24 | |||
25 | // The following ugly workaround is obviated by Carbon StdCLib headers; |
||
26 | // see: http://developer.apple.com/tools/mpw-tools/relnotes/carbonstdclib.html |
||
27 | // (via http://developer.apple.com/tools/mpw-tools/updates.html ) |
||
28 | |||
29 | //#ifdef TARGET_API_MAC_CARBON |
||
30 | // /* can't use StdCLib ctype.h, it refers to symbols which aren't in OS X stdclib */ |
||
31 | // int isprint(int); |
||
32 | //#else |
||
33 | #include <ctype.h> |
||
34 | //#endif |
||
35 | |||
36 | #include "node.h" |
||
37 | #include "y.tab.h" |
||
38 | #include "funcs.h" |
||
39 | |||
40 | void freenodes(struct node *p); |
||
41 | |||
42 | int varused[0x100],allocs; /* one flag per special variable, indicating if it's used */ |
||
43 | value_type var[0x100]; |
||
44 | |||
45 | struct node *node_list; |
||
46 | |||
47 | struct node *newnode(int k){ |
||
48 | struct node *p; |
||
49 | int i; |
||
50 | |||
51 | if(NEW(p)){ |
||
52 | #ifdef DEBUG |
||
53 | // fprintf(stderr,"NEW(%#x)\n",p); |
||
54 | ++allocs; |
||
55 | #endif |
||
56 | p->kind = k; |
||
57 | for( i = 0 ; i < MAXCHILDREN ; ++i ) |
||
58 | p->child[i] = 0; |
||
150 | dmarschall | 59 | |
2 | toby | 60 | /* add this new node to the list of allocated nodes */ |
61 | p->next = node_list; |
||
62 | node_list = p; |
||
63 | } |
||
64 | return p; |
||
65 | } |
||
66 | |||
67 | void freenodes(struct node *p){ |
||
68 | /* undo recorded allocations */ |
||
69 | if(p){ |
||
70 | freenodes(p->next); |
||
71 | free(p); |
||
72 | #ifdef DEBUG |
||
73 | // fprintf(stderr,"FREE(%#x)\n",p); |
||
74 | --allocs; |
||
75 | #endif |
||
76 | } |
||
77 | } |
||
78 | void freeallnodes(){ |
||
79 | freenodes(node_list); |
||
80 | node_list = 0; |
||
81 | } |
||
82 | |||
83 | /* pretty-print the tree */ |
||
84 | |||
85 | void dumptree(struct node *root,int level){ |
||
86 | int i; |
||
87 | |||
88 | if(level>20) |
||
89 | puts("## dumptree: sorry, not going deeper than this."); |
||
90 | else |
||
91 | if(root){ |
||
92 | for(i=level;i--;) |
||
93 | putchar('\t'); |
||
94 | switch(root->kind){ |
||
150 | dmarschall | 95 | case TOK_NUM: |
2 | toby | 96 | #ifdef FP_VALUE |
150 | dmarschall | 97 | printf("constant: %g\n",root->v.value); |
2 | toby | 98 | #else |
150 | dmarschall | 99 | printf("constant: %ld\n",root->v.value); |
2 | toby | 100 | #endif |
101 | break; |
||
150 | dmarschall | 102 | case TOK_SPECIALVAR: |
103 | printf("special variable: %c\n",root->v.specialvar); |
||
2 | toby | 104 | break; |
150 | dmarschall | 105 | case TOK_VAR: |
2 | toby | 106 | #ifdef FP_VALUE |
150 | dmarschall | 107 | printf("variable: %s (%g)\n",root->v.sym->name,*root->v.sym->pvar); |
2 | toby | 108 | #else |
150 | dmarschall | 109 | printf("variable: %s (%ld)\n",root->v.sym->name,*root->v.sym->pvar); |
2 | toby | 110 | #endif |
111 | break; |
||
150 | dmarschall | 112 | case TOK_FN1: |
113 | case TOK_FN2: |
||
114 | case TOK_FN3: |
||
115 | printf("function: %s\n",root->v.sym->name); |
||
2 | toby | 116 | break; |
150 | dmarschall | 117 | default: |
118 | printf(isprint(root->kind) ? "operator: %c\n" : "operator: %d\n",root->kind); |
||
2 | toby | 119 | break; |
120 | } |
||
121 | ++level; |
||
122 | for( i = 0 ; i < MAXCHILDREN ; ++i ) |
||
123 | dumptree(root->child[i],level); |
||
124 | } |
||
150 | dmarschall | 125 | |
2 | toby | 126 | } |
127 | |||
128 | /* evaluate the expression tree (using current values of variables) */ |
||
129 | |||
130 | value_type eval(struct node *root){ |
||
131 | value_type t; |
||
132 | if(root){ |
||
133 | switch(root->kind){ |
||
150 | dmarschall | 134 | case TOK_NUM: return root->v.value; |
2 | toby | 135 | case TOK_SPECIALVAR: return var[root->v.specialvar]; |
136 | case TOK_VAR: return *root->v.sym->pvar; |
||
137 | case TOK_FN1: return root->v.sym->fn(eval(root->child[0])); |
||
138 | case TOK_FN2: return root->v.sym->fn( |
||
62 | toby | 139 | eval(root->child[0]), |
140 | eval(root->child[1]) ); |
||
2 | toby | 141 | case TOK_FN3: return root->v.sym->fn( |
62 | toby | 142 | eval(root->child[0]), |
143 | eval(root->child[1]), |
||
144 | eval(root->child[2]) ); |
||
2 | toby | 145 | case TOK_FN4: return root->v.sym->fn( |
62 | toby | 146 | eval(root->child[0]), |
147 | eval(root->child[1]), |
||
148 | eval(root->child[2]), |
||
149 | eval(root->child[3]) ); |
||
2 | toby | 150 | case TOK_FN5: return root->v.sym->fn( |
62 | toby | 151 | eval(root->child[0]), |
152 | eval(root->child[1]), |
||
153 | eval(root->child[2]), |
||
154 | eval(root->child[3]), |
||
155 | eval(root->child[4]) ); |
||
2 | toby | 156 | case TOK_FN10: return root->v.sym->fn( |
62 | toby | 157 | eval(root->child[0]), |
158 | eval(root->child[1]), |
||
159 | eval(root->child[2]), |
||
160 | eval(root->child[3]), |
||
161 | eval(root->child[4]), |
||
162 | eval(root->child[5]), |
||
163 | eval(root->child[6]), |
||
164 | eval(root->child[7]), |
||
165 | eval(root->child[8]), |
||
166 | eval(root->child[9]) ); |
||
2 | toby | 167 | |
168 | case '+': return eval(root->child[0]) + eval(root->child[1]); |
||
169 | case '-': return eval(root->child[0]) - eval(root->child[1]); |
||
170 | case '*': return eval(root->child[0]) * eval(root->child[1]); |
||
171 | case '/': t = eval(root->child[1]); return t ? eval(root->child[0]) / t : 0; |
||
172 | case '%': t = eval(root->child[1]); return t ? eval(root->child[0]) % t : 0; |
||
185 | dmarschall | 173 | case EXP: return (value_type)(pow(eval(root->child[0]), eval(root->child[1]))); |
2 | toby | 174 | |
175 | case EQ: return eval(root->child[0]) == eval(root->child[1]); |
||
176 | case NE: return eval(root->child[0]) != eval(root->child[1]); |
||
177 | case '<': return eval(root->child[0]) < eval(root->child[1]); |
||
178 | case LE: return eval(root->child[0]) <= eval(root->child[1]); |
||
179 | case '>': return eval(root->child[0]) > eval(root->child[1]); |
||
180 | case GE: return eval(root->child[0]) >= eval(root->child[1]); |
||
181 | |||
182 | case LOGAND: return eval(root->child[0]) && eval(root->child[1]); |
||
183 | case LOGOR: return eval(root->child[0]) || eval(root->child[1]); |
||
184 | case '!': return !eval(root->child[0]); |
||
185 | |||
186 | case '?': return eval(root->child[0]) ? eval(root->child[1]) : eval(root->child[2]); |
||
187 | |||
188 | case '&': return eval(root->child[0]) & eval(root->child[1]); |
||
189 | case '^': return eval(root->child[0]) ^ eval(root->child[1]); |
||
190 | case '|': return eval(root->child[0]) | eval(root->child[1]); |
||
191 | case SHLEFT: return eval(root->child[0]) << eval(root->child[1]); |
||
192 | case SHRIGHT: return eval(root->child[0]) >> eval(root->child[1]); |
||
193 | case '~': return ~eval(root->child[0]); |
||
194 | |||
195 | case ',': eval(root->child[0]); return eval(root->child[1]); |
||
196 | } |
||
197 | } |
||
185 | dmarschall | 198 | #ifdef FP_VALUE |
2 | toby | 199 | return 0.; |
185 | dmarschall | 200 | #else |
201 | return 0; |
||
202 | #endif |
||
2 | toby | 203 | } |
204 | |||
205 | /* free the memory for a tree's nodes */ |
||
206 | |||
207 | void freetree(struct node *root){ |
||
208 | int i; |
||
209 | |||
210 | if(root){ |
||
211 | for( i = 0 ; i < MAXCHILDREN ; ++i ) |
||
212 | freetree(root->child[i]); |
||
213 | free(root); |
||
214 | } |
||
215 | } |
||
216 | |||
217 | /* tabulate usage of special variables, or any invocations of src()/rad()/cnv(), in the tree */ |
||
218 | |||
150 | dmarschall | 219 | void checkvars(struct node*p,int f[],int *cnv,int *srcrad /* ,int *mapused */, int *state_changing_funcs_used ){ |
2 | toby | 220 | int i; |
150 | dmarschall | 221 | |
2 | toby | 222 | if(p){ |
223 | if(p->kind==TOK_SPECIALVAR) |
||
224 | f[p->v.specialvar] = 1; |
||
71 | toby | 225 | else if(p->kind==TOK_FN3 && (p->v.sym->fn == (pfunc_type)ff_src || p->v.sym->fn == (pfunc_type)ff_rad)) |
2 | toby | 226 | *srcrad = 1; |
71 | toby | 227 | else if(p->kind==TOK_FN10 && p->v.sym->fn == (pfunc_type)ff_cnv) |
228 | *cnv = 1; |
||
2 | toby | 229 | // else if(p->kind==TOK_FN2 && (p->v.sym->fn == (pfunc_type)ff_map)) |
230 | // *mapused = 1; |
||
150 | dmarschall | 231 | else if ((p->kind==TOK_FN2 && p->v.sym->fn == (pfunc_type)ff_put) || |
232 | (p->kind==TOK_FN1 && p->v.sym->fn == (pfunc_type)ff_rnd) || |
||
233 | (p->kind==TOK_FN1 && p->v.sym->fn == (pfunc_type)ff_rst)) |
||
234 | *state_changing_funcs_used = 1; |
||
2 | toby | 235 | for( i = 0 ; i < MAXCHILDREN ; ++i ) |
150 | dmarschall | 236 | checkvars(p->child[i],f,cnv,srcrad/*,mapused*/,state_changing_funcs_used); |
2 | toby | 237 | } |
238 | } |