Rev 206 | Rev 259 | 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 |
206 | daniel-mar | 4 | Copyright (C) 2018-2021 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; |
||
237 | daniel-mar | 26 | // see: https://web.archive.org/web/20041031134219/http://developer.apple.com/tools/mpw-tools/relnotes/carbonstdclib.html |
2 | toby | 27 | |
28 | //#ifdef TARGET_API_MAC_CARBON |
||
29 | // /* can't use StdCLib ctype.h, it refers to symbols which aren't in OS X stdclib */ |
||
30 | // int isprint(int); |
||
31 | //#else |
||
32 | #include <ctype.h> |
||
33 | //#endif |
||
34 | |||
35 | #include "node.h" |
||
36 | #include "y.tab.h" |
||
37 | #include "funcs.h" |
||
38 | |||
39 | void freenodes(struct node *p); |
||
40 | |||
41 | int varused[0x100],allocs; /* one flag per special variable, indicating if it's used */ |
||
42 | value_type var[0x100]; |
||
43 | |||
44 | struct node *node_list; |
||
45 | |||
46 | struct node *newnode(int k){ |
||
47 | struct node *p; |
||
48 | int i; |
||
49 | |||
198 | daniel-mar | 50 | if( (p = (struct node*)malloc(sizeof(struct node))) ){ |
2 | toby | 51 | #ifdef DEBUG |
52 | // fprintf(stderr,"NEW(%#x)\n",p); |
||
53 | ++allocs; |
||
54 | #endif |
||
55 | p->kind = k; |
||
56 | for( i = 0 ; i < MAXCHILDREN ; ++i ) |
||
57 | p->child[i] = 0; |
||
150 | dmarschall | 58 | |
2 | toby | 59 | /* add this new node to the list of allocated nodes */ |
60 | p->next = node_list; |
||
61 | node_list = p; |
||
62 | } |
||
63 | return p; |
||
64 | } |
||
65 | |||
66 | void freenodes(struct node *p){ |
||
67 | /* undo recorded allocations */ |
||
68 | if(p){ |
||
69 | freenodes(p->next); |
||
70 | free(p); |
||
71 | #ifdef DEBUG |
||
72 | // fprintf(stderr,"FREE(%#x)\n",p); |
||
73 | --allocs; |
||
74 | #endif |
||
75 | } |
||
76 | } |
||
77 | void freeallnodes(){ |
||
78 | freenodes(node_list); |
||
79 | node_list = 0; |
||
80 | } |
||
81 | |||
82 | /* pretty-print the tree */ |
||
83 | |||
84 | void dumptree(struct node *root,int level){ |
||
85 | int i; |
||
86 | |||
87 | if(level>20) |
||
88 | puts("## dumptree: sorry, not going deeper than this."); |
||
89 | else |
||
90 | if(root){ |
||
91 | for(i=level;i--;) |
||
92 | putchar('\t'); |
||
93 | switch(root->kind){ |
||
150 | dmarschall | 94 | case TOK_NUM: |
2 | toby | 95 | #ifdef FP_VALUE |
150 | dmarschall | 96 | printf("constant: %g\n",root->v.value); |
2 | toby | 97 | #else |
150 | dmarschall | 98 | printf("constant: %ld\n",root->v.value); |
2 | toby | 99 | #endif |
100 | break; |
||
150 | dmarschall | 101 | case TOK_SPECIALVAR: |
102 | printf("special variable: %c\n",root->v.specialvar); |
||
2 | toby | 103 | break; |
150 | dmarschall | 104 | case TOK_VAR: |
2 | toby | 105 | #ifdef FP_VALUE |
150 | dmarschall | 106 | printf("variable: %s (%g)\n",root->v.sym->name,*root->v.sym->pvar); |
2 | toby | 107 | #else |
150 | dmarschall | 108 | printf("variable: %s (%ld)\n",root->v.sym->name,*root->v.sym->pvar); |
2 | toby | 109 | #endif |
110 | break; |
||
150 | dmarschall | 111 | case TOK_FN1: |
112 | case TOK_FN2: |
||
113 | case TOK_FN3: |
||
114 | printf("function: %s\n",root->v.sym->name); |
||
2 | toby | 115 | break; |
150 | dmarschall | 116 | default: |
117 | printf(isprint(root->kind) ? "operator: %c\n" : "operator: %d\n",root->kind); |
||
2 | toby | 118 | break; |
119 | } |
||
120 | ++level; |
||
121 | for( i = 0 ; i < MAXCHILDREN ; ++i ) |
||
122 | dumptree(root->child[i],level); |
||
123 | } |
||
150 | dmarschall | 124 | |
2 | toby | 125 | } |
126 | |||
127 | /* evaluate the expression tree (using current values of variables) */ |
||
128 | |||
129 | value_type eval(struct node *root){ |
||
130 | value_type t; |
||
131 | if(root){ |
||
132 | switch(root->kind){ |
||
150 | dmarschall | 133 | case TOK_NUM: return root->v.value; |
2 | toby | 134 | case TOK_SPECIALVAR: return var[root->v.specialvar]; |
135 | case TOK_VAR: return *root->v.sym->pvar; |
||
136 | case TOK_FN1: return root->v.sym->fn(eval(root->child[0])); |
||
137 | case TOK_FN2: return root->v.sym->fn( |
||
62 | toby | 138 | eval(root->child[0]), |
139 | eval(root->child[1]) ); |
||
2 | toby | 140 | case TOK_FN3: return root->v.sym->fn( |
62 | toby | 141 | eval(root->child[0]), |
142 | eval(root->child[1]), |
||
143 | eval(root->child[2]) ); |
||
2 | toby | 144 | case TOK_FN4: return root->v.sym->fn( |
62 | toby | 145 | eval(root->child[0]), |
146 | eval(root->child[1]), |
||
147 | eval(root->child[2]), |
||
148 | eval(root->child[3]) ); |
||
2 | toby | 149 | case TOK_FN5: return root->v.sym->fn( |
62 | toby | 150 | eval(root->child[0]), |
151 | eval(root->child[1]), |
||
152 | eval(root->child[2]), |
||
153 | eval(root->child[3]), |
||
154 | eval(root->child[4]) ); |
||
2 | toby | 155 | case TOK_FN10: return root->v.sym->fn( |
62 | toby | 156 | eval(root->child[0]), |
157 | eval(root->child[1]), |
||
158 | eval(root->child[2]), |
||
159 | eval(root->child[3]), |
||
160 | eval(root->child[4]), |
||
161 | eval(root->child[5]), |
||
162 | eval(root->child[6]), |
||
163 | eval(root->child[7]), |
||
164 | eval(root->child[8]), |
||
165 | eval(root->child[9]) ); |
||
2 | toby | 166 | |
167 | case '+': return eval(root->child[0]) + eval(root->child[1]); |
||
168 | case '-': return eval(root->child[0]) - eval(root->child[1]); |
||
169 | case '*': return eval(root->child[0]) * eval(root->child[1]); |
||
170 | case '/': t = eval(root->child[1]); return t ? eval(root->child[0]) / t : 0; |
||
171 | case '%': t = eval(root->child[1]); return t ? eval(root->child[0]) % t : 0; |
||
185 | dmarschall | 172 | case EXP: return (value_type)(pow(eval(root->child[0]), eval(root->child[1]))); |
2 | toby | 173 | |
174 | case EQ: return eval(root->child[0]) == eval(root->child[1]); |
||
175 | case NE: return eval(root->child[0]) != eval(root->child[1]); |
||
176 | case '<': return eval(root->child[0]) < eval(root->child[1]); |
||
177 | case LE: return eval(root->child[0]) <= eval(root->child[1]); |
||
178 | case '>': return eval(root->child[0]) > eval(root->child[1]); |
||
179 | case GE: return eval(root->child[0]) >= eval(root->child[1]); |
||
180 | |||
181 | case LOGAND: return eval(root->child[0]) && eval(root->child[1]); |
||
182 | case LOGOR: return eval(root->child[0]) || eval(root->child[1]); |
||
183 | case '!': return !eval(root->child[0]); |
||
184 | |||
185 | case '?': return eval(root->child[0]) ? eval(root->child[1]) : eval(root->child[2]); |
||
186 | |||
187 | case '&': return eval(root->child[0]) & eval(root->child[1]); |
||
188 | case '^': return eval(root->child[0]) ^ eval(root->child[1]); |
||
189 | case '|': return eval(root->child[0]) | eval(root->child[1]); |
||
190 | case SHLEFT: return eval(root->child[0]) << eval(root->child[1]); |
||
191 | case SHRIGHT: return eval(root->child[0]) >> eval(root->child[1]); |
||
192 | case '~': return ~eval(root->child[0]); |
||
193 | |||
194 | case ',': eval(root->child[0]); return eval(root->child[1]); |
||
195 | } |
||
196 | } |
||
185 | dmarschall | 197 | #ifdef FP_VALUE |
2 | toby | 198 | return 0.; |
185 | dmarschall | 199 | #else |
200 | return 0; |
||
201 | #endif |
||
2 | toby | 202 | } |
203 | |||
204 | /* free the memory for a tree's nodes */ |
||
205 | |||
206 | void freetree(struct node *root){ |
||
207 | int i; |
||
208 | |||
209 | if(root){ |
||
210 | for( i = 0 ; i < MAXCHILDREN ; ++i ) |
||
211 | freetree(root->child[i]); |
||
212 | free(root); |
||
213 | } |
||
214 | } |
||
215 | |||
216 | /* tabulate usage of special variables, or any invocations of src()/rad()/cnv(), in the tree */ |
||
217 | |||
150 | dmarschall | 218 | void checkvars(struct node*p,int f[],int *cnv,int *srcrad /* ,int *mapused */, int *state_changing_funcs_used ){ |
2 | toby | 219 | int i; |
150 | dmarschall | 220 | |
2 | toby | 221 | if(p){ |
222 | if(p->kind==TOK_SPECIALVAR) |
||
223 | f[p->v.specialvar] = 1; |
||
71 | toby | 224 | else if(p->kind==TOK_FN3 && (p->v.sym->fn == (pfunc_type)ff_src || p->v.sym->fn == (pfunc_type)ff_rad)) |
2 | toby | 225 | *srcrad = 1; |
71 | toby | 226 | else if(p->kind==TOK_FN10 && p->v.sym->fn == (pfunc_type)ff_cnv) |
227 | *cnv = 1; |
||
2 | toby | 228 | // else if(p->kind==TOK_FN2 && (p->v.sym->fn == (pfunc_type)ff_map)) |
229 | // *mapused = 1; |
||
150 | dmarschall | 230 | else if ((p->kind==TOK_FN2 && p->v.sym->fn == (pfunc_type)ff_put) || |
231 | (p->kind==TOK_FN1 && p->v.sym->fn == (pfunc_type)ff_rnd) || |
||
232 | (p->kind==TOK_FN1 && p->v.sym->fn == (pfunc_type)ff_rst)) |
||
233 | *state_changing_funcs_used = 1; |
||
2 | toby | 234 | for( i = 0 ; i < MAXCHILDREN ; ++i ) |
150 | dmarschall | 235 | checkvars(p->child[i],f,cnv,srcrad/*,mapused*/,state_changing_funcs_used); |
2 | toby | 236 | } |
237 | } |