1 | // This file is part of SmallBASIC |
2 | // |
3 | // inlined hotspots |
4 | // |
5 | // This program is distributed under the terms of the GPL v2.0 or later |
6 | // Download the GNU Public License (GPL) from www.gnu.org |
7 | // |
8 | // Copyright(C) 2014 Chris Warren-Smith |
9 | |
10 | #include "include/var_map.h" |
11 | #include "common/var_eval.h" |
12 | |
13 | void err_evsyntax(void); |
14 | void err_varisarray(void); |
15 | void err_varisnotarray(void); |
16 | void err_notavar(void); |
17 | |
18 | /** |
19 | * @ingroup var |
20 | * |
21 | * returns the next integer and moves the IP 4 bytes forward. |
22 | * |
23 | * R(long int) <- Code[IP]; IP+=j |
24 | */ |
25 | static inline uint32_t code_getnext32(void) { |
26 | uint32_t v; |
27 | memcpy(&v, prog_source + prog_ip, 4); |
28 | prog_ip += 4; |
29 | return v; |
30 | } |
31 | |
32 | /** |
33 | * @ingroup var |
34 | * |
35 | * returns the next 64bit and moves the instruction pointer to the next instruction |
36 | * |
37 | * R(double) <- Code[IP]; IP+=j |
38 | */ |
39 | static inline var_num_t code_getreal() { |
40 | var_num_t v; |
41 | memcpy(&v, prog_source + prog_ip, sizeof(var_num_t)); |
42 | prog_ip += sizeof(var_num_t); |
43 | return v; |
44 | } |
45 | |
46 | /** |
47 | * @ingroup var |
48 | * |
49 | * returns the next var_int_t and moves the instruction pointer to the next instruction |
50 | */ |
51 | static inline var_int_t code_getint() { |
52 | var_int_t v; |
53 | memcpy(&v, prog_source + prog_ip, sizeof(var_int_t)); |
54 | prog_ip += sizeof(var_int_t); |
55 | return v; |
56 | } |
57 | |
58 | /** |
59 | * @ingroup var |
60 | * |
61 | * returns the floating-point value of a var. |
62 | * if v is string it will converted to double. |
63 | * |
64 | * @param v the variable |
65 | * @return the numeric value of a variable |
66 | */ |
67 | static inline var_num_t v_getval(var_t *v) { |
68 | switch (v ? v->type : -1) { |
69 | case V_INT: |
70 | return v->v.i; |
71 | case V_NUM: |
72 | return v->v.n; |
73 | case V_STR: |
74 | return numexpr_sb_strtof(v->v.p.ptr); |
75 | case V_PTR: |
76 | return v->v.ap.p; |
77 | case V_MAP: |
78 | return map_to_int(v); |
79 | default: |
80 | if (v == NULL) { |
81 | err_evsyntax(); |
82 | } else { |
83 | err_varisarray(); |
84 | } |
85 | } |
86 | return 0; |
87 | } |
88 | |
89 | /** |
90 | * @ingroup var |
91 | * |
92 | * returns the integer value of a var. |
93 | * if v is string it will converted to integer. |
94 | * |
95 | * @param v the variable |
96 | * @return the integer value of a variable |
97 | */ |
98 | static inline var_int_t v_igetval(var_t *v) { |
99 | switch (v ? v->type : -1) { |
100 | case V_INT: |
101 | return v->v.i; |
102 | case V_NUM: |
103 | return v->v.n; |
104 | case V_STR: |
105 | return numexpr_strtol(v->v.p.ptr); |
106 | case V_PTR: |
107 | return v->v.ap.p; |
108 | case V_MAP: |
109 | return map_to_int(v); |
110 | default: |
111 | if (v == NULL) { |
112 | err_evsyntax(); |
113 | } else { |
114 | err_varisarray(); |
115 | } |
116 | } |
117 | return 0; |
118 | } |
119 | |
120 | /** |
121 | * @ingroup exec |
122 | * |
123 | * variant of code_getvarptr() derefence until left parenthesis found |
124 | * |
125 | * R(var_t*) <- Code[IP]; IP += 2; |
126 | * |
127 | * @return the var_t* |
128 | */ |
129 | static inline var_t *code_getvarptr_parens(int until_parens) { |
130 | var_t *var_p = NULL; |
131 | |
132 | if (code_peek() == kwTYPE_VAR) { |
133 | code_skipnext(); |
134 | var_p = tvar[code_getaddr()]; |
135 | if (code_peek() == kwTYPE_UDS_EL) { |
136 | var_p = code_resolve_map(var_p, until_parens); |
137 | } else { |
138 | switch (var_p->type) { |
139 | case V_MAP: |
140 | var_p = code_resolve_map(var_p, until_parens); |
141 | break; |
142 | case V_ARRAY: |
143 | var_p = code_resolve_varptr(var_p, until_parens); |
144 | break; |
145 | default: |
146 | if (!until_parens && code_peek() == kwTYPE_LEVEL_BEGIN) { |
147 | err_varisnotarray(); |
148 | } |
149 | } |
150 | } |
151 | } |
152 | |
153 | if (var_p == NULL && !prog_error) { |
154 | err_notavar(); |
155 | return tvar[0]; |
156 | } |
157 | |
158 | return var_p; |
159 | } |
160 | |
161 | /** |
162 | * @ingroup var |
163 | * |
164 | * initialize a variable |
165 | * |
166 | * @param v the variable |
167 | */ |
168 | static inline void v_init(var_t *v) { |
169 | v->type = V_INT; |
170 | v->const_flag = 0; |
171 | v->v.i = 0; |
172 | } |
173 | |
174 | /** |
175 | * @ingroup var |
176 | * |
177 | * frees the var or releases it back into the pool |
178 | */ |
179 | static inline void v_detach(var_t *v) { |
180 | if (v->pooled) { |
181 | v_pool_free(v); |
182 | } else { |
183 | free(v); |
184 | } |
185 | } |
186 | |
187 | /** |
188 | * @ingroup var |
189 | * |
190 | * free variable's data. |
191 | * |
192 | * @warning it frees only the data, not the variable |
193 | * |
194 | * @param v the variable |
195 | */ |
196 | static inline void v_free(var_t *v) { |
197 | switch (v->type) { |
198 | case V_STR: |
199 | if (v->v.p.owner) { |
200 | free(v->v.p.ptr); |
201 | } |
202 | break; |
203 | case V_ARRAY: |
204 | v_array_free(v); |
205 | break; |
206 | case V_MAP: |
207 | map_free(v); |
208 | break; |
209 | } |
210 | v_init(v); |
211 | } |
212 | |