types refactoring
[m6w6/ext-psi] / src / types / num_exp.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <assert.h>
36
37 #include "data.h"
38 #include "calc.h"
39
40 num_exp *init_num_exp(token_t t, void *num) {
41 num_exp *exp = calloc(1, sizeof(*exp));
42 switch (exp->t = t) {
43 case PSI_T_NUMBER:
44 case PSI_T_NSNAME:
45 exp->u.numb = strdup(num);
46 break;
47 case PSI_T_NAME:
48 exp->u.dvar = num;
49 break;
50 default:
51 assert(0);
52 }
53 return exp;
54 }
55
56 num_exp *copy_num_exp(num_exp *exp) {
57 decl_var *dvar;
58 num_exp *num = calloc(1, sizeof(*num));
59 memcpy(num, exp, sizeof(*num));
60 if (num->token) {
61 num->token = psi_token_copy(num->token);
62 }
63 if (num->operand) {
64 num->operand = copy_num_exp(num->operand);
65 }
66 switch (num->t) {
67 case PSI_T_NUMBER:
68 case PSI_T_NSNAME:
69 num->u.numb = strdup(num->u.numb);
70 break;
71 case PSI_T_NAME:
72 dvar = init_decl_var(num->u.dvar->name, num->u.dvar->pointer_level,
73 num->u.dvar->array_size);
74 dvar->arg = num->u.dvar->arg;
75 if (num->u.dvar->token) {
76 dvar->token = psi_token_copy(num->u.dvar->token);
77 }
78 num->u.dvar = dvar;
79 break;
80 default:
81 assert(0);
82 }
83 return num;
84 }
85
86 void free_num_exp(num_exp *exp) {
87 if (exp->token) {
88 free(exp->token);
89 }
90 switch (exp->t) {
91 case PSI_T_NUMBER:
92 free(exp->u.numb);
93 break;
94 case PSI_T_NSNAME:
95 break;
96 case PSI_T_NAME:
97 free_decl_var(exp->u.dvar);
98 break;
99 case PSI_T_ENUM:
100 break;
101 default:
102 assert(0);
103 }
104 if (exp->operand) {
105 free_num_exp(exp->operand);
106 }
107 free(exp);
108 }
109
110 void dump_num_exp(int fd, num_exp *exp) {
111 while (exp) {
112 switch (exp->t) {
113 case PSI_T_NUMBER:
114 dprintf(fd, "%s", exp->u.numb);
115 break;
116 case PSI_T_NSNAME:
117 dprintf(fd, "%s", exp->u.cnst->name);
118 break;
119 case PSI_T_NAME:
120 dump_decl_var(fd, exp->u.dvar);
121 break;
122 case PSI_T_ENUM:
123 dprintf(fd, "%s", exp->u.enm->name);
124 break;
125 default:
126 assert(0);
127 }
128 if (exp->operand) {
129 char op;
130
131 switch (exp->operator) {
132 case PSI_T_PLUS: op = '+'; break;
133 case PSI_T_MINUS: op = '-'; break;
134 case PSI_T_ASTERISK:op = '*'; break;
135 case PSI_T_SLASH: op = '/'; break;
136 default:
137 assert(0);
138 }
139 dprintf(fd, " %c ", op);
140 }
141 exp = exp->operand;
142 }
143 }
144
145 static inline constant *locate_num_exp_constant(num_exp *exp, constants *consts) {
146 size_t i;
147
148 for (i = 0; i < consts->count; ++i) {
149 constant *cnst = consts->list[i];
150
151 if (!strcmp(cnst->name, exp->u.numb)) {
152 free(exp->u.numb);
153 return exp->u.cnst = cnst;
154 }
155 }
156
157 return NULL;
158 }
159 static inline decl_enum_item *locate_num_exp_enum_item_ex(num_exp *exp, decl_enum *e) {
160 size_t k;
161
162 if (e) for (k = 0; k < e->items->count; ++k) {
163 decl_enum_item *i = e->items->list[k];
164
165 if (!strcmp(i->name, exp->u.dvar->name)) {
166 free_decl_var(exp->u.dvar);
167 exp->t = PSI_T_ENUM;
168 exp->u.enm = i;
169 return i;
170 }
171 }
172 return NULL;
173 }
174 static inline decl_enum_item *locate_num_exp_enum_item(num_exp *exp, decl_enums *enums) {
175 size_t j;
176
177 if (enums) for (j = 0; j < enums->count; ++j) {
178 decl_enum *e = enums->list[j];
179 decl_enum_item *i = locate_num_exp_enum_item_ex(exp, e);
180
181 if (i) {
182 return i;
183 }
184 }
185 return NULL;
186 }
187
188 int validate_num_exp(struct psi_data *data, num_exp *exp, decl_args *dargs, decl_arg *func, decl_enum *enm) {
189 if (exp->operand) {
190 switch (exp->operator) {
191 case PSI_T_PLUS:
192 exp->calculator = psi_calc_add;
193 break;
194 case PSI_T_MINUS:
195 exp->calculator = psi_calc_sub;
196 break;
197 case PSI_T_ASTERISK:
198 exp->calculator = psi_calc_mul;
199 break;
200 case PSI_T_SLASH:
201 exp->calculator = psi_calc_div;
202 break;
203 default:
204 assert(0);
205 }
206 if (!validate_num_exp(data, exp->operand, dargs, func, enm)) {
207 return 0;
208 }
209 }
210 switch (exp->t) {
211 case PSI_T_NAME:
212 if (!locate_decl_var_arg(exp->u.dvar, dargs, func)) {
213 if (!locate_num_exp_enum_item(exp, data->enums) && !locate_num_exp_enum_item_ex(exp, enm)) {
214 data->error(data, exp->token, PSI_WARNING, "Unknown variable '%s' in numeric expression",
215 exp->u.dvar->name);
216 return 0;
217 }
218 }
219 return 1;
220 case PSI_T_NSNAME:
221 if (!locate_num_exp_constant(exp, data->consts)) {
222 data->error(data, exp->token, PSI_WARNING, "Unknown constant '%s' in numeric expression",
223 exp->u.numb);
224 return 0;
225 }
226 return 1;
227 case PSI_T_NUMBER:
228 case PSI_T_ENUM:
229 return 1;
230 default:
231 return 0;
232 }
233 }