1 | #include "madx.h" |
---|
2 | |
---|
3 | static int |
---|
4 | is_operand(char c) { |
---|
5 | return (isalnum(c) || c == '_' || c == '.'); |
---|
6 | } |
---|
7 | |
---|
8 | static int |
---|
9 | is_operator(char c) { |
---|
10 | return strchr("-+*/^", c) != 0; |
---|
11 | } |
---|
12 | |
---|
13 | static int |
---|
14 | is_expr_start(char c) { |
---|
15 | return strchr("-+(",c) || is_operand(c); |
---|
16 | } |
---|
17 | |
---|
18 | #if 0 // not used... |
---|
19 | /* combine two parameters using compound expression */ |
---|
20 | static struct expression* |
---|
21 | comb_param(struct command_parameter* param1, char* op, struct command_parameter* param2) |
---|
22 | { |
---|
23 | return compound_expr(param1->expr,param1->double_value,op,param2->expr,param2->double_value); |
---|
24 | } |
---|
25 | #endif |
---|
26 | |
---|
27 | static double |
---|
28 | combine_expr_expr(struct expression* exp1, char* oper, |
---|
29 | struct expression* exp2, struct expression** comb_exp) |
---|
30 | { |
---|
31 | strcpy(c_dum->c, exp1->string); |
---|
32 | strcat(c_dum->c, oper); |
---|
33 | strcat(c_dum->c, exp2->string); |
---|
34 | mysplit(c_dum->c, tmp_p_array); |
---|
35 | *comb_exp = make_expression(tmp_p_array->curr, tmp_p_array->p); |
---|
36 | return expression_value(*comb_exp, 2); |
---|
37 | } |
---|
38 | |
---|
39 | static double |
---|
40 | combine_expr_val(struct expression* exp1, char* oper, double val2, struct expression** comb_exp) |
---|
41 | { |
---|
42 | strcpy(c_dum->c, exp1->string); |
---|
43 | sprintf(aux_buff->c, "%.12g", val2); |
---|
44 | strcat(c_dum->c, oper); |
---|
45 | strcat(c_dum->c, aux_buff->c); |
---|
46 | mysplit(c_dum->c, tmp_p_array); |
---|
47 | *comb_exp = make_expression(tmp_p_array->curr, tmp_p_array->p); |
---|
48 | return expression_value(*comb_exp, 2); |
---|
49 | } |
---|
50 | |
---|
51 | static double |
---|
52 | combine_val_expr(double val1, char* oper, struct expression* exp2, struct expression** comb_exp) |
---|
53 | { |
---|
54 | sprintf(c_dum->c, "%.12g", val1); |
---|
55 | strcat(c_dum->c, oper); |
---|
56 | strcat(c_dum->c, exp2->string); |
---|
57 | mysplit(c_dum->c, tmp_p_array); |
---|
58 | *comb_exp = make_expression(tmp_p_array->curr, tmp_p_array->p); |
---|
59 | return expression_value(*comb_exp, 2); |
---|
60 | } |
---|
61 | |
---|
62 | // public interface |
---|
63 | |
---|
64 | struct expression* |
---|
65 | make_expression(int n, char** toks) |
---|
66 | /* makes an expression from a list of tokens */ |
---|
67 | { |
---|
68 | struct expression* expr = NULL; |
---|
69 | |
---|
70 | if (polish_expr(n, toks) == 0) |
---|
71 | expr = new_expression(join_b(toks, n), deco); |
---|
72 | else warning("Invalid expression starting at:", join_b(toks, n)); |
---|
73 | return expr; |
---|
74 | } |
---|
75 | |
---|
76 | struct expression* |
---|
77 | new_expression(char* in_string, struct int_array* polish) |
---|
78 | { |
---|
79 | char rout_name[] = "new_expression"; |
---|
80 | int j; |
---|
81 | struct expression* ex = mycalloc(rout_name,1,sizeof(struct expression)); |
---|
82 | strcpy(ex->name, "expression"); |
---|
83 | ex->stamp = 123456; |
---|
84 | ex->string = mymalloc(rout_name,strlen(in_string)+1); |
---|
85 | strcpy(ex->string, in_string); |
---|
86 | if (watch_flag) fprintf(debug_file, "creating ++> %s\n", ex->name); |
---|
87 | if (polish != NULL) |
---|
88 | { |
---|
89 | ex->polish = new_int_array(polish->curr); |
---|
90 | ex->polish->curr = polish->curr; |
---|
91 | for (j = 0; j < polish->curr; j++) ex->polish->i[j] = polish->i[j]; |
---|
92 | } |
---|
93 | return ex; |
---|
94 | } |
---|
95 | |
---|
96 | struct expr_list* |
---|
97 | new_expr_list(int length) |
---|
98 | { |
---|
99 | char rout_name[] = "new_expr_list"; |
---|
100 | struct expr_list* ell = mycalloc(rout_name,1, sizeof(struct expr_list)); |
---|
101 | strcpy(ell->name, "expr_list"); |
---|
102 | ell->stamp = 123456; |
---|
103 | if (watch_flag) fprintf(debug_file, "creating ++> %s\n", ell->name); |
---|
104 | ell->list = |
---|
105 | (struct expression**) mycalloc(rout_name,length, sizeof(struct expression*)); |
---|
106 | ell->max = length; |
---|
107 | return ell; |
---|
108 | } |
---|
109 | |
---|
110 | double |
---|
111 | expression_value(struct expression* expr, int flag) /* recursive */ |
---|
112 | /* returns the value of an expression if valid, else zero */ |
---|
113 | { |
---|
114 | double val = zero; |
---|
115 | if (expr->status == 0 || flag == 2) |
---|
116 | { |
---|
117 | if (expr->polish != NULL) |
---|
118 | { |
---|
119 | val = expr->value = polish_value(expr->polish, expr->string); |
---|
120 | expr->status = 1; |
---|
121 | } |
---|
122 | } |
---|
123 | else val = expr->value; |
---|
124 | return val; |
---|
125 | } |
---|
126 | |
---|
127 | struct expression* |
---|
128 | clone_expression(struct expression* p) |
---|
129 | { |
---|
130 | struct expression* clone; |
---|
131 | if (p == NULL) return NULL; |
---|
132 | clone = new_expression(p->string, p->polish); |
---|
133 | clone->status = p->status; |
---|
134 | clone->value = p->value; |
---|
135 | return clone; |
---|
136 | } |
---|
137 | |
---|
138 | struct expr_list* |
---|
139 | clone_expr_list(struct expr_list* p) |
---|
140 | { |
---|
141 | int i; |
---|
142 | struct expr_list* clone; |
---|
143 | if (p == NULL) return NULL; |
---|
144 | clone = new_expr_list(p->curr); |
---|
145 | for (i = 0; i < p->curr; i++) clone->list[i] = clone_expression(p->list[i]); |
---|
146 | clone->curr = p->curr; |
---|
147 | return clone; |
---|
148 | } |
---|
149 | |
---|
150 | struct expression* |
---|
151 | delete_expression(struct expression* expr) |
---|
152 | { |
---|
153 | char rout_name[] = "delete_expression"; |
---|
154 | if (expr == NULL) return NULL; |
---|
155 | if (stamp_flag && expr->stamp != 123456) |
---|
156 | fprintf(stamp_file, "d_ex double delete --> %s\n", expr->name); |
---|
157 | if (watch_flag) fprintf(debug_file, "deleting --> %s\n", expr->name); |
---|
158 | if (expr->polish != NULL) expr->polish = delete_int_array(expr->polish); |
---|
159 | if (expr->string != NULL) myfree(rout_name, expr->string); |
---|
160 | myfree(rout_name, expr); |
---|
161 | return NULL; |
---|
162 | } |
---|
163 | |
---|
164 | struct expr_list* |
---|
165 | delete_expr_list(struct expr_list* exprl) |
---|
166 | { |
---|
167 | char rout_name[] = "delete_expr_list"; |
---|
168 | int i; |
---|
169 | if (exprl == NULL) return NULL; |
---|
170 | if (stamp_flag && exprl->stamp != 123456) |
---|
171 | fprintf(stamp_file, "d_ex_l double delete --> %s\n", exprl->name); |
---|
172 | if (watch_flag) fprintf(debug_file, "deleting --> %s\n", exprl->name); |
---|
173 | if (exprl->list != NULL) |
---|
174 | { |
---|
175 | for (i = 0; i < exprl->curr; i++) |
---|
176 | if (exprl->list[i] != NULL) delete_expression(exprl->list[i]); |
---|
177 | myfree(rout_name, exprl->list); |
---|
178 | } |
---|
179 | myfree(rout_name, exprl); |
---|
180 | return NULL; |
---|
181 | } |
---|
182 | |
---|
183 | void |
---|
184 | grow_expr_list(struct expr_list* p) |
---|
185 | { |
---|
186 | char rout_name[] = "grow_expr_list"; |
---|
187 | struct expression** e_loc = p->list; |
---|
188 | int j, new = 2*p->max; |
---|
189 | p->max = new; |
---|
190 | p->list = mycalloc(rout_name,new, sizeof(struct expression*)); |
---|
191 | for (j = 0; j < p->curr; j++) p->list[j] = e_loc[j]; |
---|
192 | myfree(rout_name, e_loc); |
---|
193 | } |
---|
194 | |
---|
195 | void |
---|
196 | dump_expression(struct expression* ex) |
---|
197 | { |
---|
198 | ex->value = expression_value(ex, 2); |
---|
199 | fprintf(prt_file, v_format("expression: %s :: value: %F\n"), |
---|
200 | ex->string, ex->value); |
---|
201 | } |
---|
202 | |
---|
203 | double |
---|
204 | expr_combine(struct expression* exp1, double val1, char* oper, |
---|
205 | struct expression* exp2, double val2, |
---|
206 | struct expression** exp_comb) |
---|
207 | { |
---|
208 | double val = 0; |
---|
209 | |
---|
210 | if (exp1 == NULL && exp2 == NULL) |
---|
211 | { |
---|
212 | *exp_comb = NULL; |
---|
213 | switch(oper[1]) |
---|
214 | { |
---|
215 | case '+': val = val1 + val2; break; |
---|
216 | case '-': val = val1 - val2; break; |
---|
217 | } |
---|
218 | } |
---|
219 | else if(exp1 == NULL) val = combine_val_expr (val1, oper, exp2, exp_comb); |
---|
220 | else if(exp2 == NULL) val = combine_expr_val (exp1, oper, val2, exp_comb); |
---|
221 | else val = combine_expr_expr(exp1, oper, exp2, exp_comb); |
---|
222 | return val; |
---|
223 | } |
---|
224 | |
---|
225 | void |
---|
226 | update_vector(struct expr_list* ell, struct double_array* da) |
---|
227 | { |
---|
228 | int i; |
---|
229 | for (i = 0; i < ell->curr; i++) |
---|
230 | { |
---|
231 | if (ell->list[i] != NULL) |
---|
232 | { |
---|
233 | while (da->max < i) grow_double_array(da); |
---|
234 | da->a[i] = expression_value(ell->list[i], 2); |
---|
235 | } |
---|
236 | } |
---|
237 | if (da->curr < ell->curr) da->curr = ell->curr; |
---|
238 | } |
---|
239 | |
---|
240 | void |
---|
241 | fill_expr_list(char** toks, int s_start, int s_end, struct expr_list* p) |
---|
242 | { |
---|
243 | int start = s_start, nitem = s_end + 1, end, cnt = 0, nc; |
---|
244 | while (start < nitem) |
---|
245 | { |
---|
246 | if ((nc = next_char(',', toks, start, nitem)) < 0) nc = nitem; |
---|
247 | if (loc_expr(toks, nc, start, &end)) |
---|
248 | { |
---|
249 | if (cnt == p->max) grow_expr_list(p); |
---|
250 | p->list[cnt++] = make_expression(end + 1 - start, &toks[start]); |
---|
251 | start = nc + 1; |
---|
252 | } |
---|
253 | else break; |
---|
254 | } |
---|
255 | p->curr = cnt; |
---|
256 | } |
---|
257 | |
---|
258 | void |
---|
259 | fill_expr_var_list(struct el_list* ell, struct expression* expr, struct var_list* varl) |
---|
260 | /* puts all variables an expression depends on, in a list */ |
---|
261 | { |
---|
262 | struct variable* var; |
---|
263 | struct element* el; |
---|
264 | char name[2*NAME_L]; |
---|
265 | char* p; |
---|
266 | int i, k, kc; |
---|
267 | struct int_array* deco = expr->polish; |
---|
268 | for (i = 0; i < deco->curr; i++) /* decoding loop */ |
---|
269 | { |
---|
270 | if ((k = deco->i[i]) > 4 && (kc = k / 100000000) == 1) |
---|
271 | { |
---|
272 | k -= 100000000 * kc; strcpy(name, expr_chunks->names[k]); |
---|
273 | if ((p = strstr(name, "->")) != NULL) |
---|
274 | { |
---|
275 | *p = '\0'; |
---|
276 | if ((el = find_element(name, element_list)) != NULL) |
---|
277 | add_to_el_list(&el, 0, ell, 0); |
---|
278 | } |
---|
279 | else if ((var = find_variable(name, variable_list)) != NULL) |
---|
280 | { |
---|
281 | add_to_var_list(var, varl, 2); |
---|
282 | if (var->type == 2 && var->expr != NULL) |
---|
283 | fill_expr_var_list(ell, var->expr, varl); |
---|
284 | } |
---|
285 | } |
---|
286 | } |
---|
287 | } |
---|
288 | |
---|
289 | double |
---|
290 | double_from_expr(char** toks, int s_start, int s_end) |
---|
291 | /* returns the value of an expression if valid, else INVALID */ |
---|
292 | { |
---|
293 | int end, nitem = s_end + 1; |
---|
294 | int type = loc_expr(toks, nitem, s_start, &end); |
---|
295 | if (type == 1) /* simple number */ |
---|
296 | return simple_double(toks, s_start, end); |
---|
297 | else if (polish_expr(end + 1 - s_start, &toks[s_start]) == 0) |
---|
298 | return polish_value(deco, join( &toks[s_start],end + 1 - s_start) ); |
---|
299 | else return INVALID; |
---|
300 | } |
---|
301 | |
---|
302 | int |
---|
303 | loc_expr(char** items, int nit, int start, int* end) |
---|
304 | /* Returns the type and end of an expression, or 0 if illegal */ |
---|
305 | { |
---|
306 | char c; |
---|
307 | int i, e_type = 1, par_level = 0, ltog = -1; |
---|
308 | *end = start - 1; |
---|
309 | if (nit > start && is_expr_start(*items[start])) |
---|
310 | { |
---|
311 | c = *items[start]; |
---|
312 | for (i = start; i < nit; i++) |
---|
313 | { |
---|
314 | c = *items[i]; |
---|
315 | if (c == '(') {par_level++; e_type = 2;} |
---|
316 | else if (c == ')') |
---|
317 | { |
---|
318 | if (par_level == 0) return 0; |
---|
319 | par_level--; ltog = 0; |
---|
320 | } |
---|
321 | else if (par_level == 0) |
---|
322 | { |
---|
323 | if (ltog < 0) ltog = is_operator(c) ? 1 : 0; |
---|
324 | else if ((ltog == 0 && is_operator(c)) |
---|
325 | || (ltog != 0 && is_operand(c))) ltog = 1 - ltog; |
---|
326 | else return 0; |
---|
327 | } |
---|
328 | *end = i; |
---|
329 | if ((*end > start && ltog > 0) || (isalpha(c) || c == '_')) e_type = 2; |
---|
330 | } |
---|
331 | return e_type; |
---|
332 | } |
---|
333 | else return 0; |
---|
334 | } |
---|
335 | |
---|
336 | int |
---|
337 | scan_expr(int c_item, char** item) /* split input */ |
---|
338 | |
---|
339 | /* scans expressions for parameters, elements, numbers, and functions |
---|
340 | |
---|
341 | categories: 1: variable, 3: floating constant, 4: operator |
---|
342 | operator types: |
---|
343 | 1 = +, 2 = -, 3 = *, 4 = /, 5 = ^ (power), 6 = function (from functs) |
---|
344 | */ |
---|
345 | |
---|
346 | { |
---|
347 | int i, lp, lx = -1, l_cat = 0, level = 0, pos, f_level[MAX_ITEM]; |
---|
348 | char c; |
---|
349 | char* bf; |
---|
350 | |
---|
351 | for (i = 0; i < c_item; i++) /* loop over input items */ |
---|
352 | { |
---|
353 | c = item[i][0]; /* first character of item i */ |
---|
354 | if (c == '(') |
---|
355 | { |
---|
356 | f_level[level++] = 0; |
---|
357 | if (l_cat > 0) |
---|
358 | { |
---|
359 | if (cat->i[l_cat-1] < 4) return 2; /* error: missing operator */ |
---|
360 | if (cat->i[l_cat-1] == 5) /* function */ |
---|
361 | { |
---|
362 | f_level[level-1] = func->i[--l_cat]; |
---|
363 | if (l_cat == func->max) grow_int_array(func); |
---|
364 | func->i[l_cat] = 0; |
---|
365 | } |
---|
366 | } |
---|
367 | if (l_cat == cat->max) grow_int_array(cat); |
---|
368 | cat->i[l_cat++] = 6; |
---|
369 | } |
---|
370 | else if (c == ')') |
---|
371 | { |
---|
372 | if (level == 0) return 1; /* error: too many right brackets */ |
---|
373 | if (l_cat == cat->max) grow_int_array(cat); |
---|
374 | cat->i[l_cat++] = 7; |
---|
375 | level--; |
---|
376 | if (f_level[level] != 0) |
---|
377 | { |
---|
378 | if (l_cat == oper->max) grow_int_array(oper); |
---|
379 | if (l_cat == func->max) grow_int_array(func); |
---|
380 | if (l_cat == cat->max) grow_int_array(cat); |
---|
381 | oper->i[l_cat] = 6; |
---|
382 | func->i[l_cat] = f_level[level]; |
---|
383 | cat->i[l_cat++] = 4; |
---|
384 | } |
---|
385 | } |
---|
386 | else if (isalpha(c) || c == '_') /* start of variable or function */ |
---|
387 | { |
---|
388 | lp = 0; |
---|
389 | while (strlen(functs[lp])) |
---|
390 | { |
---|
391 | lx = lp; |
---|
392 | if (strcmp(item[i], functs[lp]) == 0) break; |
---|
393 | lp++; |
---|
394 | } |
---|
395 | if (lx == lp) /* function found */ |
---|
396 | { |
---|
397 | if (l_cat == cat->max) grow_int_array(cat); |
---|
398 | if (l_cat == func->max) grow_int_array(func); |
---|
399 | cat->i[l_cat] = 5; |
---|
400 | func->i[l_cat++] = lp; |
---|
401 | if (strcmp("exist", functs[lp]) == 0 /* special function */ |
---|
402 | && i+3 < c_item && *item[i+1] == '(' && *item[i+3] == ')') |
---|
403 | { |
---|
404 | if (find_variable(item[i+2], variable_list) == NULL) |
---|
405 | strcpy(item[i+2], "0"); |
---|
406 | else strcpy(item[i+2], "1"); |
---|
407 | } |
---|
408 | } |
---|
409 | else |
---|
410 | { |
---|
411 | if (l_cat == cat->max) grow_int_array(cat); |
---|
412 | if (l_cat == d_var->max) grow_int_array(d_var); |
---|
413 | cat->i[l_cat] = 1; |
---|
414 | if ((pos = name_list_pos(item[i], expr_chunks)) < 0) |
---|
415 | { |
---|
416 | bf = permbuff(item[i]); |
---|
417 | d_var->i[l_cat++] = add_to_name_list(bf, 0, expr_chunks); |
---|
418 | } |
---|
419 | else d_var->i[l_cat++] = pos; |
---|
420 | } |
---|
421 | } |
---|
422 | else if (isdigit(c) || c == '.') /* number */ |
---|
423 | { |
---|
424 | if (l_cat == cat->max) grow_int_array(cat); |
---|
425 | if (l_cat == cat_doubles->max) grow_double_array(cat_doubles); |
---|
426 | cat->i[l_cat] = 3; |
---|
427 | cat_doubles->a[l_cat++] = atof(item[i]); |
---|
428 | } |
---|
429 | else if (is_operator(c)) |
---|
430 | { |
---|
431 | if (l_cat == cat->max ) grow_int_array(cat); |
---|
432 | if (l_cat == oper->max) grow_int_array(oper); |
---|
433 | cat->i[l_cat] = 4; |
---|
434 | oper->i[l_cat++] = str_pos(op_string, c); |
---|
435 | /* oper->i[l_cat++] = (int)strchr(op_string, c) -(int)op_string;*/ |
---|
436 | } |
---|
437 | else return 2; /* illegal character */ |
---|
438 | } |
---|
439 | if (level != 0) return 1; /* unclosed parentheses */ |
---|
440 | cat->curr = l_cat; |
---|
441 | return 0; |
---|
442 | } |
---|
443 | |
---|
444 | struct expression* |
---|
445 | compound_expr(struct expression* e1, double v1, char* oper, struct expression* e2, double v2) |
---|
446 | /* make one out of two expressions, using oper to connect them |
---|
447 | hbu 9/2005 moved from madxn.c to makethin.c as only used here |
---|
448 | and increased precision sprintf(tmp, "%e" -> sprintf(tmp, "%.14g" */ |
---|
449 | { |
---|
450 | char** toks = tmp_l_array->p; |
---|
451 | struct expression* expr = NULL; |
---|
452 | char tmp[30]; |
---|
453 | int n; |
---|
454 | char lb[] = "(", rb[] = ")"; |
---|
455 | if (e1 != NULL || e2 != NULL) |
---|
456 | { |
---|
457 | if (e1 != NULL) |
---|
458 | { |
---|
459 | if (e2 != NULL) |
---|
460 | { |
---|
461 | toks[0] = lb; toks[1] = e1->string; toks[2] = rb; |
---|
462 | toks[3] = oper; |
---|
463 | toks[4] = lb; toks[5] = e2->string; toks[6] = rb; |
---|
464 | } |
---|
465 | else |
---|
466 | { |
---|
467 | sprintf(tmp, "%.14g", v2); /* hbu */ |
---|
468 | toks[0] = lb; toks[1] = e1->string; toks[2] = rb; |
---|
469 | toks[3] = oper; |
---|
470 | toks[4] = lb; toks[5] = tmp; toks[6] = rb; |
---|
471 | } |
---|
472 | } |
---|
473 | else |
---|
474 | { |
---|
475 | sprintf(tmp, "%.14g", v1); /* hbu */ |
---|
476 | toks[0] = lb; toks[1] = tmp; toks[2] = rb; |
---|
477 | toks[3] = oper; |
---|
478 | toks[4] = lb; toks[5] = e2->string; toks[6] = rb; |
---|
479 | } |
---|
480 | join(toks, 7); |
---|
481 | pre_split(c_join->c, l_wrk, 0); |
---|
482 | n = mysplit(l_wrk->c, tmp_l_array); |
---|
483 | expr = make_expression(n, toks); |
---|
484 | } |
---|
485 | return expr; |
---|
486 | } |
---|
487 | |
---|
488 | /* scale an expression by a number - or leave it NULL */ |
---|
489 | struct expression* |
---|
490 | scale_expr(struct expression* expr,double scale) |
---|
491 | { |
---|
492 | if (expr) return compound_expr(expr,0,"*",NULL,scale); |
---|
493 | return NULL; |
---|
494 | } |
---|
495 | |
---|