1 /*
2    This program is free software; you can redistribute it and/or modify
3    it under the terms of the GNU General Public License as published by
4    the Free Software Foundation; either version 2 of the License, or
5    (at your option) any later version.
6 
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11 
12    You should have received a copy of the GNU General Public License
13    along with this program; if not, write to the Free Software
14    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15 */
16 
17 #include "udm_config.h"
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <errno.h>
24 #include <math.h>
25 
26 #include "udm_common.h"
27 #include "udm_template.h"
28 #include "udm_server.h"
29 #include "udm_env.h"
30 #include "udm_conf.h"
31 #include "udm_db.h"
32 #include "udm_http.h"
33 #include "udm_parsehtml.h"
34 #include "udm_host.h"
35 #include "udm_contentencoding.h"
36 #include "udm_utils.h"
37 #include "udm_vars.h"
38 #include "udm_wild.h"
39 #include "udm_searchtool.h"
40 #include "udm_doc.h"
41 #include "udm_match.h"
42 #include "udm_sgml.h"
43 #include "udm_proto.h"
44 #include "udm_ctype.h"
45 #include "udm_lex.h"
46 #include "udm_prog.h"
47 
48 
49 /*
50 TODO:
51 - Add C++ keywords
52 - Add size_t
53 - Add sizeof
54 - Refactor cout, make << an operator in ostream.
55 - Change functions _argv() and _argc() to paramenters argv and argc
56 - More efficient data alignment: see UdmValueHandlerAlignedDataSize()
57 - Add a warning: "Suggest parentheses around &&" when mixing || and &&
58 - Restore a warning: see ExpressionHasEffect()
59 - Create function call arguments on stack rather than on heap.
60 - Allow function calls as arguments to other function calls.
61 - maximum execution time
62 - string comparison: if (x < "yyy")
63 - string concatenation with operator+
64 
65 TODO-TEMPLATE:
66 - DetectClones: copy from msearch-test/include/search.htm
67 - doccount is 0 if there is only one search word
68 - qcache and "missing" do not work together
69 - mark stopwords (check origin)
70 - don't display suggestions (origin=6) in word statistics
71 - "Strict mode ... too few result" does not get displayed
72    if Strict found 0 results
73 - display query in browser charset, e.g. res.property_html("q") ?
74 - Remove DateFormat, implement strftime() instead
75 - HTML-aware string::left(). See UdmHtmlStrLeft().
76 - ExcerptSize and ExcerptPadding should probably be parameters to
77   property(), or to a new method.
78 */
79 
80 #define UDM_CMDNAME(x) {UDM_CSTR_WITH_LEN(x)}
81 #define UDM_CMD1_VOID(name, exec) {UDM_CMDNAME(name), 1, exec}
82 #define UDM_CMD2_VOID(name, exec) {UDM_CMDNAME(name), 2, exec}
83 #define UDM_CMD1_IREG0(name, exec) {UDM_CMDNAME(name), 1, exec}
84 
85 
86 typedef enum
87 {
88   UDM_ASSIGNMENT_MUL,
89   UDM_ASSIGNMENT_DIV,
90   UDM_ASSIGNMENT_REM,
91   UDM_ASSIGNMENT_ADD,
92   UDM_ASSIGNMENT_SUB,
93   UDM_ASSIGNMENT_AND,
94   UDM_ASSIGNMENT_OR,
95   UDM_ASSIGNMENT_XOR,
96   UDM_ASSIGNMENT_LSHIFT,
97   UDM_ASSIGNMENT_RSHIFT
98 } udm_special_assignment_t;
99 
100 
101 typedef enum
102 {
103   UDM_UNARY_OPERATOR_PREFIX_INC,
104   UDM_UNARY_OPERATOR_PREFIX_DEC,
105   UDM_UNARY_OPERATOR_POSTFIX_INC,
106   UDM_UNARY_OPERATOR_POSTFIX_DEC
107 } udm_unary_operator_t;
108 
109 
110 typedef enum
111 {
112   UDM_EXPRESSION_IDENT,
113   UDM_EXPRESSION_CONST,
114   UDM_EXPRESSION_OBJECT,      /* The value can be in a temp var   */
115   UDM_EXPRESSION_COMPUTED     /* The value is in registers        */
116 } udm_expression_t;
117 
118 
119 typedef struct
120 {
121   UDM_PROG_VAR Var;
122   udm_expression_t type;
123   char buf[2];
124   udm_offset_and_length_t textdata_addr;
125 } UDM_PROG_PRIMARY_EXPRESSION;
126 
127 
128 typedef struct
129 {
130   UDM_PROG_PRIMARY_EXPRESSION args[UDM_PROG_MAXARG];
131   size_t nargs;
132 } UDM_PROG_FUNCTION_CALL_ARGUMENTS;
133 
134 
135 typedef struct
136 {
137   UDM_PROG_PRIMARY_EXPRESSION primary_expr;
138   UDM_PROG_FUNCTION_CALL_ARGUMENTS arglist;
139 } UDM_PROG_EXPRESSION;
140 
141 
142 static const UDM_VALUE_HANDLER *
UdmProgVarHandler(const UDM_PROG_VAR * Var)143 UdmProgVarHandler(const UDM_PROG_VAR *Var)
144 {
145   return Var->value.handler;
146 }
147 
148 
149 static void
UdmProgVarSetHandler(UDM_PROG_VAR * Var,const UDM_VALUE_HANDLER * handler)150 UdmProgVarSetHandler(UDM_PROG_VAR *Var, const UDM_VALUE_HANDLER *handler)
151 {
152   Var->value.handler= handler;
153 }
154 
155 
156 static const UDM_VALUE_HANDLER *
UdmPrimaryExprHandler(const UDM_PROG_PRIMARY_EXPRESSION * expr)157 UdmPrimaryExprHandler(const UDM_PROG_PRIMARY_EXPRESSION *expr)
158 {
159   return expr->Var.value.handler;
160 }
161 
162 
163 static const UDM_VALUE_HANDLER *
UdmExprHandler(const UDM_PROG_EXPRESSION * expr)164 UdmExprHandler(const UDM_PROG_EXPRESSION *expr)
165 {
166   return expr->primary_expr.Var.value.handler;
167 }
168 
169 
170 static void
UdmExprSetHandler(UDM_PROG_EXPRESSION * expr,const UDM_VALUE_HANDLER * handler)171 UdmExprSetHandler(UDM_PROG_EXPRESSION *expr,
172                   const UDM_VALUE_HANDLER *handler)
173 {
174   expr->primary_expr.Var.value.handler= handler;
175 }
176 
177 
178 /************************************************************/
179 
180 static udm_bool_t
UdmGenerateOp(UDM_PROG_COMPILER * compiler,udm_tmpl_cmd_t cmd)181 UdmGenerateOp(UDM_PROG_COMPILER *compiler, udm_tmpl_cmd_t cmd)
182 {
183   return UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg, cmd);
184 }
185 
186 
187 static void
UdmProgItemArgInitFromLiteral(UDM_PROG_ARG * arg,const UDM_CONST_TOKEN * str,const udm_offset_and_length_t * textdata)188 UdmProgItemArgInitFromLiteral(UDM_PROG_ARG *arg,
189                               const UDM_CONST_TOKEN *str,
190                               const udm_offset_and_length_t *textdata)
191 {
192   arg->textdata_addr= *textdata;
193 }
194 
195 
196 static void
UdmProgItemArgInitFromLiteralAndHandler(UDM_PROG_ARG * arg,const UDM_PROG_PRIMARY_EXPRESSION * expr)197 UdmProgItemArgInitFromLiteralAndHandler(UDM_PROG_ARG *arg,
198                                         const UDM_PROG_PRIMARY_EXPRESSION *expr)
199 {
200   arg->handler= UdmPrimaryExprHandler(expr);
201   arg->textdata_addr= expr->textdata_addr;
202 }
203 
204 
205 static void
UdmProgItemArgInitFromVar(UDM_PROG_ARG * arg,const UDM_PROG_VAR * Var)206 UdmProgItemArgInitFromVar(UDM_PROG_ARG *arg, const UDM_PROG_VAR *Var)
207 {
208   arg->stack_offset= Var->value.stack_offset;
209   arg->handler= Var->value.handler;
210 }
211 
212 
213 static udm_rc_t
UdmProgAddJmpWithComment(UDM_PROG * prog,udm_tmpl_cmd_t cmdnum,int addr,const char * comment)214 UdmProgAddJmpWithComment(UDM_PROG *prog,
215                          udm_tmpl_cmd_t cmdnum,
216                          int addr, const char *comment)
217 {
218   UDM_PROG_ITEM i;
219   UdmProgItemInit(&i);
220   i.cmdnum= cmdnum;
221   i.comment= strdup(comment);
222   i.cmdarg.jump= addr;
223   return UdmProgAdd(prog, &i);
224 }
225 
226 
227 static udm_bool_t
UdmGenerateOpOffset(UDM_PROG_COMPILER * compiler,udm_tmpl_cmd_t cmdnum,size_t offset)228 UdmGenerateOpOffset(UDM_PROG_COMPILER *compiler,
229                     udm_tmpl_cmd_t cmdnum,
230                     size_t offset)
231 {
232   UDM_PROG_ITEM it;
233   UdmProgItemInit(&it);
234   it.cmdnum= cmdnum;
235   it.cmdarg.offset= offset;
236   return UDM_OK == UdmProgAdd(compiler->prg, &it);
237 }
238 
239 
240 /*********************************************************************/
241 
242 static const UDM_PROG_ITEM *
UdmProgExecutorStateCurrentCmd(const UDM_PROG_EXECUTOR_STATE * p)243 UdmProgExecutorStateCurrentCmd(const UDM_PROG_EXECUTOR_STATE *p)
244 {
245   return p->curr;
246 }
247 
248 
249 static void *
UdmProgExecutorStateStackAddr0(UDM_PROG_EXECUTOR_STATE * st,const UDM_PROG_ITEM * it)250 UdmProgExecutorStateStackAddr0(UDM_PROG_EXECUTOR_STATE *st,
251                                const UDM_PROG_ITEM *it)
252 {
253   return st->stack.Val.str + it->item_args.stack_offset;
254 }
255 
256 
257 static void
Template_mov_dregn_var0(UDM_PROG_EXECUTOR_STATE * T,size_t dregno)258 Template_mov_dregn_var0(UDM_PROG_EXECUTOR_STATE *T, size_t dregno)
259 {
260   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
261   void *Data= UdmProgExecutorStateStackAddr0(T, it);
262   it->item_args.handler->GetDouble(Data, &T->reg.d[dregno]);
263 }
264 
265 
266 static void
Template_mov_iregn_var0(UDM_PROG_EXECUTOR_STATE * T,size_t iregno)267 Template_mov_iregn_var0(UDM_PROG_EXECUTOR_STATE *T, size_t iregno)
268 {
269   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
270   void *Data= UdmProgExecutorStateStackAddr0(T, it);
271   it->item_args.handler->GetInt(Data, &T->reg.i[iregno]);
272 }
273 
274 
275 /* Variable initialization */
276 
277 /*TODO34: destructor is never called for declared variables!!! */
278 static void
Template_construct_var(UDM_PROG_EXECUTOR_STATE * T)279 Template_construct_var(UDM_PROG_EXECUTOR_STATE *T)
280 {
281   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
282   const UDM_VALUE_HANDLER *ha= it->item_args.handler;
283   void *Data= UdmProgExecutorStateStackAddr0(T, it);
284   UDM_ASSERT(it->item_args.stack_offset + ha->DataSize() < T->stack.size_alloced);
285   if (UDM_OK != ha->Constructor(Data, NULL, 0))
286     T->fatal_error= UDM_TRUE;
287 }
288 
289 
290 static void
Template_set_var_from_ireg0(UDM_PROG_EXECUTOR_STATE * T)291 Template_set_var_from_ireg0(UDM_PROG_EXECUTOR_STATE *T)
292 {
293   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
294   void *Data= UdmProgExecutorStateStackAddr0(T, it);
295   const UDM_VALUE_HANDLER *ha= it->item_args.handler;
296   ha->SetInt(Data, T->reg.i[0]);
297 }
298 
299 
300 static void
Template_set_var_from_dreg0(UDM_PROG_EXECUTOR_STATE * T)301 Template_set_var_from_dreg0(UDM_PROG_EXECUTOR_STATE *T)
302 {
303   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
304   void *Data= UdmProgExecutorStateStackAddr0(T, it);
305   const UDM_VALUE_HANDLER *ha= it->item_args.handler;
306   ha->SetDouble(Data, T->reg.d[0]);
307 }
308 
309 
310 static void
Template_set_var_from_text0(UDM_PROG_EXECUTOR_STATE * T)311 Template_set_var_from_text0(UDM_PROG_EXECUTOR_STATE *T)
312 {
313   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
314   void *Data= UdmProgExecutorStateStackAddr0(T, it);
315   const UDM_VALUE_HANDLER *ha= it->item_args.handler;
316   ha->SetStrn(Data,
317               T->prog->textdata.Val.str + it->item_args.textdata_addr.offset,
318               it->item_args.textdata_addr.length);
319 }
320 
321 
322 static void
Template_set_var_from_cs0_z0(UDM_PROG_EXECUTOR_STATE * T)323 Template_set_var_from_cs0_z0(UDM_PROG_EXECUTOR_STATE *T)
324 {
325   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
326   void *Dst= UdmProgExecutorStateStackAddr0(T, it);
327   if (UDM_OK != it->item_args.handler->SetStrn(Dst, T->reg.cs0, T->reg.z0))
328     T->fatal_error= UDM_TRUE;
329 }
330 
331 
332 static void
Template_get_var_to_cs0_z0(UDM_PROG_EXECUTOR_STATE * T)333 Template_get_var_to_cs0_z0(UDM_PROG_EXECUTOR_STATE *T)
334 {
335   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
336   void *Src= UdmProgExecutorStateStackAddr0(T, it);
337   UDM_CONST_STR str;
338   it->item_args.handler->GetConstStr(Src, &str);
339   T->reg.cs0= str.str;
340   T->reg.z0= str.length;
341 }
342 
343 
344 static void
Template_get_textdata_to_cs0_z0(UDM_PROG_EXECUTOR_STATE * T)345 Template_get_textdata_to_cs0_z0(UDM_PROG_EXECUTOR_STATE *T)
346 {
347   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
348   T->reg.cs0= T->prog->textdata.Val.str + it->item_args.textdata_addr.offset;
349   T->reg.z0= it->item_args.textdata_addr.length;
350 }
351 
352 
353 static void
Template_destruct_var(UDM_PROG_EXECUTOR_STATE * T)354 Template_destruct_var(UDM_PROG_EXECUTOR_STATE *T)
355 {
356   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
357   void *Data= UdmProgExecutorStateStackAddr0(T, it);
358   it->item_args.handler->Destructor(Data);
359 }
360 
361 
362 static void
Template_mov_ireg0_var0(UDM_PROG_EXECUTOR_STATE * T)363 Template_mov_ireg0_var0(UDM_PROG_EXECUTOR_STATE *T)
364 {
365   Template_mov_iregn_var0(T, 0);
366 }
367 
368 
369 static void
Template_mov_ireg1_var0(UDM_PROG_EXECUTOR_STATE * T)370 Template_mov_ireg1_var0(UDM_PROG_EXECUTOR_STATE *T)
371 {
372   Template_mov_iregn_var0(T, 1);
373 }
374 
375 
376 static void
Template_mov_dreg0_var0(UDM_PROG_EXECUTOR_STATE * T)377 Template_mov_dreg0_var0(UDM_PROG_EXECUTOR_STATE *T)
378 {
379   Template_mov_dregn_var0(T, 0);
380 }
381 
382 
383 static void
Template_mov_dreg1_var0(UDM_PROG_EXECUTOR_STATE * T)384 Template_mov_dreg1_var0(UDM_PROG_EXECUTOR_STATE *T)
385 {
386   Template_mov_dregn_var0(T, 1);
387 }
388 
389 
390 #define UDM_CMDNAME(x) {UDM_CSTR_WITH_LEN(x)}
391 
392 
393 #define UDM_CMD1_VOID(name, exec) {UDM_CMDNAME(name), 1, exec}
394 #define UDM_CMD2_VOID(name, exec) {UDM_CMDNAME(name), 2, exec}
395 #define UDM_CMD3_VOID(name, exec) {UDM_CMDNAME(name), 3, exec}
396 
397 #define UDM_CMD0_IREG0(name, exec) {UDM_CMDNAME(name), 0, exec}
398 #define UDM_CMD0_IREG1(name, exec) {UDM_CMDNAME(name), 0, exec}
399 #define UDM_CMD0_DREG0(name, exec) {UDM_CMDNAME(name), 0, exec}
400 #define UDM_CMD0_DREG1(name, exec) {UDM_CMDNAME(name), 0, exec}
401 
402 #define UDM_CMD1_IREG0(name, exec) {UDM_CMDNAME(name), 1, exec}
403 #define UDM_CMD1_IREG1(name, exec) {UDM_CMDNAME(name), 1, exec}
404 #define UDM_CMD1_DREG0(name, exec) {UDM_CMDNAME(name), 1, exec}
405 #define UDM_CMD1_DREG1(name, exec) {UDM_CMDNAME(name), 1, exec}
406 
407 #define UDM_CMD2_IREG0(name, exec) {UDM_CMDNAME(name), 2, exec}
408 
409 
410 
411 /* Registers and variables */
412 static UDM_PROG_CMD
413 udm_tmpl_mov_ireg0_var0= UDM_CMD1_IREG0("GetInt i0 v0", Template_mov_ireg0_var0),
414 udm_tmpl_mov_ireg1_var0= UDM_CMD1_IREG1("GetInt i1 v0", Template_mov_ireg1_var0);
415 
416 static UDM_PROG_CMD
417 udm_tmpl_mov_dreg0_var0= UDM_CMD1_DREG0("GetDbl d0 v0", Template_mov_dreg0_var0),
418 udm_tmpl_mov_dreg1_var0= UDM_CMD1_DREG0("GetDbl d1 v0", Template_mov_dreg1_var0);
419 
420 static UDM_PROG_CMD
421 udm_tmpl_get_var_to_cs0_z0= UDM_CMD1_DREG0("GetStr cs0/z0 v0", Template_get_var_to_cs0_z0);
422 
423 static UDM_PROG_CMD
424 udm_tmpl_textdata_to_cs0_z0= UDM_CMD1_DREG0("GetStr cs0/z0 textdata", Template_get_textdata_to_cs0_z0);
425 
426 /* Registers and values */
427 
428 static UDM_PROG_CMD
429 udm_tmpl_set_var_from_text0= UDM_CMD2_VOID("SetStr v0 text0", Template_set_var_from_text0),
430 udm_tmpl_set_var_from_ireg0=  UDM_CMD2_VOID("SetInt v0 i0", Template_set_var_from_ireg0),
431 udm_tmpl_set_var_from_dreg0=  UDM_CMD2_VOID("SetDbl v0 d0", Template_set_var_from_dreg0),
432 udm_tmpl_set_var_from_cs0_z0=   UDM_CMD2_VOID("SetStr v0 cs0/z0", Template_set_var_from_cs0_z0),
433 udm_tmpl_construct_var= UDM_CMD2_VOID("construct", Template_construct_var),
434 udm_tmpl_destruct_var= UDM_CMD2_VOID("destruct", Template_destruct_var);
435 
436 /*********************************************************************/
437 
438 static void
Exec_method_make_arg(UDM_PROG_EXECUTOR_STATE * T,size_t argno)439 Exec_method_make_arg(UDM_PROG_EXECUTOR_STATE *T, size_t argno)
440 {
441   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
442   const UDM_VALUE_HANDLER *handler= it->item_args.handler;
443   T->vreg[argno].Data= UdmMalloc(handler->DataSize());
444   handler->Constructor(T->vreg[argno].Data, NULL, 0);
445   handler->SetStrn(T->vreg[argno].Data,
446                    T->prog->textdata.Val.str + it->item_args.textdata_addr.offset,
447                    it->item_args.textdata_addr.length);
448 }
449 
450 
451 static void
Exec_method_free_arg(UDM_PROG_EXECUTOR_STATE * T,size_t argno)452 Exec_method_free_arg(UDM_PROG_EXECUTOR_STATE *T, size_t argno)
453 {
454   const UDM_PROG_ITEM *it= UdmProgExecutorStateCurrentCmd(T);
455   const UDM_VALUE_HANDLER *handler= it->item_args.handler;
456   handler->Destructor(T->vreg[argno].Data);
457   UdmFree(T->vreg[argno].Data);
458   T->vreg[argno].Data= NULL;
459 }
460 
461 /**** arg0 ***/
462 
463 static void
Exec_method_make_arg0(UDM_PROG_EXECUTOR_STATE * T)464 Exec_method_make_arg0(UDM_PROG_EXECUTOR_STATE *T)
465 {
466   Exec_method_make_arg(T, 0);
467 }
468 
469 static void
Exec_method_free_arg0(UDM_PROG_EXECUTOR_STATE * T)470 Exec_method_free_arg0(UDM_PROG_EXECUTOR_STATE *T)
471 {
472   Exec_method_free_arg(T, 0);
473 }
474 
475 
476 static void
Exec_method_clear_arg0(UDM_PROG_EXECUTOR_STATE * T)477 Exec_method_clear_arg0(UDM_PROG_EXECUTOR_STATE *T)
478 {
479   T->vreg[0].Data= NULL;
480 }
481 
482 
483 /*** arg1 ***/
484 
485 static void
Exec_method_make_arg1(UDM_PROG_EXECUTOR_STATE * T)486 Exec_method_make_arg1(UDM_PROG_EXECUTOR_STATE *T)
487 {
488   Exec_method_make_arg(T, 1);
489 }
490 
491 static void
Exec_method_free_arg1(UDM_PROG_EXECUTOR_STATE * T)492 Exec_method_free_arg1(UDM_PROG_EXECUTOR_STATE *T)
493 {
494   Exec_method_free_arg(T, 1);
495 }
496 
497 static void
Exec_method_clear_arg1(UDM_PROG_EXECUTOR_STATE * T)498 Exec_method_clear_arg1(UDM_PROG_EXECUTOR_STATE *T)
499 {
500   T->vreg[1].Data= NULL;
501 }
502 
503 
504 /*** arg2 ***/
505 
506 static void
Exec_method_make_arg2(UDM_PROG_EXECUTOR_STATE * T)507 Exec_method_make_arg2(UDM_PROG_EXECUTOR_STATE *T)
508 {
509   Exec_method_make_arg(T, 2);
510 }
511 
512 static void
Exec_method_free_arg2(UDM_PROG_EXECUTOR_STATE * T)513 Exec_method_free_arg2(UDM_PROG_EXECUTOR_STATE *T)
514 {
515   Exec_method_free_arg(T, 2);
516 }
517 
518 static void
Exec_method_clear_arg2(UDM_PROG_EXECUTOR_STATE * T)519 Exec_method_clear_arg2(UDM_PROG_EXECUTOR_STATE *T)
520 {
521   T->vreg[2].Data= NULL;
522 }
523 
524 /*** arg3 ***/
525 
526 static void
Exec_method_make_arg3(UDM_PROG_EXECUTOR_STATE * T)527 Exec_method_make_arg3(UDM_PROG_EXECUTOR_STATE *T)
528 {
529   Exec_method_make_arg(T, 3);
530 }
531 
532 static void
Exec_method_free_arg3(UDM_PROG_EXECUTOR_STATE * T)533 Exec_method_free_arg3(UDM_PROG_EXECUTOR_STATE *T)
534 {
535   Exec_method_free_arg(T, 3);
536 }
537 
538 static void
Exec_method_clear_arg3(UDM_PROG_EXECUTOR_STATE * T)539 Exec_method_clear_arg3(UDM_PROG_EXECUTOR_STATE *T)
540 {
541   T->vreg[3].Data= NULL;
542 }
543 
544 /*** arg4 ***/
545 
546 static void
Exec_method_make_arg4(UDM_PROG_EXECUTOR_STATE * T)547 Exec_method_make_arg4(UDM_PROG_EXECUTOR_STATE *T)
548 {
549   Exec_method_make_arg(T, 4);
550 }
551 
552 static void
Exec_method_free_arg4(UDM_PROG_EXECUTOR_STATE * T)553 Exec_method_free_arg4(UDM_PROG_EXECUTOR_STATE *T)
554 {
555   Exec_method_free_arg(T, 4);
556 }
557 
558 static void
Exec_method_clear_arg4(UDM_PROG_EXECUTOR_STATE * T)559 Exec_method_clear_arg4(UDM_PROG_EXECUTOR_STATE *T)
560 {
561   T->vreg[4].Data= NULL;
562 }
563 
564 /****/
565 
566 static UDM_PROG_CMD
567 udm_method_clear_arg0=  UDM_CMD1_VOID("mov  v0,0", Exec_method_clear_arg0),
568 udm_method_clear_arg1=  UDM_CMD1_VOID("mov  v1,0", Exec_method_clear_arg1),
569 udm_method_clear_arg2=  UDM_CMD1_VOID("mov  v2,0", Exec_method_clear_arg2),
570 udm_method_clear_arg3=  UDM_CMD1_VOID("mov  v3,0", Exec_method_clear_arg3),
571 udm_method_clear_arg4=  UDM_CMD1_VOID("mov  v4,0", Exec_method_clear_arg4);
572 
573 
574 static UDM_PROG_CMD
575 udm_method_make_arg0=   UDM_CMD1_VOID("MAKE-ARG0", Exec_method_make_arg0),
576 udm_method_free_arg0=   UDM_CMD1_VOID("FREE-ARG0", Exec_method_free_arg0);
577 
578 
579 static UDM_PROG_CMD
580 udm_method_make_arg1=   UDM_CMD1_VOID("MAKE-ARG1", Exec_method_make_arg1),
581 udm_method_free_arg1=   UDM_CMD1_VOID("FREE-ARG1", Exec_method_free_arg1);
582 
583 
584 static UDM_PROG_CMD
585 udm_method_make_arg2=   UDM_CMD1_VOID("MAKE-ARG2", Exec_method_make_arg2),
586 udm_method_free_arg2=   UDM_CMD1_VOID("FREE-ARG2", Exec_method_free_arg2);
587 
588 
589 static UDM_PROG_CMD
590 udm_method_make_arg3=   UDM_CMD1_VOID("MAKE-ARG3", Exec_method_make_arg3),
591 udm_method_free_arg3=   UDM_CMD1_VOID("FREE-ARG3", Exec_method_free_arg3);
592 
593 
594 static UDM_PROG_CMD
595 udm_method_make_arg4=   UDM_CMD1_VOID("MAKE-ARG4", Exec_method_make_arg4),
596 udm_method_free_arg4=   UDM_CMD1_VOID("FREE-ARG4", Exec_method_free_arg4);
597 
598 
599 /*********************************************************************/
600 
601 static void
Template_cout_ireg0(UDM_PROG_EXECUTOR_STATE * T)602 Template_cout_ireg0(UDM_PROG_EXECUTOR_STATE *T)
603 {
604   fprintf(T->globals.stdout, "%d", T->reg.i[0]);
605 }
606 
607 
608 static void
Template_cout_ireg0_char(UDM_PROG_EXECUTOR_STATE * T)609 Template_cout_ireg0_char(UDM_PROG_EXECUTOR_STATE *T)
610 {
611   char ch= T->reg.i[0];
612   (void) fwrite(&ch, 1, 1, T->globals.stdout);
613 
614 }
615 
616 
617 static void
Template_cout_dreg0(UDM_PROG_EXECUTOR_STATE * T)618 Template_cout_dreg0(UDM_PROG_EXECUTOR_STATE *T)
619 {
620   fprintf(T->globals.stdout, "%f", T->reg.d[0]);
621 }
622 
623 
624 static void
Template_cout_cs0_z0(UDM_PROG_EXECUTOR_STATE * T)625 Template_cout_cs0_z0(UDM_PROG_EXECUTOR_STATE *T)
626 {
627   fwrite(T->reg.cs0, T->reg.z0, 1, T->globals.stdout);
628 }
629 
630 
631 /* New echo functions */
632 static UDM_PROG_CMD
633 udm_tmpl_cout_ireg0=          UDM_CMD1_VOID("cout i0", Template_cout_ireg0),
634 udm_tmpl_cout_ireg0_char=     UDM_CMD1_VOID("cout i0 (char)", Template_cout_ireg0_char),
635 udm_tmpl_cout_dreg0=          UDM_CMD1_VOID("cout d0", Template_cout_dreg0),
636 udm_tmpl_cout_cs0_z0=          UDM_CMD1_VOID("cout   cs0/z0", Template_cout_cs0_z0);
637 
638 
639 /*********************************************************************/
640 
641 
642 static void
UdmPIScanLexToken(UDM_LEX_SCANNER * p,UDM_LEX_TOKEN * a)643 UdmPIScanLexToken(UDM_LEX_SCANNER *p, UDM_LEX_TOKEN *a)
644 {
645 beg:
646   UdmLexScannerSkipSpaces(p);
647   a->token.str= UdmLexScannerCur(p);
648   if (UdmLexScannerEOF(p))
649   {
650     a->type= UDM_LEX_EOF;
651     a->token.end= a->token.str;
652   }
653   else if (!UdmLexScannerScanCComment(p, a))
654   {
655     goto beg;
656   }
657   else if (!UdmLexScannerScanCOperator(p, a))
658   {
659   }
660   else if (!UdmLexScannerScanIdentifier(p, a))
661   {
662   }
663   else if (!UdmLexScannerScanPunctuation(p, a))
664   {
665   }
666   else if (!UdmLexScannerScanEscapedString(p, a))
667   {
668   }
669   else if (!UdmLexScannerScanChar(p, a))
670   {
671   }
672   else if (!UdmLexScannerScanUnsignedNumber(p, a))
673   {
674   }
675   else
676   {
677     a->type= UDM_LEX_UNKNOWN;
678   }
679 
680 #if 0
681   fprintf(stderr, "LEX=%s='%.*s'\n",
682           UdmLex2str(a->type), (int) (a->token.end-a->token.str), a->token.str);
683 #endif
684 }
685 
686 
687 static void
UdmPIParserInit(UDM_PROG_COMPILER * compiler,const char * src,size_t length)688 UdmPIParserInit(UDM_PROG_COMPILER *compiler, const char *src, size_t length)
689 {
690   UdmLexScannerInit(&compiler->scanner, src, length);
691   UdmProgVarListListInit(&compiler->Vars2);
692   compiler->errstr[0]= '\0';
693   compiler->current_loop_continue= 0;
694 }
695 
696 
697 static void
UdmPIParserFree(UDM_PROG_COMPILER * compiler)698 UdmPIParserFree(UDM_PROG_COMPILER *compiler)
699 {
700   UdmProgVarListListFree(&compiler->Vars2);
701 }
702 
703 
704 static size_t
UdmProgCompilerLineno(UDM_PROG_COMPILER * compiler)705 UdmProgCompilerLineno(UDM_PROG_COMPILER *compiler)
706 {
707   const char *s;
708   size_t lineno= compiler->lineno;
709   for (s= compiler->start; s < compiler->scanner.token.token.str; s++)
710   {
711     if (*s == '\n')
712       lineno++;
713   }
714   return lineno + 1;
715 }
716 
717 
718 static size_t
UdmProgCompilerNextVarStackOffset(UDM_PROG_COMPILER * compiler)719 UdmProgCompilerNextVarStackOffset(UDM_PROG_COMPILER *compiler)
720 {
721   UDM_PROG_VARLIST *Vars= &compiler->Vars2.Item[compiler->Vars2.nitems - 1];
722   UDM_ASSERT(compiler->Vars2.nitems);
723   return Vars->next_stack_offset;
724 }
725 
726 
727 static udm_rc_t
UdmProgCompilerNextVarStackOffsetIncrement(UDM_PROG_COMPILER * compiler,size_t inc)728 UdmProgCompilerNextVarStackOffsetIncrement(UDM_PROG_COMPILER *compiler,
729                                            size_t inc)
730 {
731   UDM_PROG_VARLIST *Vars= &compiler->Vars2.Item[compiler->Vars2.nitems - 1];
732   Vars->next_stack_offset+= inc;
733   return UDM_OK;
734 }
735 
736 
737 static udm_bool_t
UdmProgCompilerEnterBlock(UDM_PROG_COMPILER * compiler)738 UdmProgCompilerEnterBlock(UDM_PROG_COMPILER *compiler)
739 {
740   UDM_PROG_VARLIST tmp;
741   UdmProgVarListInit(&tmp);
742   tmp.next_stack_offset= compiler->Vars2.nitems ?
743                          UdmProgCompilerNextVarStackOffset(compiler) : 0;
744   if (UDM_OK != UdmProgVarListListAdd(&compiler->Vars2, &tmp))
745     return UDM_FALSE;
746   return UDM_TRUE;
747 }
748 
749 
750 /**
751   Generate destructors for all variables in the list,
752   in reverse creation order.
753 */
754 static udm_bool_t
UdmProgCompilerGenerateVarListDestructors(UDM_PROG_COMPILER * compiler,UDM_PROG_VARLIST * Vars)755 UdmProgCompilerGenerateVarListDestructors(UDM_PROG_COMPILER *compiler,
756                                           UDM_PROG_VARLIST *Vars)
757 {
758   size_t i;
759   for (i= 0; i < Vars->nitems; i++)
760   {
761     const UDM_PROG_VAR2 *Var= &Vars->Item[Vars->nitems - i - 1];
762     UDM_PROG_ITEM it;
763     UdmProgItemInit(&it);
764     it.item_args.stack_offset= Var->value.stack_offset;
765     it.item_args.handler= Var->value.handler;
766     it.cmd= &udm_tmpl_destruct_var;
767     if (compiler->generate_debug_info)
768       it.comment= UdmStrdup(Var->name);
769     if (UDM_OK != UdmProgAdd(compiler->prg, &it))
770       return UDM_FALSE;
771   }
772   return UDM_TRUE;
773 }
774 
775 
776 static udm_bool_t
UdmProgCompilerGenerateVarListListDestructors(UDM_PROG_COMPILER * compiler)777 UdmProgCompilerGenerateVarListListDestructors(UDM_PROG_COMPILER *compiler)
778 {
779   size_t i;
780   /*
781     Generate destructors for all variables on all levels,
782     to avoid memory leaks.
783   */
784   for (i= compiler->Vars2.nitems; i > 0; i--)
785   {
786     UDM_PROG_VARLIST *Vars= &compiler->Vars2.Item[i - 1];
787     if (!UdmProgCompilerGenerateVarListDestructors(compiler, Vars))
788       return UDM_FALSE;
789   }
790   return UDM_TRUE;
791 }
792 
793 
794 static udm_bool_t
UdmProgCompilerLeaveBlock(UDM_PROG_COMPILER * compiler)795 UdmProgCompilerLeaveBlock(UDM_PROG_COMPILER *compiler)
796 {
797   UDM_PROG_VARLIST *Vars= &compiler->Vars2.Item[compiler->Vars2.nitems - 1];
798   UDM_ASSERT(compiler->Vars2.nitems);
799   if (!UdmProgCompilerGenerateVarListDestructors(compiler, Vars))
800     return UDM_FALSE;
801   UdmProgVarListFree(Vars);
802   compiler->Vars2.nitems--;
803   return UDM_TRUE;
804 }
805 
806 
807 static udm_bool_t
UdmProgCompilerRedeclarationError(UDM_PROG_COMPILER * compiler,const char * name)808 UdmProgCompilerRedeclarationError(UDM_PROG_COMPILER *compiler,
809                                   const char *name)
810 {
811   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
812                "%d: ERROR: Redeclaration of '%s'",
813                (int) UdmProgCompilerLineno(compiler), name);
814   return UDM_FALSE;
815 }
816 
817 
818 typedef struct
819 {
820   udm_unary_operator_t op;
821   UDM_VALUE_HANDLER *ha;
822 } UDM_UNARY_OPERATOR;
823 
824 
825 static UDM_UNARY_OPERATOR unary_operators[]=
826 {
827   {UDM_UNARY_OPERATOR_PREFIX_INC, &UdmValueHandlerInt},
828   {UDM_UNARY_OPERATOR_PREFIX_DEC, &UdmValueHandlerInt},
829   {UDM_UNARY_OPERATOR_POSTFIX_INC, &UdmValueHandlerInt},
830   {UDM_UNARY_OPERATOR_POSTFIX_DEC, &UdmValueHandlerInt},
831 
832   {UDM_UNARY_OPERATOR_PREFIX_INC,  &UdmValueHandlerChar},
833   {UDM_UNARY_OPERATOR_PREFIX_DEC,  &UdmValueHandlerChar},
834   {UDM_UNARY_OPERATOR_POSTFIX_INC, &UdmValueHandlerChar},
835   {UDM_UNARY_OPERATOR_POSTFIX_DEC, &UdmValueHandlerChar},
836 
837   {UDM_UNARY_OPERATOR_PREFIX_INC,  &UdmValueHandlerDouble},
838   {UDM_UNARY_OPERATOR_PREFIX_DEC,  &UdmValueHandlerDouble},
839   {UDM_UNARY_OPERATOR_POSTFIX_INC, &UdmValueHandlerDouble},
840   {UDM_UNARY_OPERATOR_POSTFIX_DEC, &UdmValueHandlerDouble},
841 
842   {UDM_UNARY_OPERATOR_PREFIX_INC, NULL}
843 };
844 
845 
846 static const UDM_UNARY_OPERATOR *
UdmUnaryOperatorFind(const UDM_UNARY_OPERATOR * ops,udm_unary_operator_t op,const UDM_VALUE_HANDLER * h1)847 UdmUnaryOperatorFind(const UDM_UNARY_OPERATOR *ops,
848                      udm_unary_operator_t op,
849                      const UDM_VALUE_HANDLER *h1)
850 {
851   for (  ; ops->ha; ops++)
852   {
853     if (ops->ha == h1 && ops->op == op)
854       return ops;
855   }
856   return NULL;
857 }
858 
859 
860 static const UDM_UNARY_OPERATOR *
UdmUnaryOperatorFindWithError(UDM_PROG_COMPILER * compiler,const UDM_UNARY_OPERATOR * ops,udm_unary_operator_t op,const UDM_VALUE_HANDLER * ha,const char * name)861 UdmUnaryOperatorFindWithError(UDM_PROG_COMPILER *compiler,
862                               const UDM_UNARY_OPERATOR *ops,
863                               udm_unary_operator_t op,
864                               const UDM_VALUE_HANDLER *ha,
865                               const char *name)
866 {
867   const UDM_UNARY_OPERATOR *res;
868   if ((res= UdmUnaryOperatorFind(ops, op, ha)))
869     return res;
870   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
871                "%d: no operator '%s' declared for '%s'",
872                (int) UdmProgCompilerLineno(compiler),
873                name, ha->type_name);
874   return NULL;
875 }
876 
877 
878 typedef struct
879 {
880   const UDM_VALUE_HANDLER *h1;
881   const UDM_VALUE_HANDLER *h2;
882   const UDM_VALUE_HANDLER *res; /* Aggregate type for h1 and h2 */
883 } UDM_DYADIC_OPERATOR;
884 
885 
886 static UDM_DYADIC_OPERATOR assignment_operators[]=
887 {
888   {&UdmValueHandlerDouble,    &UdmValueHandlerDouble,    NULL},
889   {&UdmValueHandlerDouble,    &UdmValueHandlerInt,       NULL},
890   {&UdmValueHandlerDouble,    &UdmValueHandlerChar,      NULL},
891   {&UdmValueHandlerInt,       &UdmValueHandlerDouble,    NULL},
892   {&UdmValueHandlerInt,       &UdmValueHandlerInt,       NULL},
893   {&UdmValueHandlerInt,       &UdmValueHandlerChar,      NULL},
894   {&UdmValueHandlerChar,      &UdmValueHandlerDouble,    NULL},
895   {&UdmValueHandlerChar,      &UdmValueHandlerInt,       NULL},
896   {&UdmValueHandlerChar,      &UdmValueHandlerChar,      NULL},
897   {&UdmValueHandlerSimple,    &UdmValueHandlerSimple,    NULL},
898   {&UdmValueHandlerQueryWord, &UdmValueHandlerQueryWord, NULL},
899   {NULL, NULL}
900 };
901 
902 
903 static const UDM_DYADIC_OPERATOR *
UdmDyadicOperatorFind(UDM_DYADIC_OPERATOR * ops,const UDM_VALUE_HANDLER * h1,const UDM_VALUE_HANDLER * h2)904 UdmDyadicOperatorFind(UDM_DYADIC_OPERATOR *ops,
905                       const UDM_VALUE_HANDLER *h1,
906                       const UDM_VALUE_HANDLER *h2)
907 {
908   const UDM_DYADIC_OPERATOR *op;
909   for (op= ops; op->h1; op++)
910   {
911     if (op->h1 == h1 && op->h2 == h2)
912       return op;
913   }
914   return NULL;
915 }
916 
917 
918 static udm_bool_t
UdmCompilerErrorInvalidOperands(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * h1,const UDM_VALUE_HANDLER * h2,const char * name)919 UdmCompilerErrorInvalidOperands(UDM_PROG_COMPILER *compiler,
920                                 const UDM_VALUE_HANDLER *h1,
921                                 const UDM_VALUE_HANDLER *h2,
922                                 const char *name)
923 {
924   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
925                "%d: Invalid operands of types for '%s' and '%s' to operator '%s'",
926                (int) UdmProgCompilerLineno(compiler),
927                h1->type_name, h2->type_name, name);
928   return UDM_FALSE;
929 }
930 
931 
932 static const UDM_DYADIC_OPERATOR *
UdmDyadicOperatorFindWithError(UDM_PROG_COMPILER * compiler,UDM_DYADIC_OPERATOR * ops,const UDM_VALUE_HANDLER * h1,const UDM_VALUE_HANDLER * h2,const char * name)933 UdmDyadicOperatorFindWithError(UDM_PROG_COMPILER *compiler,
934                                UDM_DYADIC_OPERATOR *ops,
935                                const UDM_VALUE_HANDLER *h1,
936                                const UDM_VALUE_HANDLER *h2,
937                                const char *name)
938 {
939   const UDM_DYADIC_OPERATOR *op;
940   if ((op= UdmDyadicOperatorFind(ops, h1, h2)))
941     return op;
942   UdmCompilerErrorInvalidOperands(compiler, h1, h2, name);
943   return NULL;
944 }
945 
946 
947 static udm_bool_t
UdmProgCompilerError(const UDM_PROG_COMPILER * compiler)948 UdmProgCompilerError(const UDM_PROG_COMPILER *compiler)
949 {
950   return compiler->errstr[0] != '\0';
951 }
952 
953 
954 static void
UdmProgCompilerScan(UDM_PROG_COMPILER * compiler)955 UdmProgCompilerScan(UDM_PROG_COMPILER *compiler)
956 {
957   UdmPIScanLexToken(&compiler->scanner, &compiler->scanner.token);
958 }
959 
960 
961 static udm_lex_t
UdmProgCompilerLastTokenType(const UDM_PROG_COMPILER * compiler)962 UdmProgCompilerLastTokenType(const UDM_PROG_COMPILER *compiler)
963 {
964   return compiler->scanner.token.type;
965 }
966 
967 
968 static udm_bool_t
ParseTerm(UDM_PROG_COMPILER * compiler,udm_lex_t term)969 ParseTerm(UDM_PROG_COMPILER *compiler, udm_lex_t term)
970 {
971   if (UdmProgCompilerError(compiler))
972     return UDM_FALSE;
973   if (UdmProgCompilerLastTokenType(compiler) != term)
974     return UDM_FALSE;
975   UdmProgCompilerScan(compiler);
976   return UDM_TRUE;
977 }
978 
979 
980 static udm_bool_t
ParseTermOrError(UDM_PROG_COMPILER * compiler,udm_lex_t term)981 ParseTermOrError(UDM_PROG_COMPILER *compiler, udm_lex_t term)
982 {
983   if (UdmProgCompilerError(compiler))
984     return UDM_FALSE;
985   if (UdmProgCompilerLastTokenType(compiler) != term)
986   {
987     udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
988                  "%d: ERROR: Expected %s got %s",
989                  (int) UdmProgCompilerLineno(compiler),
990                  UdmLex2str(term),
991                  UdmLex2str(UdmProgCompilerLastTokenType(compiler)));
992     return UDM_FALSE;
993   }
994   UdmProgCompilerScan(compiler);
995   return UDM_TRUE;
996 }
997 
998 
999 static udm_bool_t
UdmProgCompilerErrorMultiCharacter(UDM_PROG_COMPILER * compiler)1000 UdmProgCompilerErrorMultiCharacter(UDM_PROG_COMPILER *compiler)
1001 {
1002   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1003                "%d: error: multi-character character constant",
1004                (int) UdmProgCompilerLineno(compiler));
1005   return UDM_FALSE;
1006 }
1007 
1008 
1009 static udm_bool_t
UdmProgCompilerGenericError(UDM_PROG_COMPILER * compiler,const char * msg)1010 UdmProgCompilerGenericError(UDM_PROG_COMPILER *compiler, const char *msg)
1011 {
1012   if (!UdmProgCompilerError(compiler))
1013     udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1014                  "%d: ERROR: %s",
1015                  (int) UdmProgCompilerLineno(compiler), msg);
1016   return UDM_FALSE;
1017 }
1018 
1019 
1020 static udm_bool_t
UdmProgCompilerExpectedRule(UDM_PROG_COMPILER * compiler,const char * expected)1021 UdmProgCompilerExpectedRule(UDM_PROG_COMPILER *compiler, const char *expected)
1022 {
1023   if (!UdmProgCompilerError(compiler))
1024     udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1025                  "%d: ERROR: Expected %s got %s",
1026                  (int) UdmProgCompilerLineno(compiler), expected,
1027                  UdmLex2str(UdmProgCompilerLastTokenType(compiler)));
1028   return UDM_FALSE;
1029 }
1030 
1031 
1032 static udm_bool_t
UdmProgCompilerNotSupported(UDM_PROG_COMPILER * compiler,const char * msg)1033 UdmProgCompilerNotSupported(UDM_PROG_COMPILER *compiler, const char *msg)
1034 {
1035   if (!UdmProgCompilerError(compiler))
1036     udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1037                  "%d: ERROR: %s is not supported",
1038                  (int) UdmProgCompilerLineno(compiler), msg);
1039   return UDM_FALSE;
1040 }
1041 
1042 
1043 static udm_bool_t
UdmProgCompilerExponentHasNoDigits(UDM_PROG_COMPILER * compiler)1044 UdmProgCompilerExponentHasNoDigits(UDM_PROG_COMPILER *compiler)
1045 {
1046   if (!UdmProgCompilerError(compiler))
1047     udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1048                  "%d: ERROR: exponent has no digits",
1049                  (int) UdmProgCompilerLineno(compiler));
1050   return UDM_FALSE;
1051 }
1052 
1053 
1054 static udm_bool_t
UdmProgCompilerExponentInvalidSuffix(UDM_PROG_COMPILER * compiler,const UDM_CONST_TOKEN * exponent)1055 UdmProgCompilerExponentInvalidSuffix(UDM_PROG_COMPILER *compiler,
1056                                      const UDM_CONST_TOKEN *exponent)
1057 {
1058   if (!UdmProgCompilerError(compiler))
1059     udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1060                  "%d: ERROR: invalid suffix \"%.*s\" on floating exponent",
1061                  (int) UdmProgCompilerLineno(compiler),
1062                  (int) (exponent->end - exponent->str), exponent->str);
1063   return UDM_FALSE;
1064 }
1065 
1066 
1067 static udm_bool_t
UdmProgCompilerUnknownIdentifierError(UDM_PROG_COMPILER * compiler,const UDM_CONST_TOKEN * name)1068 UdmProgCompilerUnknownIdentifierError(UDM_PROG_COMPILER *compiler,
1069                                       const UDM_CONST_TOKEN *name)
1070 {
1071   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1072                "%d: ERROR: Unknown identifier '%.*s'",
1073                (int) UdmProgCompilerLineno(compiler),
1074                (int) (name->end - name->str), name->str);
1075   return UDM_FALSE;
1076 }
1077 
1078 
1079 static udm_bool_t
UdmProgCompilerBadDataTypeForArg(UDM_PROG_COMPILER * compiler,size_t argno,const UDM_VALUE_HANDLER * expected,const UDM_VALUE_HANDLER * actual)1080 UdmProgCompilerBadDataTypeForArg(UDM_PROG_COMPILER *compiler, size_t argno,
1081                                  const UDM_VALUE_HANDLER *expected,
1082                                  const UDM_VALUE_HANDLER *actual)
1083 {
1084   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1085                "%d: ERROR: Bad data type for argument #%d: expected '%s', got '%s'",
1086                (int) UdmProgCompilerLineno(compiler),
1087                (int) argno, expected->type_name, actual->type_name);
1088   return UDM_FALSE;
1089 }
1090 
1091 
1092 static udm_bool_t
UdmProgCompilerBadDataTypeForOperator2(UDM_PROG_COMPILER * compiler,const char * name,const UDM_VALUE_HANDLER * arg1,const UDM_VALUE_HANDLER * arg2)1093 UdmProgCompilerBadDataTypeForOperator2(UDM_PROG_COMPILER *compiler,
1094                                        const char *name,
1095                                        const UDM_VALUE_HANDLER *arg1,
1096                                        const UDM_VALUE_HANDLER *arg2)
1097 {
1098   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1099                "%d: ERROR: Invalid operands to binary operator '%s' "
1100                "(have '%s' and '%s')",
1101                (int) UdmProgCompilerLineno(compiler),
1102                name, arg1->type_name, arg2->type_name);
1103   return UDM_FALSE;
1104 }
1105 
1106 
1107 typedef struct
1108 {
1109   UDM_CONST_STR name;
1110   UDM_VALUE_HANDLER *handler;
1111 } UDM_TYPE_SPECIFIER;
1112 
1113 #define STD_TYPE_SPECIFIER(x, h) {{UDM_CSTR_WITH_LEN(x)}, h}
1114 
1115 static UDM_TYPE_SPECIFIER std_type_specifiers[]=
1116 {
1117   STD_TYPE_SPECIFIER("string", &UdmValueHandlerSimple),
1118   STD_TYPE_SPECIFIER("ENV", &UdmValueHandlerEnv),
1119   STD_TYPE_SPECIFIER("RESULT", &UdmValueHandlerResult),
1120   STD_TYPE_SPECIFIER("DOCUMENT", &UdmValueHandlerDocument),
1121   STD_TYPE_SPECIFIER("QUERYWORD", &UdmValueHandlerQueryWord),
1122   {{0, 0}}
1123 };
1124 
1125 /*
1126 <type-specifier> ::= void
1127                    | char
1128                    | short
1129                    | int
1130                    | long
1131                    | float
1132                    | double
1133                    | signed
1134                    | unsigned
1135                    | <struct-or-union-specifier>
1136                    | <enum-specifier>
1137                    | <typedef-name>
1138 */
1139 static const UDM_VALUE_HANDLER *
FindTypeByName(const UDM_CONST_TOKEN * name)1140 FindTypeByName(const UDM_CONST_TOKEN *name)
1141 {
1142   UDM_TYPE_SPECIFIER *t;
1143   for (t= std_type_specifiers; t->name.str; t++)
1144   {
1145     size_t name_length= name->end - name->str;
1146     if (name_length == t->name.length &&
1147         !memcmp(name->str, t->name.str, name_length))
1148       return t->handler;
1149   }
1150   return NULL;
1151 }
1152 
1153 
1154 static udm_bool_t
ParseTypeSpecifier(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** ha)1155 ParseTypeSpecifier(UDM_PROG_COMPILER *compiler,
1156                    const UDM_VALUE_HANDLER **ha)
1157 {
1158   if (ParseTerm(compiler, UDM_LEX_CHAR))
1159   {
1160     ha[0]= &UdmValueHandlerChar;
1161     return UDM_TRUE;
1162   }
1163   if (ParseTerm(compiler, UDM_LEX_INT))
1164   {
1165     ha[0]= &UdmValueHandlerInt;
1166     return UDM_TRUE;
1167   }
1168   if (ParseTerm(compiler, UDM_LEX_DOUBLE))
1169   {
1170     ha[0]= &UdmValueHandlerDouble;
1171     return UDM_TRUE;
1172   }
1173   if (UdmProgCompilerLastTokenType(compiler) != UDM_LEX_IDENT)
1174     return UDM_FALSE;
1175   if (!(ha[0]= FindTypeByName(&compiler->scanner.token.token)))
1176     return UDM_FALSE;
1177   return ParseTerm(compiler, UDM_LEX_IDENT);
1178 }
1179 
1180 
1181 /**
1182   This needs to do look-ahead for one more step, to distinguish between:
1183     x= (ident);            // a parenthesized expression
1184     x= (type) expression;  // a type cast
1185 */
1186 static udm_bool_t
TestParenthesizedTypeSpecifier(UDM_PROG_COMPILER * compiler)1187 TestParenthesizedTypeSpecifier(UDM_PROG_COMPILER *compiler)
1188 {
1189   udm_bool_t rc;
1190   UDM_LEX_SCANNER scanner;
1191   const UDM_VALUE_HANDLER *ha;
1192   if (UdmProgCompilerLastTokenType(compiler) != UDM_LEX_LP)
1193     return UDM_FALSE;
1194   scanner= compiler->scanner;
1195   if (!ParseTerm(compiler, UDM_LEX_LP))
1196   {
1197     UDM_ASSERT(0);
1198     return UDM_FALSE;
1199   }
1200   rc= ParseTypeSpecifier(compiler, &ha) && ParseTerm(compiler, UDM_LEX_RP);
1201   compiler->scanner= scanner; /* Rollback to the initial state */
1202   return rc;
1203 }
1204 
1205 
1206 /*
1207 <declaration-specifier> ::= <storage-class-specifier>
1208                           | <type-specifier>
1209                           | <type-qualifier>
1210 */
1211 static udm_bool_t
ParseDeclarationSpecifier(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** ha)1212 ParseDeclarationSpecifier(UDM_PROG_COMPILER *compiler,
1213                           const UDM_VALUE_HANDLER **ha)
1214 {
1215   return ParseTypeSpecifier(compiler, ha);
1216 }
1217 
1218 
1219 static void
UdmDSTRAppendArgTypes(UDM_DSTR * dstr,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * arglist)1220 UdmDSTRAppendArgTypes(UDM_DSTR *dstr,
1221                       const UDM_PROG_FUNCTION_CALL_ARGUMENTS *arglist)
1222 {
1223   size_t i;
1224   for (i= 0; i <  arglist->nargs; i++)
1225   {
1226     if (i > 0)
1227       UdmDSTRAppend(dstr, ",", 1);
1228     UdmDSTRAppendSTR(dstr, UdmPrimaryExprHandler(&arglist->args[i])->type_name);
1229   }
1230 }
1231 
1232 
1233 static udm_bool_t
UdmProgCompilerErrorUnknownFunction(UDM_PROG_COMPILER * compiler,const UDM_CONST_TOKEN * name,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * arglist)1234 UdmProgCompilerErrorUnknownFunction(UDM_PROG_COMPILER *compiler,
1235                                     const UDM_CONST_TOKEN *name,
1236                                     const UDM_PROG_FUNCTION_CALL_ARGUMENTS *arglist)
1237 {
1238   UDM_DSTR dstr;
1239   UdmDSTRInit(&dstr, 128);
1240   UdmDSTRAppendf(&dstr, "%d: ERROR: unknown function: %.*s(",
1241                  (int) UdmProgCompilerLineno(compiler),
1242                  (int) UdmConstTokenLength(name), UdmConstTokenStr(name));
1243   UdmDSTRAppendArgTypes(&dstr, arglist);
1244   UdmDSTRAppend(&dstr, ")", 1);
1245   udm_snprintf(compiler->errstr, sizeof(compiler->errstr), "%.*s",
1246                (int) UdmDSTRLength(&dstr), UdmDSTRPtr(&dstr));
1247   UdmDSTRFree(&dstr);
1248   return UDM_FALSE;
1249 }
1250 
1251 
1252 static udm_bool_t
UdmProgCompilerUnknownMethodError(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler,const UDM_CONST_TOKEN * name,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * args)1253 UdmProgCompilerUnknownMethodError(UDM_PROG_COMPILER *compiler,
1254                                   const UDM_VALUE_HANDLER *handler,
1255                                   const UDM_CONST_TOKEN *name,
1256                                   const UDM_PROG_FUNCTION_CALL_ARGUMENTS *args)
1257 {
1258   size_t i;
1259   UDM_DSTR dstr;
1260   UdmDSTRInit(&dstr, 128);
1261   UdmDSTRAppendf(&dstr, "%d: ERROR: %s has no method '%.*s(",
1262                (int) UdmProgCompilerLineno(compiler),
1263                handler->type_name, (int) UdmConstTokenLength(name),
1264                UdmConstTokenStr(name));
1265   for (i= 0; i < args->nargs; i++)
1266   {
1267     UdmDSTRAppendf(&dstr, "%s%s&", i > 0 ? "," : "",
1268                    UdmPrimaryExprHandler(&args->args[i])->type_name);
1269   }
1270   UdmDSTRAppend(&dstr, ")'", 2);
1271   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1272                "%.*s", (int) UdmDSTRLength(&dstr), UdmDSTRPtr(&dstr));
1273   UdmDSTRFree(&dstr);
1274   return UDM_FALSE;
1275 }
1276 
1277 
1278 static udm_bool_t
UdmProgCompilerVoidValueIsNotIgnored(UDM_PROG_COMPILER * compiler)1279 UdmProgCompilerVoidValueIsNotIgnored(UDM_PROG_COMPILER *compiler)
1280 {
1281   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
1282                "%d: ERROR: void value is not ignored as it ought to be",
1283                (int) UdmProgCompilerLineno(compiler));
1284   return UDM_FALSE;
1285 }
1286 
1287 
1288 static udm_bool_t
UdmProgGenerateVariableItemWithComment(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var,UDM_PROG_ITEM * it)1289 UdmProgGenerateVariableItemWithComment(UDM_PROG_COMPILER *compiler,
1290                                        const UDM_PROG_VAR *Var,
1291                                        UDM_PROG_ITEM *it)
1292 {
1293   UdmProgItemArgInitFromVar(&it->item_args, Var);
1294   if (compiler->generate_debug_info)
1295     it->comment= UdmConstTokenStrDup(&Var->name);
1296   return UdmProgAdd(compiler->prg, it) == UDM_OK;
1297 }
1298 
1299 
1300 static udm_bool_t
UdmGenerateVariableOp(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var,udm_tmpl_cmd_t op)1301 UdmGenerateVariableOp(UDM_PROG_COMPILER *compiler,
1302                       const UDM_PROG_VAR *Var,
1303                       udm_tmpl_cmd_t op)
1304 {
1305   UDM_PROG_ITEM i;
1306   UdmProgItemInit(&i);
1307   i.cmdnum= op;
1308   return UdmProgGenerateVariableItemWithComment(compiler, Var, &i);
1309 }
1310 
1311 
1312 static udm_bool_t
UdmGenerateVariableOperation(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var,UDM_PROG_CMD * cmd)1313 UdmGenerateVariableOperation(UDM_PROG_COMPILER *compiler,
1314                              const UDM_PROG_VAR *Var,
1315                              UDM_PROG_CMD *cmd)
1316 {
1317   UDM_PROG_ITEM i;
1318   UdmProgItemInit(&i);
1319   i.cmd= cmd;
1320   return UdmProgGenerateVariableItemWithComment(compiler, Var, &i);
1321 }
1322 
1323 
1324 static udm_bool_t
UdmGenerateConstructor(UDM_PROG_COMPILER * c,const UDM_PROG_VAR * Var)1325 UdmGenerateConstructor(UDM_PROG_COMPILER *c, const UDM_PROG_VAR *Var)
1326 {
1327   return UdmGenerateVariableOperation(c, Var, &udm_tmpl_construct_var);
1328 }
1329 
1330 
1331 static udm_bool_t
UdmGenerateVariableOperationToIReg0(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var)1332 UdmGenerateVariableOperationToIReg0(UDM_PROG_COMPILER *compiler,
1333                                     const UDM_PROG_VAR *Var)
1334 {
1335   if (UdmProgVarHandler(Var)->datatype == UDM_VALUE_DATA_TYPE_INT)
1336   {
1337     UDM_PROG_ITEM it;
1338     UdmProgItemInit(&it);
1339     it.cmdnum= UDM_PROG_MOV_IREG0_INT_PTR_STACK_OFFSET;
1340     return UdmProgGenerateVariableItemWithComment(compiler, Var, &it);
1341   }
1342   return UdmGenerateVariableOperation(compiler, Var, &udm_tmpl_mov_ireg0_var0);
1343 }
1344 
1345 
1346 static udm_bool_t
UdmGenerateVariableOperationToDReg0(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var)1347 UdmGenerateVariableOperationToDReg0(UDM_PROG_COMPILER *compiler,
1348                                     const UDM_PROG_VAR *Var)
1349 {
1350   if (UdmProgVarHandler(Var)->datatype == UDM_VALUE_DATA_TYPE_DOUBLE)
1351   {
1352     UDM_PROG_ITEM it;
1353     UdmProgItemInit(&it);
1354     it.cmdnum= UDM_PROG_MOV_DREG0_DBL_PTR_STACK_OFFSET;
1355     return UdmProgGenerateVariableItemWithComment(compiler, Var, &it);
1356   }
1357   return UdmGenerateVariableOperation(compiler, Var, &udm_tmpl_mov_dreg0_var0);
1358 }
1359 
1360 
1361 static udm_bool_t
UdmGenerateVariableOperationToIReg1(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var)1362 UdmGenerateVariableOperationToIReg1(UDM_PROG_COMPILER *compiler,
1363                                     const UDM_PROG_VAR *Var)
1364 {
1365   if (UdmProgVarHandler(Var)->datatype == UDM_VALUE_DATA_TYPE_INT)
1366   {
1367     UDM_PROG_ITEM it;
1368     UdmProgItemInit(&it);
1369     it.cmdnum= UDM_PROG_MOV_IREG1_INT_PTR_STACK_OFFSET;
1370     return UdmProgGenerateVariableItemWithComment(compiler, Var, &it);
1371   }
1372   return UdmGenerateVariableOperation(compiler, Var, &udm_tmpl_mov_ireg1_var0);
1373 }
1374 
1375 
1376 static udm_bool_t
UdmGenerateVariableOperationToDReg1(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var)1377 UdmGenerateVariableOperationToDReg1(UDM_PROG_COMPILER *compiler,
1378                                     const UDM_PROG_VAR *Var)
1379 {
1380   if (UdmProgVarHandler(Var)->datatype == UDM_VALUE_DATA_TYPE_DOUBLE)
1381   {
1382     UDM_PROG_ITEM it;
1383     UdmProgItemInit(&it);
1384     it.cmdnum= UDM_PROG_MOV_DREG1_DBL_PTR_STACK_OFFSET;
1385     return UdmProgGenerateVariableItemWithComment(compiler, Var, &it);
1386   }
1387   return UdmGenerateVariableOperation(compiler, Var, &udm_tmpl_mov_dreg1_var0);
1388 }
1389 
1390 
1391 static udm_bool_t
UdmGenerateBooleanTest(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler,udm_bool_t positive)1392 UdmGenerateBooleanTest(UDM_PROG_COMPILER *compiler,
1393                        const UDM_VALUE_HANDLER *handler,
1394                        udm_bool_t positive)
1395 {
1396   if (!handler)
1397     return UdmProgCompilerVoidValueIsNotIgnored(compiler);
1398   switch (handler->datatype)
1399   {
1400   case UDM_VALUE_DATA_TYPE_CHAR:
1401   case UDM_VALUE_DATA_TYPE_INT:
1402   case UDM_VALUE_DATA_TYPE_DOUBLE:
1403     break;
1404   case UDM_VALUE_DATA_TYPE_STR:
1405   case UDM_VALUE_DATA_TYPE_ENV:
1406   case UDM_VALUE_DATA_TYPE_RESULT:
1407   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1408   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1409   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1410     return UdmProgCompilerNotSupported(compiler, "boolean test for data type");
1411   }
1412 
1413   if (handler == &UdmValueHandlerInt)
1414   {
1415     if (UDM_OK != UdmProgAddArg0SimpleOp(compiler->prg,
1416                                          UDM_PROG_MOV_IREG1_0))
1417       return UDM_FALSE;
1418     if (UDM_OK != UdmProgAddArg0SimpleOp(compiler->prg,
1419                                           positive ?
1420                                           UDM_PROG_CMP_IREG0_IREG1_NE:
1421                                           UDM_PROG_CMP_IREG0_IREG1_EQ))
1422       return UDM_FALSE;
1423   }
1424   else
1425   {
1426     if (UDM_OK != UdmProgAddArg0SimpleOp(compiler->prg,
1427                                          UDM_PROG_MOV_DREG1_0))
1428       return UDM_FALSE;
1429     if (UDM_OK != UdmProgAddArg0SimpleOp(compiler->prg,
1430                                          positive ?
1431                                          UDM_PROG_CMP_DREG0_DREG1_NE :
1432                                          UDM_PROG_CMP_DREG0_DREG1_EQ))
1433       return UDM_FALSE;
1434   }
1435   return UDM_TRUE;
1436 }
1437 
1438 
1439 /*
1440   Store the value of (!expr) into ireg0.
1441 */
1442 static udm_bool_t
UdmGenerateIsNotTrueTest(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler)1443 UdmGenerateIsNotTrueTest(UDM_PROG_COMPILER *compiler,
1444                          const UDM_VALUE_HANDLER *handler)
1445 {
1446   return UdmGenerateBooleanTest(compiler, handler, UDM_FALSE);
1447 }
1448 
1449 
1450 static udm_bool_t
UdmGenerateIsTrueTest(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler)1451 UdmGenerateIsTrueTest(UDM_PROG_COMPILER *compiler,
1452                       const UDM_VALUE_HANDLER *handler)
1453 {
1454   return UdmGenerateBooleanTest(compiler, handler, UDM_TRUE);
1455 }
1456 
1457 
1458 
1459 static udm_bool_t
UdmGenerateSwapNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler)1460 UdmGenerateSwapNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1461                               const UDM_VALUE_HANDLER *handler)
1462 {
1463   return UdmGenerateOp(compiler,
1464                        handler->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE ?
1465                        UDM_PROG_SWP_DREG0_DREG1:
1466                        UDM_PROG_SWP_IREG0_IREG1);
1467 }
1468 
1469 
1470 static udm_bool_t
UdmGenerateAddNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** handler,udm_lex_t op)1471 UdmGenerateAddNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1472                              const UDM_VALUE_HANDLER **handler,
1473                              udm_lex_t op)
1474 {
1475   UDM_ASSERT(op == UDM_LEX_PLUS || op == UDM_LEX_MINUS);
1476   switch (handler[0]->native_reg_type)
1477   {
1478   case UDM_VALUE_DATA_TYPE_CHAR:
1479   case UDM_VALUE_DATA_TYPE_INT:
1480     return UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg,
1481                                             op == UDM_LEX_PLUS ?
1482                                             UDM_PROG_ADD_IREG0_IREG1 :
1483                                             UDM_PROG_SUB_IREG0_IREG1);
1484 
1485   case UDM_VALUE_DATA_TYPE_DOUBLE:
1486     return UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg,
1487                                             op == UDM_LEX_PLUS ?
1488                                             UDM_PROG_ADD_DREG0_DREG1:
1489                                             UDM_PROG_SUB_DREG0_DREG1);
1490   case UDM_VALUE_DATA_TYPE_STR:
1491   case UDM_VALUE_DATA_TYPE_ENV:
1492   case UDM_VALUE_DATA_TYPE_RESULT:
1493   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1494   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1495   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1496     break;
1497   }
1498   UDM_ASSERT(0);
1499   return UDM_FALSE;
1500 }
1501 
1502 
1503 static udm_bool_t
UdmGenerateMulNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** handler,udm_lex_t op)1504 UdmGenerateMulNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1505                              const UDM_VALUE_HANDLER **handler,
1506                              udm_lex_t op)
1507 {
1508   UDM_ASSERT(op == UDM_LEX_ASTERISK || op == UDM_LEX_SLASH || op == UDM_LEX_PERCENT);
1509   switch (handler[0]->native_reg_type)
1510   {
1511   case UDM_VALUE_DATA_TYPE_CHAR:
1512   case UDM_VALUE_DATA_TYPE_INT:
1513     return UdmGenerateOp(compiler, op == UDM_LEX_ASTERISK ?
1514                                    UDM_PROG_MUL_IREG0_IREG1 :
1515                                    op == UDM_LEX_SLASH ?
1516                                    UDM_PROG_DIV_IREG0_IREG1 :
1517                                    UDM_PROG_REM_IREG0_IREG1);
1518   case UDM_VALUE_DATA_TYPE_DOUBLE:
1519     if (op == UDM_LEX_PERCENT)
1520       return UdmProgCompilerNotSupported(compiler, "binary operator % for the `double` data type");
1521     return UdmGenerateOp(compiler, op == UDM_LEX_ASTERISK ?
1522                                    UDM_PROG_MUL_DREG0_DREG1 :
1523                                    UDM_PROG_DIV_DREG0_DREG1);
1524   case UDM_VALUE_DATA_TYPE_STR:
1525   case UDM_VALUE_DATA_TYPE_ENV:
1526   case UDM_VALUE_DATA_TYPE_RESULT:
1527   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1528   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1529   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1530     break;
1531   }
1532   UDM_ASSERT(0);
1533   return UDM_FALSE;
1534 }
1535 
1536 
1537 static udm_bool_t
UdmGenerateShiftNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** handler,udm_lex_t op)1538 UdmGenerateShiftNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1539                              const UDM_VALUE_HANDLER **handler,
1540                              udm_lex_t op)
1541 {
1542   UDM_ASSERT(op == UDM_LEX_LSHIFT || op == UDM_LEX_RSHIFT);
1543   switch (handler[0]->native_reg_type)
1544   {
1545   case UDM_VALUE_DATA_TYPE_CHAR:
1546   case UDM_VALUE_DATA_TYPE_INT:
1547     return UdmGenerateOp(compiler, op == UDM_LEX_LSHIFT ?
1548                                    UDM_PROG_SHL_IREG0_IREG1 :
1549                                    UDM_PROG_SHR_IREG0_IREG1);
1550   case UDM_VALUE_DATA_TYPE_DOUBLE:
1551     return UdmProgCompilerNotSupported(compiler, "<< and >> for this data type");
1552   case UDM_VALUE_DATA_TYPE_STR:
1553   case UDM_VALUE_DATA_TYPE_ENV:
1554   case UDM_VALUE_DATA_TYPE_RESULT:
1555   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1556   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1557   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1558     break;
1559   }
1560   UDM_ASSERT(0);
1561   return UDM_FALSE;
1562 }
1563 
1564 
1565 static udm_bool_t
UdmGenerateRelNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** handler,udm_lex_t op)1566 UdmGenerateRelNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1567                              const UDM_VALUE_HANDLER **handler,
1568                              udm_lex_t op)
1569 {
1570   UDM_ASSERT(op == UDM_LEX_LE || op == UDM_LEX_LT ||
1571              op == UDM_LEX_GT || op == UDM_LEX_GE);
1572   switch (handler[0]->native_reg_type)
1573   {
1574   case UDM_VALUE_DATA_TYPE_CHAR:
1575   case UDM_VALUE_DATA_TYPE_INT:
1576     switch (op)
1577     {
1578     case UDM_LEX_LE: return UdmGenerateOp(compiler, UDM_PROG_CMP_IREG0_IREG1_LE);
1579     case UDM_LEX_LT: return UdmGenerateOp(compiler, UDM_PROG_CMP_IREG0_IREG1_LT);
1580     case UDM_LEX_GT: return UdmGenerateOp(compiler, UDM_PROG_CMP_IREG0_IREG1_GT);
1581     case UDM_LEX_GE: return UdmGenerateOp(compiler, UDM_PROG_CMP_IREG0_IREG1_GE);
1582     default:
1583       break;
1584     }
1585     break;
1586   case UDM_VALUE_DATA_TYPE_DOUBLE:
1587     *handler= &UdmValueHandlerInt;
1588     switch (op)
1589     {
1590     case UDM_LEX_LE: return UdmGenerateOp(compiler, UDM_PROG_CMP_DREG0_DREG1_LE);
1591     case UDM_LEX_LT: return UdmGenerateOp(compiler, UDM_PROG_CMP_DREG0_DREG1_LT);
1592     case UDM_LEX_GT: return UdmGenerateOp(compiler, UDM_PROG_CMP_DREG0_DREG1_GT);
1593     case UDM_LEX_GE: return UdmGenerateOp(compiler, UDM_PROG_CMP_DREG0_DREG1_GE);
1594     default:
1595       break;
1596     }
1597     break;
1598 
1599   case UDM_VALUE_DATA_TYPE_STR:
1600   case UDM_VALUE_DATA_TYPE_ENV:
1601   case UDM_VALUE_DATA_TYPE_RESULT:
1602   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1603   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1604   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1605     break;
1606   }
1607   UDM_ASSERT(0);
1608   return UDM_FALSE;
1609 }
1610 
1611 
1612 static udm_bool_t
UdmGenerateEqNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** handler,udm_lex_t op)1613 UdmGenerateEqNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1614                             const UDM_VALUE_HANDLER **handler,
1615                             udm_lex_t op)
1616 {
1617   UDM_ASSERT(op == UDM_LEX_EQ_EQ || op == UDM_LEX_NOT_EQ);
1618   switch (handler[0]->native_reg_type)
1619   {
1620   case UDM_VALUE_DATA_TYPE_CHAR:
1621   case UDM_VALUE_DATA_TYPE_INT:
1622     switch (op)
1623     {
1624     case UDM_LEX_EQ_EQ:  return UdmGenerateOp(compiler, UDM_PROG_CMP_IREG0_IREG1_EQ);
1625     case UDM_LEX_NOT_EQ: return UdmGenerateOp(compiler, UDM_PROG_CMP_IREG0_IREG1_NE);
1626     default:
1627       break;
1628     }
1629     break;
1630   case UDM_VALUE_DATA_TYPE_DOUBLE:
1631     *handler= &UdmValueHandlerInt;
1632     switch (op)
1633     {
1634     case UDM_LEX_EQ_EQ:  return UdmGenerateOp(compiler, UDM_PROG_CMP_DREG0_DREG1_EQ);
1635     case UDM_LEX_NOT_EQ: return UdmGenerateOp(compiler, UDM_PROG_CMP_DREG0_DREG1_NE);
1636     default:
1637       break;
1638     }
1639     break;
1640   case UDM_VALUE_DATA_TYPE_STR:
1641   case UDM_VALUE_DATA_TYPE_ENV:
1642   case UDM_VALUE_DATA_TYPE_RESULT:
1643   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1644   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1645   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1646     break;
1647   }
1648   UDM_ASSERT(0);
1649   return UDM_FALSE;
1650 }
1651 
1652 
1653 static udm_bool_t
UdmGenerateAndNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** handler,udm_lex_t op)1654 UdmGenerateAndNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1655                              const UDM_VALUE_HANDLER **handler,
1656                              udm_lex_t op)
1657 {
1658   UDM_ASSERT(op == UDM_LEX_AMPERSAND);
1659   switch (handler[0]->native_reg_type)
1660   {
1661   case UDM_VALUE_DATA_TYPE_CHAR:
1662   case UDM_VALUE_DATA_TYPE_INT:
1663     return UdmGenerateOp(compiler, UDM_PROG_AND_IREG0_IREG1);
1664   case UDM_VALUE_DATA_TYPE_DOUBLE:
1665     return UdmProgCompilerNotSupported(compiler, "binary & for this data type");
1666   case UDM_VALUE_DATA_TYPE_STR:
1667   case UDM_VALUE_DATA_TYPE_ENV:
1668   case UDM_VALUE_DATA_TYPE_RESULT:
1669   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1670   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1671   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1672     break;
1673   }
1674   UDM_ASSERT(0);
1675   return UDM_FALSE;
1676 }
1677 
1678 
1679 static udm_bool_t
UdmGenerateXorNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** handler,udm_lex_t op)1680 UdmGenerateXorNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1681                              const UDM_VALUE_HANDLER **handler,
1682                              udm_lex_t op)
1683 {
1684   UDM_ASSERT(op == UDM_LEX_CARET);
1685   switch (handler[0]->native_reg_type)
1686   {
1687   case UDM_VALUE_DATA_TYPE_CHAR:
1688   case UDM_VALUE_DATA_TYPE_INT:
1689     return UdmGenerateOp(compiler, UDM_PROG_XOR_IREG0_IREG1);
1690   case UDM_VALUE_DATA_TYPE_DOUBLE:
1691     return UdmProgCompilerNotSupported(compiler, "binary ^ for this data type");
1692   case UDM_VALUE_DATA_TYPE_STR:
1693   case UDM_VALUE_DATA_TYPE_ENV:
1694   case UDM_VALUE_DATA_TYPE_RESULT:
1695   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1696   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1697   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1698     break;
1699   }
1700   UDM_ASSERT(0);
1701   return UDM_FALSE;
1702 }
1703 
1704 
1705 static udm_bool_t
UdmGenerateOrNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** handler,udm_lex_t op)1706 UdmGenerateOrNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1707                             const UDM_VALUE_HANDLER **handler,
1708                             udm_lex_t op)
1709 {
1710   UDM_ASSERT(op == UDM_LEX_VBAR);
1711   switch (handler[0]->native_reg_type)
1712   {
1713   case UDM_VALUE_DATA_TYPE_CHAR:
1714   case UDM_VALUE_DATA_TYPE_INT:
1715     return UdmGenerateOp(compiler, UDM_PROG_OR_IREG0_IREG1);
1716   case UDM_VALUE_DATA_TYPE_DOUBLE:
1717     return UdmProgCompilerNotSupported(compiler, "binary | for this data type");
1718   case UDM_VALUE_DATA_TYPE_STR:
1719   case UDM_VALUE_DATA_TYPE_ENV:
1720   case UDM_VALUE_DATA_TYPE_RESULT:
1721   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1722   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1723   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1724     break;
1725   }
1726   UDM_ASSERT(0);
1727   return UDM_FALSE;
1728 }
1729 
1730 
1731 static udm_bool_t
UdmGenerateDiadicOperationNativeReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER ** handler,udm_lex_t op)1732 UdmGenerateDiadicOperationNativeReg0Reg1(UDM_PROG_COMPILER *compiler,
1733                                          const UDM_VALUE_HANDLER **handler,
1734                                          udm_lex_t op)
1735 {
1736   switch (op)
1737   {
1738   case UDM_LEX_VBAR:
1739     return UdmGenerateOrNativeReg0Reg1(compiler, handler, op);
1740   case UDM_LEX_CARET:
1741     return UdmGenerateXorNativeReg0Reg1(compiler, handler, op);
1742   case UDM_LEX_AMPERSAND:
1743     return UdmGenerateAndNativeReg0Reg1(compiler, handler, op);
1744   case UDM_LEX_EQ_EQ:
1745   case UDM_LEX_NOT_EQ:
1746     return UdmGenerateEqNativeReg0Reg1(compiler, handler, op);
1747   case UDM_LEX_LE:
1748   case UDM_LEX_GE:
1749   case UDM_LEX_LT:
1750   case UDM_LEX_GT:
1751     return UdmGenerateRelNativeReg0Reg1(compiler, handler, op);
1752   case UDM_LEX_ASTERISK:
1753   case UDM_LEX_SLASH:
1754   case UDM_LEX_PERCENT:
1755     return UdmGenerateMulNativeReg0Reg1(compiler, handler, op);
1756   case UDM_LEX_PLUS:
1757   case UDM_LEX_MINUS:
1758     return UdmGenerateAddNativeReg0Reg1(compiler, handler, op);
1759   case UDM_LEX_LSHIFT:
1760   case UDM_LEX_RSHIFT:
1761     return UdmGenerateShiftNativeReg0Reg1(compiler, handler, op);
1762   default:
1763     UDM_ASSERT(0);
1764   }
1765   return UDM_FALSE;
1766 }
1767 
1768 
1769 static udm_bool_t
UdmGenerateVarToNativeReg0(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * src)1770 UdmGenerateVarToNativeReg0(UDM_PROG_COMPILER *compiler,
1771                            const UDM_PROG_VAR *src)
1772 {
1773   switch (UdmProgVarHandler(src)->datatype)
1774   {
1775   case UDM_VALUE_DATA_TYPE_INT:
1776     return UdmGenerateVariableOperationToIReg0(compiler, src);
1777   case UDM_VALUE_DATA_TYPE_CHAR:
1778     return UdmGenerateVariableOperation(compiler, src, &udm_tmpl_mov_ireg0_var0);
1779   case UDM_VALUE_DATA_TYPE_DOUBLE:
1780     return UdmGenerateVariableOperationToDReg0(compiler, src);
1781   default:
1782     return UdmGenerateVariableOperation(compiler, src, &udm_tmpl_get_var_to_cs0_z0);
1783   }
1784   UDM_ASSERT(0);
1785   return UDM_FALSE;
1786 }
1787 
1788 
1789 static udm_bool_t
UdmGenerateVarToNativeReg1(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * src)1790 UdmGenerateVarToNativeReg1(UDM_PROG_COMPILER *compiler,
1791                            const UDM_PROG_VAR *src)
1792 {
1793   switch (UdmProgVarHandler(src)->datatype)
1794   {
1795   case UDM_VALUE_DATA_TYPE_INT:
1796     return UdmGenerateVariableOperationToIReg1(compiler, src);
1797   case UDM_VALUE_DATA_TYPE_CHAR:
1798     return UdmGenerateVariableOperation(compiler, src, &udm_tmpl_mov_ireg1_var0);
1799   case UDM_VALUE_DATA_TYPE_DOUBLE:
1800     return UdmGenerateVariableOperationToDReg1(compiler, src);
1801   default:
1802     return UdmProgCompilerNotSupported(compiler, "Variable of a complex type in this context");
1803   }
1804   UDM_ASSERT(0);
1805   return UDM_FALSE;
1806 }
1807 
1808 
1809 static udm_bool_t
UdmGenerateNativeReg0ToVar(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var)1810 UdmGenerateNativeReg0ToVar(UDM_PROG_COMPILER *compiler,
1811                            const UDM_PROG_VAR *Var)
1812 {
1813   switch (UdmProgVarHandler(Var)->datatype)
1814   {
1815   case UDM_VALUE_DATA_TYPE_INT:
1816   case UDM_VALUE_DATA_TYPE_CHAR:
1817     return UdmGenerateVariableOperation(compiler, Var, &udm_tmpl_set_var_from_ireg0);
1818   case UDM_VALUE_DATA_TYPE_DOUBLE:
1819     return UdmGenerateVariableOperation(compiler, Var, &udm_tmpl_set_var_from_dreg0);
1820   default:
1821     UDM_ASSERT(0);
1822     return UDM_FALSE;
1823   }
1824   UDM_ASSERT(0);
1825   return UDM_FALSE;
1826 }
1827 
1828 
1829 static udm_bool_t
UdmGenerateLiteralToNativeRegNInt(UDM_PROG_COMPILER * compiler,const UDM_PROG_PRIMARY_EXPRESSION * expr,size_t regno)1830 UdmGenerateLiteralToNativeRegNInt(UDM_PROG_COMPILER *compiler,
1831                                   const UDM_PROG_PRIMARY_EXPRESSION *expr,
1832                                   size_t regno)
1833 {
1834   udm_tmpl_cmd_t cmd= !regno ? UDM_PROG_MOV_IREG0_INT : UDM_PROG_MOV_IREG1_INT;
1835   int tmp= udm_strntoi(expr->Var.name.str, expr->Var.name.end - expr->Var.name.str);
1836   if (UDM_OK != UdmProgAddArg1SimpleOpInt(compiler->prg, cmd, tmp))
1837     return UDM_FALSE;
1838   return UDM_TRUE;
1839 }
1840 
1841 
1842 static udm_bool_t
UdmGenerateLiteralToNativeRegNDbl(UDM_PROG_COMPILER * compiler,const UDM_PROG_PRIMARY_EXPRESSION * expr,size_t regno)1843 UdmGenerateLiteralToNativeRegNDbl(UDM_PROG_COMPILER *compiler,
1844                                   const UDM_PROG_PRIMARY_EXPRESSION *expr,
1845                                   size_t regno)
1846 {
1847   udm_tmpl_cmd_t cmd= !regno ? UDM_PROG_MOV_DREG0_DBL : UDM_PROG_MOV_DREG1_DBL;
1848   double tmp= udm_strntod(expr->Var.name.str, expr->Var.name.end - expr->Var.name.str);
1849   if (UDM_OK != UdmProgAddArg1SimpleOpDouble(compiler->prg, cmd, tmp))
1850     return UDM_FALSE;
1851   return UDM_TRUE;
1852 }
1853 
1854 
1855 static udm_bool_t
UdmGenerateLiteralToNativeRegNChar(UDM_PROG_COMPILER * compiler,const UDM_PROG_PRIMARY_EXPRESSION * expr,size_t regno)1856 UdmGenerateLiteralToNativeRegNChar(UDM_PROG_COMPILER *compiler,
1857                                    const UDM_PROG_PRIMARY_EXPRESSION *expr,
1858                                    size_t regno)
1859 {
1860   udm_tmpl_cmd_t cmd= !regno ? UDM_PROG_MOV_IREG0_INT : UDM_PROG_MOV_IREG1_INT;
1861   return UDM_OK == UdmProgAddArg1SimpleOpInt(compiler->prg,
1862                                              cmd, expr->Var.name.str[0]);
1863 }
1864 
1865 
1866 static udm_bool_t
UdmGenerateTextSegmentTo_cs0_z0(UDM_PROG_COMPILER * compiler,udm_offset_and_length_t addr)1867 UdmGenerateTextSegmentTo_cs0_z0(UDM_PROG_COMPILER *compiler,
1868                                 udm_offset_and_length_t addr)
1869 {
1870   UDM_PROG_ITEM i;
1871   UdmProgItemInit(&i);
1872   i.cmd= &udm_tmpl_textdata_to_cs0_z0;
1873   i.item_args.textdata_addr= addr;
1874   return UDM_OK == UdmProgAdd(compiler->prg, &i);
1875 }
1876 
1877 
1878 static udm_bool_t
UdmGenerateMovNativeReg0ToReg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler)1879 UdmGenerateMovNativeReg0ToReg1(UDM_PROG_COMPILER *compiler,
1880                                const UDM_VALUE_HANDLER *handler)
1881 {
1882   switch (handler->native_reg_type)
1883   {
1884   case UDM_VALUE_DATA_TYPE_INT:
1885     return UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_IREG1_IREG0);
1886   case UDM_VALUE_DATA_TYPE_DOUBLE:
1887     return UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_DREG1_DREG0);
1888   default:
1889     UDM_ASSERT(0);
1890   }
1891   return UDM_FALSE;
1892 }
1893 
1894 
1895 static udm_bool_t
UdmGenerateClearNativeReg0(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler)1896 UdmGenerateClearNativeReg0(UDM_PROG_COMPILER *compiler,
1897                            const UDM_VALUE_HANDLER *handler)
1898 {
1899   switch (handler->native_reg_type)
1900   {
1901   case UDM_VALUE_DATA_TYPE_INT:
1902     return UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_IREG0_0);
1903   case UDM_VALUE_DATA_TYPE_DOUBLE:
1904     return UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_DREG0_0);
1905   default:
1906     UDM_ASSERT(0);
1907   }
1908   return UDM_FALSE;
1909 }
1910 
1911 
1912 static udm_bool_t
UdmGenerateLiteralToNativeRegN(UDM_PROG_COMPILER * compiler,const UDM_PROG_PRIMARY_EXPRESSION * expr,size_t regno)1913 UdmGenerateLiteralToNativeRegN(UDM_PROG_COMPILER *compiler,
1914                                const UDM_PROG_PRIMARY_EXPRESSION *expr,
1915                                size_t regno)
1916 {
1917   switch (UdmPrimaryExprHandler(expr)->datatype)
1918   {
1919   case UDM_VALUE_DATA_TYPE_DOUBLE:
1920     return UdmGenerateLiteralToNativeRegNDbl(compiler, expr, regno);
1921   case UDM_VALUE_DATA_TYPE_INT:
1922     return UdmGenerateLiteralToNativeRegNInt(compiler, expr, regno);
1923   case UDM_VALUE_DATA_TYPE_CHAR:
1924     return UdmGenerateLiteralToNativeRegNChar(compiler, expr, regno);
1925   case UDM_VALUE_DATA_TYPE_STR:
1926     UDM_ASSERT(regno == 0);
1927     return UdmGenerateTextSegmentTo_cs0_z0(compiler, expr->textdata_addr);
1928   case UDM_VALUE_DATA_TYPE_ENV:
1929   case UDM_VALUE_DATA_TYPE_RESULT:
1930   case UDM_VALUE_DATA_TYPE_DOCUMENT:
1931   case UDM_VALUE_DATA_TYPE_SQLRESULT:
1932   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
1933     break;
1934   }
1935   UDM_ASSERT(0);
1936   return UDM_TRUE;
1937 }
1938 
1939 
1940 static udm_bool_t
UdmGenerateExpressionToNativeReg0(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,const UDM_PROG_VAR * func_result)1941 UdmGenerateExpressionToNativeReg0(UDM_PROG_COMPILER *compiler,
1942                                   UDM_PROG_EXPRESSION *expr,
1943                                   const UDM_PROG_VAR *func_result)
1944 {
1945   switch (expr->primary_expr.type)
1946   {
1947     case UDM_EXPRESSION_CONST:
1948       expr->primary_expr.type= UDM_EXPRESSION_COMPUTED;
1949       return UdmGenerateLiteralToNativeRegN(compiler, &expr->primary_expr, 0);
1950     case UDM_EXPRESSION_IDENT:
1951       expr->primary_expr.type= UDM_EXPRESSION_COMPUTED;
1952       return UdmGenerateVarToNativeReg0(compiler, &expr->primary_expr.Var);
1953     case UDM_EXPRESSION_OBJECT:
1954       expr->primary_expr.type= UDM_EXPRESSION_COMPUTED;
1955       if (func_result && UdmProgVarHandler(func_result))
1956         return UdmGenerateVarToNativeReg0(compiler, func_result);
1957       else
1958         return UDM_TRUE; /* Simple type: char, int, double */
1959     case UDM_EXPRESSION_COMPUTED:
1960       return UDM_TRUE;
1961   }
1962   UDM_ASSERT(0);
1963   return UdmProgCompilerNotSupported(compiler, "cout with postfix expression of this type");
1964 }
1965 
1966 
1967 static udm_bool_t
UdmGenerateNativeReg0TypeConversion(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * dst,const UDM_VALUE_HANDLER * src)1968 UdmGenerateNativeReg0TypeConversion(UDM_PROG_COMPILER *compiler,
1969                                     const UDM_VALUE_HANDLER *dst,
1970                                     const UDM_VALUE_HANDLER *src)
1971 {
1972   if (dst->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE &&
1973       src->native_reg_type == UDM_VALUE_DATA_TYPE_INT)
1974   {
1975     if (UDM_OK != UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_DREG0_IREG0))
1976       return UDM_FALSE;
1977   }
1978   else if (dst->native_reg_type == UDM_VALUE_DATA_TYPE_INT &&
1979            src->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE)
1980   {
1981     if (UDM_OK != UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_IREG0_DREG0))
1982       return UDM_FALSE;
1983   }
1984   return UDM_TRUE; /* No conversion needed */
1985 }
1986 
1987 
1988 static udm_bool_t
UdmGenerateNativeReg1TypeConversion(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * dst,const UDM_VALUE_HANDLER * src)1989 UdmGenerateNativeReg1TypeConversion(UDM_PROG_COMPILER *compiler,
1990                                     const UDM_VALUE_HANDLER *dst,
1991                                     const UDM_VALUE_HANDLER *src)
1992 {
1993   if (dst->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE &&
1994       src->native_reg_type == UDM_VALUE_DATA_TYPE_INT)
1995   {
1996     if (UDM_OK != UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_DREG1_IREG1))
1997       return UDM_FALSE;
1998   }
1999   else if (dst->native_reg_type == UDM_VALUE_DATA_TYPE_INT &&
2000            src->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE)
2001   {
2002     if (UDM_OK != UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_IREG1_DREG1))
2003       return UDM_FALSE;
2004   }
2005   return UDM_TRUE; /* No conversion needed */
2006 }
2007 
2008 
2009 static size_t
UdmValueHandlerAlignedDataSize(const UDM_VALUE_HANDLER * handler)2010 UdmValueHandlerAlignedDataSize(const UDM_VALUE_HANDLER *handler)
2011 {
2012   size_t data_size= handler->DataSize();
2013   if (data_size < sizeof(void*))
2014     data_size= sizeof(void*);
2015   return data_size;
2016 }
2017 
2018 
2019 static udm_bool_t
UdmGenerateDeclareNonInitializedVariableWithName(UDM_PROG_COMPILER * compiler,UDM_PROG_VARLIST * Vars,const UDM_PROG_VAR * PIVar,const char * name)2020 UdmGenerateDeclareNonInitializedVariableWithName(UDM_PROG_COMPILER *compiler,
2021                                                  UDM_PROG_VARLIST *Vars,
2022                                                  const UDM_PROG_VAR *PIVar,
2023                                                  const char *name)
2024 {
2025   size_t data_size;
2026   UDM_ASSERT(compiler->Vars2.nitems);
2027   if (UdmProgVarListFind(Vars, name))
2028   {
2029     UDM_ASSERT(name[0] != '/'); /* Not a temporary variable */
2030     return UdmProgCompilerRedeclarationError(compiler, name);
2031   }
2032   /*fprintf(stderr, "stackaddr=%d name=%s type=%s\n",
2033            (int) UdmProgCompilerNextVarStackOffset(compiler),
2034            name, PIVar->handler->type_name);*/
2035 
2036   data_size= UdmValueHandlerAlignedDataSize(UdmProgVarHandler(PIVar));
2037   if (UDM_OK != UdmProgCompilerNextVarStackOffsetIncrement(compiler, data_size) ||
2038       UDM_OK != UdmProgVarListAdd(Vars, name, &PIVar->value))
2039     return UDM_FALSE;
2040   return UDM_TRUE;
2041 }
2042 
2043 
2044 /**
2045   Create a named or a temporary variable on the last stack level.
2046 */
2047 static udm_bool_t
UdmGenerateDeclareNonInitializedVariable(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * PIVar)2048 UdmGenerateDeclareNonInitializedVariable(UDM_PROG_COMPILER *compiler,
2049                                          const UDM_PROG_VAR *PIVar)
2050 {
2051   char name[128];
2052   size_t name_length= UdmConstTokenLength(&PIVar->name);
2053   UDM_PROG_VARLIST *Vars= &compiler->Vars2.Item[compiler->Vars2.nitems - 1];
2054   if (name_length)
2055     udm_snprintf(name, sizeof(name), "%.*s",
2056                  (int) (PIVar->name.end - PIVar->name.str), PIVar->name.str);
2057   else
2058     udm_snprintf(name, sizeof(name), "/tmp_%03X", (int) Vars->nitems);
2059   return UdmGenerateDeclareNonInitializedVariableWithName(compiler, Vars,
2060                                                           PIVar, name);
2061 }
2062 
2063 
2064 static const UDM_PROG_VAR2 *
UdmProgCompilerFindVariable(UDM_PROG_COMPILER * compiler,UDM_CONST_TOKEN * str)2065 UdmProgCompilerFindVariable(UDM_PROG_COMPILER *compiler,
2066                             UDM_CONST_TOKEN *str)
2067 {
2068   size_t i;
2069   char name[128]; /* TODO34: find by name+length */
2070   udm_snprintf(name, sizeof(name), "%.*s",
2071                (int) (str->end - str->str), str->str);
2072   for (i= compiler->Vars2.nitems; i > 0; i--)
2073   {
2074     const UDM_PROG_VAR2 *Var= UdmProgVarListFind(&compiler->Vars2.Item[i - 1],
2075                                                  name);
2076     if (Var)
2077       return Var;
2078   }
2079   return NULL;
2080 }
2081 
2082 
2083 static udm_bool_t
ParseIdentifier(UDM_PROG_COMPILER * compiler,UDM_CONST_TOKEN * ident)2084 ParseIdentifier(UDM_PROG_COMPILER *compiler, UDM_CONST_TOKEN *ident)
2085 {
2086   if (UdmProgCompilerLastTokenType(compiler) == UDM_LEX_IDENT)
2087     *ident= compiler->scanner.token.token;
2088   return ParseTerm(compiler, UDM_LEX_IDENT);
2089 }
2090 
2091 
2092 static udm_bool_t
ParseUnsignedNumber(UDM_PROG_COMPILER * compiler,UDM_PROG_VAR * Var)2093 ParseUnsignedNumber(UDM_PROG_COMPILER *compiler, UDM_PROG_VAR *Var)
2094 {
2095   UDM_CONST_TOKEN exponent;
2096   if (UdmProgCompilerLastTokenType(compiler) != UDM_LEX_UINT)
2097     return UDM_FALSE;
2098   Var->name= compiler->scanner.token.token;
2099   UdmProgVarSetHandler(Var, &UdmValueHandlerInt);
2100   if (!ParseTerm(compiler, UDM_LEX_UINT))
2101   {
2102     UDM_ASSERT(0);
2103     return UDM_FALSE;
2104   }
2105   if (ParseTerm(compiler, UDM_LEX_DOT))
2106   {
2107     UdmProgVarSetHandler(Var, &UdmValueHandlerDouble);
2108     if (UdmProgCompilerLastTokenType(compiler) == UDM_LEX_UINT)
2109     {
2110       Var->name.end= compiler->scanner.token.token.end;
2111       if (!ParseTerm(compiler, UDM_LEX_UINT))
2112       {
2113         UDM_ASSERT(0);
2114         return UDM_FALSE;
2115       }
2116     }
2117   }
2118   if (UdmProgCompilerLastTokenType(compiler) != UDM_LEX_IDENT)
2119     return UDM_TRUE;
2120   UdmProgVarSetHandler(Var, &UdmValueHandlerDouble);
2121   exponent= compiler->scanner.token.token;
2122   UDM_ASSERT(exponent.end - exponent.str > 0);
2123   if (exponent.str[0] != 'E' && exponent.str[0] != 'e')
2124     return UDM_TRUE;
2125   if (!ParseTerm(compiler, UDM_LEX_IDENT))
2126   {
2127     UDM_ASSERT(0);
2128     return UDM_FALSE;
2129   }
2130   if (exponent.end - exponent.str > 1) /* e123 was scanned as UDM_LEX_IDENT*/
2131   {
2132     const char *e;
2133     if (!udm_isdigit(exponent.str[1]))
2134       return UdmProgCompilerExponentHasNoDigits(compiler);
2135     for (e= exponent.str + 2; e < exponent.end; e++)
2136     {
2137       if (!udm_isdigit(*e))
2138       {
2139         exponent.str= e;
2140         return UdmProgCompilerExponentInvalidSuffix(compiler, &exponent);
2141       }
2142     }
2143     Var->name.end= exponent.end;
2144     return UDM_TRUE;
2145   }
2146   if (!ParseTerm(compiler, UDM_LEX_MINUS) &&
2147       !ParseTerm(compiler, UDM_LEX_PLUS))
2148     return UdmProgCompilerExponentHasNoDigits(compiler); /* e.g. 123e; */
2149   if (UdmProgCompilerLastTokenType(compiler) != UDM_LEX_UINT)
2150     return UdmProgCompilerExponentHasNoDigits(compiler); /* e.g. 123e+; */
2151   Var->name.end= compiler->scanner.token.token.end;
2152   if (!ParseTerm(compiler, UDM_LEX_UINT))
2153   {
2154     UDM_ASSERT(0);
2155     return UDM_FALSE;
2156   }
2157   return UDM_TRUE;
2158 }
2159 
2160 
2161 static udm_bool_t
ParseString(UDM_PROG_COMPILER * compiler,UDM_CONST_TOKEN * string)2162 ParseString(UDM_PROG_COMPILER *compiler, UDM_CONST_TOKEN *string)
2163 {
2164   if (UdmProgCompilerLastTokenType(compiler) != UDM_LEX_STRING &&
2165       UdmProgCompilerLastTokenType(compiler) != UDM_LEX_ESCAPED_STRING)
2166     return UDM_FALSE;
2167   *string= compiler->scanner.token.token;
2168   UdmProgCompilerScan(compiler);
2169   return UDM_TRUE;
2170 }
2171 
2172 
2173 static udm_bool_t
ParseChar(UDM_PROG_COMPILER * compiler,UDM_CONST_TOKEN * string)2174 ParseChar(UDM_PROG_COMPILER *compiler, UDM_CONST_TOKEN *string)
2175 {
2176   if (UdmProgCompilerLastTokenType(compiler) == UDM_LEX_CHAR_LITERAL)
2177   {
2178     *string= compiler->scanner.token.token;
2179     if (UdmConstTokenLength(string) != 1 &&
2180         string->str[0] != '\\')
2181       return UdmProgCompilerErrorMultiCharacter(compiler);
2182   }
2183   return ParseTerm(compiler, UDM_LEX_CHAR_LITERAL);
2184 }
2185 
2186 
2187 static udm_bool_t
ParseLCB(UDM_PROG_COMPILER * compiler)2188 ParseLCB(UDM_PROG_COMPILER *compiler)
2189 {
2190   return ParseTerm(compiler, UDM_LEX_LCB);
2191 }
2192 
2193 
2194 static udm_bool_t
ParsePrimaryExpressionIdentifier(UDM_PROG_COMPILER * compiler,UDM_PROG_PRIMARY_EXPRESSION * expr)2195 ParsePrimaryExpressionIdentifier(UDM_PROG_COMPILER *compiler,
2196                                  UDM_PROG_PRIMARY_EXPRESSION *expr)
2197 {
2198   if (ParseIdentifier(compiler, &expr->Var.name))
2199   {
2200     const UDM_PROG_VAR2 *Var= UdmProgCompilerFindVariable(compiler,
2201                                                     &expr->Var.name);
2202     if (Var)
2203       expr->Var.value= Var->value;
2204     else
2205       UDM_BZERO(&expr->Var.value, sizeof(expr->Var.value));
2206     expr->type= UDM_EXPRESSION_IDENT;
2207     return UDM_TRUE;
2208   }
2209   return UDM_FALSE;
2210 }
2211 
2212 
2213 static int
CharUnescape(int ch)2214 CharUnescape(int ch)
2215 {
2216   switch (ch)
2217   {
2218   case 'n': return '\n';
2219   case 'r': return '\r';
2220   case 't': return '\t';
2221   case '0': return '\0';
2222   }
2223   return ch;
2224 }
2225 
2226 
2227 static udm_bool_t
UdmCreateTextSegmentEntry(UDM_PROG_COMPILER * compiler,udm_offset_and_length_t * addr,const char * src,size_t length,udm_bool_t unescape,udm_bool_t append)2228 UdmCreateTextSegmentEntry(UDM_PROG_COMPILER *compiler,
2229                          udm_offset_and_length_t *addr,
2230                          const char *src, size_t length,
2231                          udm_bool_t unescape,
2232                          udm_bool_t append)
2233 {
2234   if (append)
2235   {
2236     UDM_ASSERT(UdmDSTRLength(&compiler->prg->textdata));
2237     UdmDSTRShrinkLast(&compiler->prg->textdata);
2238   }
2239   addr->offset= UdmDSTRLength(&compiler->prg->textdata);
2240   /*
2241   fprintf(stderr, "CREATE: pos=%d len=%d\n",
2242         (int) addr->offset,
2243         (int) length);
2244   */
2245   if (unescape)
2246   {
2247     const char *end;
2248     UdmDSTRReserve(&compiler->prg->textdata, length);
2249     for (end= src + length ; src < end; src++)
2250     {
2251       if (*src != '\\')
2252         UdmDSTRAppend(&compiler->prg->textdata, src, 1);
2253       else if (src + 1 < end)
2254       {
2255         char ch= CharUnescape(src[1]);
2256         UdmDSTRAppend(&compiler->prg->textdata, &ch, 1);
2257         src++;
2258       }
2259     }
2260   }
2261   else
2262     UdmDSTRAppend(&compiler->prg->textdata, src, length);
2263   addr->length= UdmDSTRLength(&compiler->prg->textdata) - addr->offset;
2264   UdmDSTRAppend(&compiler->prg->textdata, "\0", 1);
2265   return UDM_TRUE;
2266 }
2267 
2268 
2269 static udm_bool_t
UdmProgGenerateCoutStringFromTextSegment(UDM_PROG_COMPILER * compiler,udm_offset_and_length_t addr)2270 UdmProgGenerateCoutStringFromTextSegment(UDM_PROG_COMPILER *compiler,
2271                                          udm_offset_and_length_t addr)
2272 {
2273   return UdmGenerateTextSegmentTo_cs0_z0(compiler, addr) &&
2274          UDM_OK == UdmProgAddArg0Simple(compiler->prg, &udm_tmpl_cout_cs0_z0);
2275 }
2276 
2277 
2278 static udm_bool_t
UdmProgGenerateCoutText(UDM_PROG_COMPILER * compiler,const char * str,const char * strend,udm_bool_t unescape)2279 UdmProgGenerateCoutText(UDM_PROG_COMPILER *compiler,
2280                         const char *str,
2281                         const char *strend,
2282                         udm_bool_t unescape)
2283 {
2284   if (str && str != strend)
2285   {
2286     udm_offset_and_length_t addr;
2287     UdmCreateTextSegmentEntry(compiler, &addr, str, strend - str, unescape, UDM_FALSE);
2288     return UdmProgGenerateCoutStringFromTextSegment(compiler, addr);
2289   }
2290   return UDM_OK;
2291 }
2292 
2293 
2294 static udm_bool_t
ParsePrimaryExpressionString(UDM_PROG_COMPILER * compiler,UDM_PROG_PRIMARY_EXPRESSION * expr)2295 ParsePrimaryExpressionString(UDM_PROG_COMPILER *compiler, UDM_PROG_PRIMARY_EXPRESSION *expr)
2296 {
2297   UDM_CONST_TOKEN chunk;
2298   udm_offset_and_length_t addr;
2299   if (!ParseString(compiler, &expr->Var.name))
2300     return UDM_FALSE;
2301   expr->type= UDM_EXPRESSION_CONST;
2302   UdmProgVarSetHandler(&expr->Var, &UdmValueHandlerSimple);
2303   if (!UdmCreateTextSegmentEntry(compiler, &expr->textdata_addr,
2304                                    expr->Var.name.str,
2305                                    expr->Var.name.end - expr->Var.name.str,
2306                                    UDM_TRUE, UDM_FALSE))
2307     return UDM_FALSE;
2308   while (ParseString(compiler, &chunk))
2309   {
2310     if (!UdmCreateTextSegmentEntry(compiler, &addr,
2311                                    chunk.str, chunk.end - chunk.str,
2312                                    UDM_TRUE, UDM_TRUE))
2313       return UDM_FALSE;
2314     expr->textdata_addr.length+= addr.length;
2315   }
2316   return UDM_TRUE;
2317 }
2318 
2319 
2320 static udm_bool_t
ParsePrimaryExpressionUnsignedNumber(UDM_PROG_COMPILER * compiler,UDM_PROG_PRIMARY_EXPRESSION * expr)2321 ParsePrimaryExpressionUnsignedNumber(UDM_PROG_COMPILER *compiler,
2322                                      UDM_PROG_PRIMARY_EXPRESSION *expr)
2323 {
2324   if (!ParseUnsignedNumber(compiler, &expr->Var))
2325     return UDM_FALSE;
2326   expr->type= UDM_EXPRESSION_CONST;
2327   return UdmCreateTextSegmentEntry(compiler, &expr->textdata_addr,
2328                                    expr->Var.name.str,
2329                                    expr->Var.name.end - expr->Var.name.str,
2330                                    UDM_FALSE, UDM_FALSE);
2331 }
2332 
2333 
2334 static void
CharToStr(char * dst,const UDM_CONST_TOKEN * src)2335 CharToStr(char *dst, const UDM_CONST_TOKEN *src)
2336 {
2337   UDM_ASSERT(UdmConstTokenLength(src) > 0);
2338   if (src->str[0] == '\\')
2339   {
2340     UDM_ASSERT(UdmConstTokenLength(src) > 1);
2341     dst[0]= CharUnescape(src->str[1]);
2342   }
2343   else
2344     dst[0]= src->str[0];
2345   dst[1]= '\0';
2346 }
2347 
2348 
2349 static udm_bool_t
ParsePrimaryExpressionChar(UDM_PROG_COMPILER * compiler,UDM_PROG_PRIMARY_EXPRESSION * expr)2350 ParsePrimaryExpressionChar(UDM_PROG_COMPILER *compiler,
2351                            UDM_PROG_PRIMARY_EXPRESSION *expr)
2352 {
2353   if (!ParseChar(compiler, &expr->Var.name))
2354     return UDM_FALSE;
2355   CharToStr(expr->buf, &expr->Var.name);
2356   expr->Var.name.str= expr->buf;
2357   expr->Var.name.end= expr->buf + 1;
2358   expr->type= UDM_EXPRESSION_CONST;
2359   UdmProgVarSetHandler(&expr->Var, &UdmValueHandlerChar);
2360   return UdmCreateTextSegmentEntry(compiler, &expr->textdata_addr,
2361                                    expr->Var.name.str, 1,
2362                                    UDM_FALSE, UDM_FALSE);
2363 }
2364 
2365 
2366 /*
2367  <primary-expression> ::= <identifier>
2368                         | <constant>
2369                         | <string>
2370                         | ( <expression> )
2371 */
2372 static udm_bool_t
ParsePrimaryExpressionLiteral(UDM_PROG_COMPILER * compiler,UDM_PROG_PRIMARY_EXPRESSION * expr)2373 ParsePrimaryExpressionLiteral(UDM_PROG_COMPILER *compiler,
2374                               UDM_PROG_PRIMARY_EXPRESSION *expr)
2375 {
2376   if (ParsePrimaryExpressionString(compiler, expr))
2377     return UDM_TRUE;
2378   if (ParsePrimaryExpressionChar(compiler, expr))
2379     return UDM_TRUE;
2380   if (ParsePrimaryExpressionUnsignedNumber(compiler, expr))
2381     return UDM_TRUE;
2382   return UDM_FALSE;
2383 }
2384 
2385 /*
2386   TODO: move parsing of parenthesized expression to here.
2387 */
2388 static udm_bool_t
ParsePrimaryExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_PRIMARY_EXPRESSION * expr)2389 ParsePrimaryExpression(UDM_PROG_COMPILER *compiler, UDM_PROG_PRIMARY_EXPRESSION *expr)
2390 {
2391   if (ParsePrimaryExpressionIdentifier(compiler, expr))
2392     return UDM_TRUE;
2393   if (ParsePrimaryExpressionLiteral(compiler, expr))
2394     return UDM_TRUE;
2395   return UDM_FALSE;
2396 }
2397 
2398 
2399 /*
2400   <function-call-argument> ::= <assignment-expression>
2401 */
2402 static udm_bool_t
ParseFunctionCallArgument(UDM_PROG_COMPILER * compiler,UDM_PROG_PRIMARY_EXPRESSION * expr)2403 ParseFunctionCallArgument(UDM_PROG_COMPILER *compiler,
2404                           UDM_PROG_PRIMARY_EXPRESSION *expr)
2405 {
2406   if (ParsePrimaryExpressionIdentifier(compiler, expr))
2407   {
2408     if (!UdmPrimaryExprHandler(expr))
2409       return UdmProgCompilerUnknownIdentifierError(compiler, &expr->Var.name);
2410     return UDM_TRUE;
2411   }
2412   return ParsePrimaryExpressionLiteral(compiler, expr);
2413 }
2414 
2415 
2416 /*
2417 <function-call-argument> ::= <assignment-expression>
2418 
2419 <function-call-argument-list> ::=     <function-call-argument>
2420                                  {',' <function-call-argument>}*
2421 
2422 <function-call-arguments> ::= '(' <function-call-argument-list>? ')'
2423                             | '(' ')'
2424 */
2425 static udm_bool_t
ParseFunctionCallArguments(UDM_PROG_COMPILER * compiler,UDM_PROG_FUNCTION_CALL_ARGUMENTS * func)2426 ParseFunctionCallArguments(UDM_PROG_COMPILER *compiler,
2427                            UDM_PROG_FUNCTION_CALL_ARGUMENTS *func)
2428 {
2429   if (!ParseTerm(compiler, UDM_LEX_LP))
2430     return UDM_FALSE;
2431   func->nargs= 0;
2432   if (!ParseFunctionCallArgument(compiler, &func->args[0]))
2433   {
2434     if (UdmProgCompilerError(compiler))
2435       return UDM_FALSE;
2436     goto rp;
2437   }
2438   func->nargs= 1;
2439   for ( ; ; )
2440   {
2441     if (!ParseTerm(compiler, UDM_LEX_COMMA))
2442       break;
2443     if (func->nargs >= UDM_PROG_MAXARG)
2444     {
2445       udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
2446                    "In <function-call-arguments>: Too many arguments");
2447       return UDM_FALSE;
2448     }
2449     func->nargs++;
2450     if (!ParseFunctionCallArgument(compiler, &func->args[func->nargs - 1]))
2451       return UdmProgCompilerExpectedRule(compiler, "<function-call-argument>");
2452   }
2453 rp:
2454   return ParseTermOrError(compiler, UDM_LEX_RP);
2455 }
2456 
2457 
2458 /**
2459   Check if a function prototype is compatible with the actual paramenter.
2460   Returns UDM_TRUE  on failure (incompatible)
2461   Returns UDM_FALSE on success (compatible)
2462 */
2463 static udm_bool_t
UdmFunctionPrototypeCheck(const UDM_FUNCTION_PROTOTYPE * prototype,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * arglist,size_t offset)2464 UdmFunctionPrototypeCheck(const UDM_FUNCTION_PROTOTYPE *prototype,
2465                           const UDM_PROG_FUNCTION_CALL_ARGUMENTS *arglist,
2466                           size_t offset)
2467 {
2468   size_t i;
2469   for (i= 0; i < arglist->nargs; i++)
2470   {
2471     if (prototype->args[i + offset].handler !=
2472         UdmPrimaryExprHandler(&arglist->args[i]))
2473       return UDM_TRUE;
2474   }
2475   return UDM_FALSE;
2476 }
2477 
2478 
2479 static const UDM_FUNCTION *
UdmFunctionListFind(const UDM_FUNCTION * functions,const char * name,size_t length,const UDM_VALUE_HANDLER * handler_for_this,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * arglist,size_t offset)2480 UdmFunctionListFind(const UDM_FUNCTION *functions,
2481                     const char *name, size_t length,
2482                     const UDM_VALUE_HANDLER *handler_for_this,
2483                     const UDM_PROG_FUNCTION_CALL_ARGUMENTS *arglist,
2484                     size_t offset /* 0, or 1 in case of method */)
2485 {
2486   const UDM_FUNCTION *method;
2487   for (method= functions; method->name.str; method++)
2488   {
2489     if (handler_for_this &&
2490         handler_for_this != method->prototype.args[0].handler)
2491       continue;
2492     if (method->prototype.nargs == arglist->nargs + offset &&
2493         method->name.length == length &&
2494         !memcmp(method->name.str, name, length) &&
2495         !UdmFunctionPrototypeCheck(&method->prototype, arglist, offset))
2496       return method;
2497   }
2498   return NULL;
2499 }
2500 
2501 
2502 static const UDM_FUNCTION *
UdmValueHandlerMethodFind(const UDM_VALUE_HANDLER * ha,const char * name,size_t length,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * arglist)2503 UdmValueHandlerMethodFind(const UDM_VALUE_HANDLER *ha,
2504                           const char *name, size_t length,
2505                           const UDM_PROG_FUNCTION_CALL_ARGUMENTS *arglist)
2506 {
2507   if (!ha->method)
2508     return NULL;
2509   return UdmFunctionListFind(ha->method, name, length, ha, arglist, 1);
2510 }
2511 
2512 
2513 typedef struct
2514 {
2515   udm_tmpl_cmd_t create_ident;
2516   UDM_PROG_CMD *create_value;
2517   UDM_PROG_CMD *delete_value;
2518   UDM_PROG_CMD *clear_value;
2519 } UDM_CALL_ARG_CMD;
2520 
2521 
2522 #define UDM_MAX_FUNC_ARG 5
2523 
2524 static UDM_CALL_ARG_CMD call_arg_cmd[UDM_MAX_FUNC_ARG]=
2525 {
2526   {
2527     UDM_PROG_MOV_VREG0_STACK_OFFSET,
2528     &udm_method_make_arg0,
2529     &udm_method_free_arg0,
2530     &udm_method_clear_arg0
2531   },
2532   {
2533     UDM_PROG_MOV_VREG1_STACK_OFFSET,
2534     &udm_method_make_arg1,
2535     &udm_method_free_arg1,
2536     &udm_method_clear_arg1
2537   },
2538   {
2539     UDM_PROG_MOV_VREG2_STACK_OFFSET,
2540     &udm_method_make_arg2,
2541     &udm_method_free_arg2,
2542     &udm_method_clear_arg2
2543   },
2544   {
2545     UDM_PROG_MOV_VREG3_STACK_OFFSET,
2546     &udm_method_make_arg3,
2547     &udm_method_free_arg3,
2548     &udm_method_clear_arg3
2549   },
2550   {
2551     UDM_PROG_MOV_VREG4_STACK_OFFSET,
2552     &udm_method_make_arg4,
2553     &udm_method_free_arg4,
2554     &udm_method_clear_arg4
2555   }
2556 };
2557 
2558 
2559 /*
2560   Create a temporary value.
2561 */
2562 static udm_bool_t
UdmGenerateFunctionCallArgCreate(UDM_PROG_COMPILER * compiler,const UDM_PROG_PRIMARY_EXPRESSION * arg,size_t offset)2563 UdmGenerateFunctionCallArgCreate(UDM_PROG_COMPILER *compiler,
2564                                  const UDM_PROG_PRIMARY_EXPRESSION *arg,
2565                                  size_t offset)
2566 {
2567   UDM_PROG_ITEM item;
2568   UdmProgItemInit(&item);
2569   if (arg->type == UDM_EXPRESSION_IDENT)
2570   {
2571     return UdmGenerateOpOffset(compiler, call_arg_cmd[offset].create_ident,
2572                                arg->Var.value.stack_offset);
2573   }
2574   else
2575   {
2576     item.cmd= call_arg_cmd[offset].create_value;
2577     UdmProgItemArgInitFromLiteralAndHandler(&item.item_args, arg);
2578   }
2579   return UDM_OK == UdmProgAdd(compiler->prg, &item);
2580 }
2581 
2582 
2583 /*
2584   Setup a pointer to a variable, or create a temporary value.
2585 */
2586 static udm_bool_t
UdmGenerateFunctionCallArgSetup(UDM_PROG_COMPILER * compiler,const UDM_FUNCTION * func,const UDM_PROG_PRIMARY_EXPRESSION * arg,size_t argno)2587 UdmGenerateFunctionCallArgSetup(UDM_PROG_COMPILER *compiler,
2588                                 const UDM_FUNCTION *func,
2589                                 const UDM_PROG_PRIMARY_EXPRESSION *arg,
2590                                 size_t argno)
2591 {
2592   if (arg->type == UDM_EXPRESSION_IDENT)
2593   {
2594     if (!UdmPrimaryExprHandler(arg))
2595       return UdmProgCompilerUnknownIdentifierError(compiler, &arg->Var.name);
2596   }
2597   if (func->prototype.args[argno].handler != UdmPrimaryExprHandler(arg))
2598   {
2599     return UdmProgCompilerBadDataTypeForArg(compiler, argno,
2600                                             func->prototype.args[argno].handler,
2601                                             UdmPrimaryExprHandler(arg));
2602   }
2603   return UdmGenerateFunctionCallArgCreate(compiler, arg, argno);
2604 }
2605 
2606 
2607 static udm_bool_t
UdmGenerateFunctionCallArgDelete(UDM_PROG_COMPILER * compiler,const UDM_PROG_PRIMARY_EXPRESSION * arg,size_t offset)2608 UdmGenerateFunctionCallArgDelete(UDM_PROG_COMPILER *compiler,
2609                                  const UDM_PROG_PRIMARY_EXPRESSION *arg,
2610                                  size_t offset)
2611 {
2612   UDM_PROG_ITEM item;
2613   UdmProgItemInit(&item);
2614   item.cmd= arg->type == UDM_EXPRESSION_IDENT ?
2615             call_arg_cmd[offset].clear_value :
2616             call_arg_cmd[offset].delete_value;
2617   if (arg->type != UDM_EXPRESSION_IDENT)
2618     item.item_args.handler= UdmPrimaryExprHandler(arg);
2619   /*item.item_args.stack_offset= arg->Var.value.stack_offset;*/
2620   return UDM_OK == UdmProgAdd(compiler->prg, &item);
2621 }
2622 
2623 
2624 /**
2625   Returns UDM_TRUE if a function returning a value
2626   of the handler requires an object.
2627   Returns UDM_FALSE if the function can simply return
2628   the value in registers.
2629 */
2630 static udm_bool_t
UdmValueHandlerIsComplex(const UDM_VALUE_HANDLER * handler)2631 UdmValueHandlerIsComplex(const UDM_VALUE_HANDLER *handler)
2632 {
2633   switch (handler->datatype)
2634   {
2635   case UDM_VALUE_DATA_TYPE_INT:
2636   case UDM_VALUE_DATA_TYPE_DOUBLE:
2637   case UDM_VALUE_DATA_TYPE_CHAR:
2638     return UDM_FALSE;
2639   case UDM_VALUE_DATA_TYPE_STR:
2640   case UDM_VALUE_DATA_TYPE_ENV:
2641   case UDM_VALUE_DATA_TYPE_RESULT:
2642   case UDM_VALUE_DATA_TYPE_DOCUMENT:
2643   case UDM_VALUE_DATA_TYPE_SQLRESULT:
2644   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
2645     break;
2646   }
2647   return UDM_TRUE;
2648 }
2649 
2650 
2651 /**
2652   Initialize everything but name.
2653 */
2654 static void
UdmProgStackVarInitAttributes(UDM_PROG_VAR * Var,UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler)2655 UdmProgStackVarInitAttributes(UDM_PROG_VAR *Var,
2656                     UDM_PROG_COMPILER *compiler,
2657                     const UDM_VALUE_HANDLER *handler)
2658 {
2659   UdmProgVarSetHandler(Var, handler);
2660   Var->value.stack_offset= UdmProgCompilerNextVarStackOffset(compiler);
2661 }
2662 
2663 
2664 /**
2665   Construct a temporary variable on stack.
2666   Return its address on result->stack_offset.
2667 */
2668 static udm_bool_t
UdmGenerateReserveNonInitializedTemporaryVariableOnStack(UDM_PROG_COMPILER * c,const UDM_VALUE_HANDLER * handler,UDM_PROG_VAR * result)2669 UdmGenerateReserveNonInitializedTemporaryVariableOnStack(UDM_PROG_COMPILER *c,
2670                                               const UDM_VALUE_HANDLER *handler,
2671                                                         UDM_PROG_VAR *result)
2672 {
2673   UDM_BZERO(&result->name, sizeof(result->name));
2674   UdmProgStackVarInitAttributes(result, c, handler);
2675   if (!UdmGenerateDeclareNonInitializedVariable(c, result))
2676     return UDM_FALSE;
2677   if (UDM_OK != UdmProgAddValueHandler(c->prg, UDM_PROG_MOV_HREG0_PTR,
2678                                        handler))
2679     return UDM_FALSE;
2680   if (!UdmGenerateOpOffset(c, UDM_PROG_MOV_SREG0_STACK_OFFSET,
2681                            result->value.stack_offset))
2682     return UDM_FALSE;
2683   return UDM_TRUE;
2684 }
2685 
2686 
2687 static udm_bool_t
UdmGenerateFunctionReturnValue(UDM_PROG_COMPILER * compiler,const UDM_FUNCTION * func,UDM_PROG_VAR * result,const UDM_PROG_VAR * dstvar)2688 UdmGenerateFunctionReturnValue(UDM_PROG_COMPILER *compiler,
2689                                const UDM_FUNCTION *func,
2690                                UDM_PROG_VAR *result,
2691                                const UDM_PROG_VAR *dstvar)
2692 {
2693   /*
2694     TODO34: a better test for this. Perhaps a method in handler.
2695   */
2696 
2697   if (func->prototype.result.handler &&
2698       UdmValueHandlerIsComplex(func->prototype.result.handler))
2699   {
2700     if (!(!result ^ !dstvar))
2701     {
2702       /*
2703         Called from UdmParseConditionalExpression,
2704         with both result==NULL and dstvar==NULL.
2705       */
2706       /*UDM_ASSERT(0);*/
2707       return UdmProgCompilerNotSupported(compiler, "function call of this type in this context (e.g. in a conditional expression)");
2708     }
2709     UDM_ASSERT(!result ^ !dstvar); /* At least on of them should be set */
2710     if (dstvar) /* string x= str.upper(); */
2711     {
2712       if (func->prototype.result.handler != UdmProgVarHandler(dstvar))
2713         return UdmCompilerErrorInvalidOperands(compiler,
2714                                                func->prototype.result.handler,
2715                                                UdmProgVarHandler(dstvar), "=");
2716       if (UDM_OK != UdmProgAddValueHandler(compiler->prg, UDM_PROG_MOV_HREG0_PTR,
2717                                            func->prototype.result.handler))
2718         return UDM_FALSE;
2719       if (!UdmGenerateOpOffset(compiler, UDM_PROG_MOV_SREG0_STACK_OFFSET,
2720                                dstvar->value.stack_offset))
2721         return UDM_FALSE;
2722     }
2723     else if (result) /* Want complex return value on stack rather than to be alloced */
2724     {
2725       UDM_ASSERT(!UdmProgVarHandler(result)); /* Must be initialized */
2726       if (!UdmGenerateReserveNonInitializedTemporaryVariableOnStack(compiler,
2727                                               func->prototype.result.handler,
2728                                                                     result))
2729         return UDM_FALSE;
2730     }
2731   }
2732   return UDM_TRUE;
2733 }
2734 
2735 
2736 static udm_bool_t
UdmGenerateFunctionArgsSetup(UDM_PROG_COMPILER * compiler,const UDM_FUNCTION * func,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * arglist,size_t offset)2737 UdmGenerateFunctionArgsSetup(UDM_PROG_COMPILER *compiler,
2738                              const UDM_FUNCTION *func,
2739                              const UDM_PROG_FUNCTION_CALL_ARGUMENTS *arglist,
2740                              size_t offset)
2741 {
2742   size_t i;
2743   for (i= 0; i < arglist->nargs && i < UDM_MAX_FUNC_ARG; i++)
2744   {
2745     if (!UdmGenerateFunctionCallArgSetup(compiler, func,
2746                                          &arglist->args[i], i + offset))
2747       return UDM_FALSE;
2748   }
2749   return UDM_TRUE;
2750 }
2751 
2752 
2753 static udm_bool_t
UdmGenerateFunctionArgsDelete(UDM_PROG_COMPILER * compiler,const UDM_FUNCTION * func,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * arglist,size_t offset)2754 UdmGenerateFunctionArgsDelete(UDM_PROG_COMPILER *compiler,
2755                               const UDM_FUNCTION *func,
2756                               const UDM_PROG_FUNCTION_CALL_ARGUMENTS *arglist,
2757                               size_t offset)
2758 {
2759   size_t i;
2760   for (i= 0; i < arglist->nargs && i < UDM_MAX_FUNC_ARG; i++)
2761   {
2762     if (!UdmGenerateFunctionCallArgDelete(compiler,
2763                                           &arglist->args[i], i + offset))
2764       return UDM_FALSE;
2765   }
2766   return UDM_TRUE;
2767 }
2768 
2769 
2770 static udm_bool_t
UdmGenerateCallInstruction(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * classhandler,const UDM_FUNCTION * func)2771 UdmGenerateCallInstruction(UDM_PROG_COMPILER *compiler,
2772                            const UDM_VALUE_HANDLER *classhandler,
2773                            const UDM_FUNCTION *func)
2774 {
2775   UDM_PROG_ITEM item;
2776   char comment[128];
2777   UdmProgItemInit(&item);
2778   item.cmdarg.func= func;
2779   item.cmdnum= UDM_PROG_CALL;
2780   udm_snprintf(comment, sizeof(comment), "%s::%.*s()",
2781                classhandler ?
2782                classhandler->type_name : "",
2783                (int) func->name.length, func->name.str);
2784   return UDM_OK == UdmProgAdd(compiler->prg, &item);
2785 }
2786 
2787 
2788 /*
2789   @param [OUT] result - non-NULL means that we want the result on stack.
2790                         A new stack variable is created and
2791                         is returned in result[0].
2792                         NULL means that we want the result on heap in (h0,s0).
2793   @param       dstvar - non-NULL if the function call is directly assigned
2794                         to a variable:
2795                           string x= str.upper();
2796                         A new variable is not created in this case,
2797                         neither on stack, nor on heap.
2798 
2799   Function call returns resuts as follows:
2800   - INT    is returned in i0
2801   - DOUBLE is returned in d0
2802   - Other datatypes are returned in the register pair (h0,s0),
2803     where h0 stores the pointer to the data type handler,
2804     and s0 stores the pointer to the data.
2805 */
2806 static udm_bool_t
UdmGenerateNewFunctionCall(UDM_PROG_COMPILER * compiler,const UDM_FUNCTION * func,const UDM_PROG_VAR * thisptr,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * arglist,UDM_PROG_VAR * result,const UDM_PROG_VAR * dstvar)2807 UdmGenerateNewFunctionCall(UDM_PROG_COMPILER *compiler,
2808                            const UDM_FUNCTION *func,
2809                            const UDM_PROG_VAR *thisptr,
2810                            const UDM_PROG_FUNCTION_CALL_ARGUMENTS *arglist,
2811                            UDM_PROG_VAR *result,
2812                            const UDM_PROG_VAR *dstvar)
2813 {
2814   size_t offset= thisptr ? 1 : 0; /* 1 means method, 0 means function */
2815   if (!UdmGenerateFunctionReturnValue(compiler, func, result, dstvar))
2816     return UDM_FALSE;
2817 
2818   if (thisptr)
2819   {
2820     /* Pass "this" as the first arg */
2821     if (!UdmGenerateOpOffset(compiler, UDM_PROG_MOV_VREG0_STACK_OFFSET,
2822                              thisptr->value.stack_offset))
2823       return UDM_FALSE;
2824   }
2825   if (!UdmGenerateFunctionArgsSetup(compiler, func, arglist, offset))
2826     return UDM_FALSE;
2827 
2828   if (!UdmGenerateCallInstruction(compiler,
2829                                   thisptr ?
2830                                   UdmProgVarHandler(thisptr) : NULL, func))
2831     return UDM_FALSE;
2832 
2833   if (!UdmGenerateFunctionArgsDelete(compiler, func, arglist, offset))
2834     return UDM_FALSE;
2835 
2836   if (thisptr)
2837   {
2838     if (UDM_OK != UdmProgAddArg0Simple(compiler->prg, &udm_method_clear_arg0))
2839       return UDM_FALSE;
2840   }
2841   if (func->func == UdmFunction_exit)
2842   {
2843     if (!UdmProgCompilerGenerateVarListListDestructors(compiler))
2844       return UDM_FALSE;
2845     UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_EXIT);
2846   }
2847   return UDM_TRUE;
2848 }
2849 
2850 
2851 static udm_bool_t
UdmGenerateFunctionCall(UDM_PROG_COMPILER * compiler,const UDM_CONST_TOKEN * name,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)2852 UdmGenerateFunctionCall(UDM_PROG_COMPILER *compiler,
2853                         const UDM_CONST_TOKEN *name,
2854                         UDM_PROG_EXPRESSION *expr,
2855                         UDM_PROG_VAR *complex_func_result_on_stack,
2856                         const UDM_PROG_VAR *dstvar)
2857 {
2858   const UDM_FUNCTION *func2;
2859   if (!(func2= UdmFunctionListFind(udm_builtin_functions,
2860                                   name->str, name->end - name->str,
2861                                   NULL, &expr->arglist, 0)))
2862     return UdmProgCompilerErrorUnknownFunction(compiler, name, &expr->arglist);
2863   if (!UdmGenerateNewFunctionCall(compiler, func2,
2864                                     NULL, &expr->arglist,
2865                                     complex_func_result_on_stack, dstvar))
2866     return UDM_FALSE;
2867   UdmExprSetHandler(expr, func2->prototype.result.handler);
2868   expr->primary_expr.type= UDM_EXPRESSION_OBJECT;
2869   return UDM_TRUE;
2870 }
2871 
2872 
2873 static udm_bool_t
UdmGenerateMethodCall(UDM_PROG_COMPILER * compiler,const UDM_CONST_TOKEN * name,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)2874 UdmGenerateMethodCall(UDM_PROG_COMPILER *compiler,
2875                       const UDM_CONST_TOKEN *name,
2876                       UDM_PROG_EXPRESSION *expr,
2877                       UDM_PROG_VAR *complex_func_result_on_stack,
2878                       const UDM_PROG_VAR *dstvar)
2879 {
2880   const UDM_FUNCTION *method;
2881 
2882   if (!(method= UdmValueHandlerMethodFind(UdmExprHandler(expr),
2883                                           name->str, name->end - name->str,
2884                                           &expr->arglist)))
2885     return UdmProgCompilerUnknownMethodError(compiler, UdmExprHandler(expr),
2886                                              name, &expr->arglist);
2887   if (!UdmGenerateNewFunctionCall(compiler, method,
2888                                   &expr->primary_expr.Var, &expr->arglist,
2889                                   complex_func_result_on_stack, dstvar))
2890     return UDM_FALSE;
2891   UdmExprSetHandler(expr, method->prototype.result.handler);
2892   expr->primary_expr.type= UDM_EXPRESSION_OBJECT;
2893   return UDM_TRUE;
2894 }
2895 
2896 
2897 static udm_bool_t
UdmGenerateStackVarIncrement(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var)2898 UdmGenerateStackVarIncrement(UDM_PROG_COMPILER *compiler, const UDM_PROG_VAR *Var)
2899 {
2900   if (!UdmUnaryOperatorFindWithError(compiler, unary_operators,
2901                                     UDM_UNARY_OPERATOR_POSTFIX_INC,
2902                                     UdmProgVarHandler(Var), "++"))
2903     return UDM_FALSE;
2904   switch (UdmProgVarHandler(Var)->datatype)
2905   {
2906   case UDM_VALUE_DATA_TYPE_INT:
2907     return UdmGenerateVariableOp(compiler, Var, UDM_PROG_INC_INT_PTR_STACK_OFFSET);
2908   case UDM_VALUE_DATA_TYPE_DOUBLE:
2909     return UdmGenerateVariableOp(compiler, Var, UDM_PROG_INC_DBL_PTR_STACK_OFFSET);
2910   case UDM_VALUE_DATA_TYPE_CHAR:
2911     return UdmGenerateVariableOp(compiler, Var, UDM_PROG_INC_CHR_PTR_STACK_OFFSET);
2912   case UDM_VALUE_DATA_TYPE_STR:
2913   case UDM_VALUE_DATA_TYPE_ENV:
2914   case UDM_VALUE_DATA_TYPE_RESULT:
2915   case UDM_VALUE_DATA_TYPE_DOCUMENT:
2916   case UDM_VALUE_DATA_TYPE_SQLRESULT:
2917   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
2918     break;
2919   }
2920   UDM_ASSERT(0);
2921   return UDM_TRUE;
2922 }
2923 
2924 
2925 static udm_bool_t
UdmGenerateStackVarDecrement(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var)2926 UdmGenerateStackVarDecrement(UDM_PROG_COMPILER *compiler, const UDM_PROG_VAR *Var)
2927 {
2928   if (!UdmUnaryOperatorFindWithError(compiler, unary_operators,
2929                                      UDM_UNARY_OPERATOR_POSTFIX_DEC,
2930                                      UdmProgVarHandler(Var), "--"))
2931     return UDM_FALSE;
2932   switch (UdmProgVarHandler(Var)->datatype)
2933   {
2934   case UDM_VALUE_DATA_TYPE_INT:
2935     return UdmGenerateVariableOp(compiler, Var, UDM_PROG_DEC_INT_PTR_STACK_OFFSET);
2936   case UDM_VALUE_DATA_TYPE_DOUBLE:
2937     return UdmGenerateVariableOp(compiler, Var, UDM_PROG_DEC_DBL_PTR_STACK_OFFSET);
2938   case UDM_VALUE_DATA_TYPE_CHAR:
2939     return UdmGenerateVariableOp(compiler, Var, UDM_PROG_DEC_CHR_PTR_STACK_OFFSET);
2940   case UDM_VALUE_DATA_TYPE_STR:
2941   case UDM_VALUE_DATA_TYPE_ENV:
2942   case UDM_VALUE_DATA_TYPE_RESULT:
2943   case UDM_VALUE_DATA_TYPE_DOCUMENT:
2944   case UDM_VALUE_DATA_TYPE_SQLRESULT:
2945   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
2946     break;
2947   }
2948   UDM_ASSERT(0);
2949   return UDM_TRUE;
2950 }
2951 
2952 
2953 static udm_bool_t
UdmGenerateStackVarIncOrDec(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var,udm_lex_t op)2954 UdmGenerateStackVarIncOrDec(UDM_PROG_COMPILER *compiler,
2955                             const UDM_PROG_VAR *Var,
2956                             udm_lex_t op)
2957 {
2958   if (op == UDM_LEX_INC)
2959     return UdmGenerateStackVarIncrement(compiler, Var);
2960   if (op == UDM_LEX_DEC)
2961     return UdmGenerateStackVarDecrement(compiler, Var);
2962   UDM_ASSERT(0);
2963   return UDM_FALSE;
2964 }
2965 
2966 
2967 /*
2968 <postfix-expression-part2> ::= '[' <expression> ']'
2969                              | <function-call-arguments>
2970                              | '.' <identifier>
2971                              | '->' <identifier>
2972                              | '++'
2973                              | '--'
2974 */
2975 static udm_bool_t
ParsePostfixExpressionVarPart2(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr)2976 ParsePostfixExpressionVarPart2(UDM_PROG_COMPILER *compiler,
2977                                UDM_PROG_EXPRESSION *expr)
2978 {
2979   udm_lex_t cmd;
2980   if (ParseTerm(compiler, (cmd= UDM_LEX_INC)) ||
2981       ParseTerm(compiler, (cmd= UDM_LEX_DEC)))
2982   {
2983     expr->primary_expr.type= UDM_EXPRESSION_COMPUTED;
2984     return
2985       UdmGenerateVarToNativeReg0(compiler, &expr->primary_expr.Var) &&
2986       UdmGenerateStackVarIncOrDec(compiler, &expr->primary_expr.Var, cmd);
2987   }
2988   return UDM_TRUE;
2989 }
2990 
2991 
2992 static udm_bool_t
2993 UdmParseExpression(UDM_PROG_COMPILER *compiler,
2994                    UDM_PROG_EXPRESSION *expr,
2995                    UDM_PROG_VAR *complex_result_on_stack,
2996                    const UDM_PROG_VAR *dstvar);
2997 
2998 static udm_bool_t
ParseParenthesizedExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)2999 ParseParenthesizedExpression(UDM_PROG_COMPILER *compiler,
3000                              UDM_PROG_EXPRESSION *expr,
3001                              UDM_PROG_VAR *complex_func_result_on_stack,
3002                              const UDM_PROG_VAR *dstvar)
3003 {
3004   if (TestParenthesizedTypeSpecifier(compiler))
3005     return UDM_FALSE; /* This is a type cast, e.g.: y= (int) x; */
3006   if (!ParseTerm(compiler, UDM_LEX_LP))
3007     return UDM_FALSE;
3008   if (!UdmParseExpression(compiler, expr,
3009                           complex_func_result_on_stack, dstvar))
3010     return UDM_FALSE;
3011   return ParseTermOrError(compiler, UDM_LEX_RP);
3012 }
3013 
3014 
3015 static udm_bool_t
UdmParseMemberAccess(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3016 UdmParseMemberAccess(UDM_PROG_COMPILER *compiler,
3017                      UDM_PROG_EXPRESSION *expr,
3018                      UDM_PROG_VAR *complex_func_result_on_stack,
3019                      const UDM_PROG_VAR *dstvar)
3020 {
3021   UDM_CONST_TOKEN name;
3022   if (ParseTerm(compiler, UDM_LEX_OPERATOR))
3023   {
3024     if (!ParseTermOrError(compiler, UDM_LEX_EQ))
3025       return UDM_FALSE;
3026     UdmConstTokenSet(&name, UDM_CSTR_WITH_LEN("operator="));
3027   }
3028   else if (!ParseIdentifier(compiler, &name))
3029     return UdmProgCompilerExpectedRule(compiler, "<method-name> or `operator`");
3030   if (!ParseFunctionCallArguments(compiler, &expr->arglist))
3031     return UDM_FALSE;
3032   return UdmGenerateMethodCall(compiler, &name, expr,
3033                                complex_func_result_on_stack, dstvar);
3034 }
3035 
3036 
3037 static void
UdmPrepareFunctionResultForMethodCall(UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack)3038 UdmPrepareFunctionResultForMethodCall(UDM_PROG_EXPRESSION *expr,
3039                                       UDM_PROG_VAR *complex_func_result_on_stack)
3040 {
3041     /* Preserve expr->primary_expr.Var.handler */
3042     UdmConstTokenSet(&expr->primary_expr.Var.name, NULL, 0);
3043     expr->primary_expr.type= UDM_EXPRESSION_IDENT;
3044     expr->primary_expr.Var.value.stack_offset=
3045       complex_func_result_on_stack->value.stack_offset;
3046     UDM_BZERO(complex_func_result_on_stack, sizeof(*complex_func_result_on_stack));
3047 
3048 }
3049 
3050 
3051 static udm_bool_t
UdmParseRecursiveMemberAccess(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3052 UdmParseRecursiveMemberAccess(UDM_PROG_COMPILER *compiler,
3053                               UDM_PROG_EXPRESSION *expr,
3054                               UDM_PROG_VAR *complex_func_result_on_stack,
3055                               const UDM_PROG_VAR *dstvar)
3056 {
3057   if (!UdmParseMemberAccess(compiler, expr,
3058                             complex_func_result_on_stack, dstvar))
3059     return UDM_FALSE;
3060   while (ParseTerm(compiler, UDM_LEX_DOT))
3061   {
3062     if (dstvar)
3063       return UdmProgCompilerNotSupported(compiler,
3064                                          "recursive member access in this context");
3065     UdmPrepareFunctionResultForMethodCall(expr, complex_func_result_on_stack);
3066     if (!UdmParseMemberAccess(compiler, expr,
3067                               complex_func_result_on_stack, dstvar))
3068       return UDM_FALSE;
3069   }
3070   return UDM_TRUE;
3071 }
3072 
3073 /*
3074 
3075 <postfix-expression> ::= <primary-expression> {<postfix-expression-part2>}*
3076 
3077 */
3078 static udm_bool_t
ParsePostfixExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3079 ParsePostfixExpression(UDM_PROG_COMPILER *compiler,
3080                        UDM_PROG_EXPRESSION *expr,
3081                        UDM_PROG_VAR *complex_func_result_on_stack,
3082                        const UDM_PROG_VAR *dstvar)
3083 {
3084   if (ParseParenthesizedExpression(compiler, expr,
3085                                    complex_func_result_on_stack, dstvar))
3086   {
3087     if (ParseTerm(compiler, UDM_LEX_DOT))
3088     {
3089       UdmPrepareFunctionResultForMethodCall(expr, complex_func_result_on_stack);
3090       return UdmParseRecursiveMemberAccess(compiler, expr,
3091                                            complex_func_result_on_stack, dstvar);
3092     }
3093     return UDM_TRUE;
3094   }
3095   if (!ParsePrimaryExpression(compiler, &expr->primary_expr))
3096     return UDM_FALSE;
3097 
3098   if (expr->primary_expr.type == UDM_EXPRESSION_IDENT)
3099   {
3100     if (!UdmExprHandler(expr))
3101     {
3102       if (!ParseFunctionCallArguments(compiler, &expr->arglist))
3103       {
3104         if (UdmProgCompilerError(compiler))
3105           return UDM_FALSE;
3106         return UdmProgCompilerUnknownIdentifierError(compiler, &expr->primary_expr.Var.name);
3107       }
3108       else
3109       {
3110         return UdmGenerateFunctionCall(compiler, &expr->primary_expr.Var.name, expr,
3111                                        complex_func_result_on_stack,
3112                                        dstvar);
3113       }
3114     }
3115 
3116     if (ParseTerm(compiler, UDM_LEX_DOT))
3117       return UdmParseRecursiveMemberAccess(compiler, expr,
3118                                            complex_func_result_on_stack, dstvar);
3119     return ParsePostfixExpressionVarPart2(compiler, expr);
3120   }
3121   return UDM_TRUE;
3122 }
3123 
3124 
3125 static udm_bool_t
ExpressionHasEffect(const UDM_PROG_EXPRESSION * expr)3126 ExpressionHasEffect(const UDM_PROG_EXPRESSION *expr)
3127 {
3128   switch (expr->primary_expr.type)
3129   {
3130   case UDM_EXPRESSION_IDENT:
3131   case UDM_EXPRESSION_CONST:
3132     return UDM_FALSE;
3133   case UDM_EXPRESSION_OBJECT:
3134   case UDM_EXPRESSION_COMPUTED:
3135     return UDM_TRUE;
3136   }
3137   return UDM_FALSE;
3138 }
3139 
3140 
3141 static udm_bool_t ParseUnaryExpression(UDM_PROG_COMPILER *compiler,
3142                                        UDM_PROG_EXPRESSION *expr,
3143                                        UDM_PROG_VAR *complex_func_result_on_stack,
3144                                        const UDM_PROG_VAR *dstvar);
3145 
3146 static udm_bool_t
3147 UdmParseCastExpression(UDM_PROG_COMPILER *compiler,
3148                        UDM_PROG_EXPRESSION *expr,
3149                        UDM_PROG_VAR *complex_func_result_on_stack,
3150                        const UDM_PROG_VAR *dstvar);
3151 
3152 /*
3153 <unary-operator> ::= &
3154                    | *
3155                    | +
3156                    | -
3157                    | ~
3158                    | !
3159 
3160 <prefix-expression> ::= <unary-operator> [<cast>] <cast-expression>
3161                       | '++' <unary-expression>
3162                       | '--' <unary-expression>
3163                       | 'sizeof' <unary-expression>
3164                       | 'sizeof' <type-name>
3165 
3166 <unary-expression> ::= <postfix-expression>
3167                      | <prefix-expression>
3168 */
3169 static udm_bool_t
ParseUnaryExpressionInternal(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3170 ParseUnaryExpressionInternal(UDM_PROG_COMPILER *compiler,
3171                              UDM_PROG_EXPRESSION *expr,
3172                              UDM_PROG_VAR *complex_func_result_on_stack,
3173                              const UDM_PROG_VAR *dstvar)
3174 {
3175   if (ParseTerm(compiler, UDM_LEX_DEC))
3176   {
3177     if (!ParseUnaryExpression(compiler, expr,
3178                               complex_func_result_on_stack, dstvar))
3179       return UdmProgCompilerExpectedRule(compiler, "<unary-expression>");
3180     expr->primary_expr.type= UDM_EXPRESSION_COMPUTED;
3181     return UdmGenerateStackVarDecrement(compiler, &expr->primary_expr.Var) &&
3182            UdmGenerateVarToNativeReg0(compiler, &expr->primary_expr.Var);
3183   }
3184   if (ParseTerm(compiler, UDM_LEX_INC))
3185   {
3186     if (!ParseUnaryExpression(compiler, expr,
3187                               complex_func_result_on_stack, dstvar))
3188       return UdmProgCompilerExpectedRule(compiler, "<unary-expression>");
3189     expr->primary_expr.type=  UDM_EXPRESSION_COMPUTED;
3190     return UdmGenerateStackVarIncrement(compiler, &expr->primary_expr.Var) &&
3191            UdmGenerateVarToNativeReg0(compiler, &expr->primary_expr.Var);
3192   }
3193   if (!ParsePostfixExpression(compiler, expr,
3194                               complex_func_result_on_stack, dstvar))
3195     return UDM_FALSE;
3196 
3197   return UDM_TRUE;
3198 }
3199 
3200 
3201 static udm_bool_t
ParseUnaryExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3202 ParseUnaryExpression(UDM_PROG_COMPILER *compiler,
3203                      UDM_PROG_EXPRESSION *expr,
3204                      UDM_PROG_VAR *complex_func_result_on_stack,
3205                      const UDM_PROG_VAR *dstvar)
3206 {
3207   if (ParseTerm(compiler, UDM_LEX_EXCLAM))
3208   {
3209     if (!UdmParseCastExpression(compiler, expr,
3210                                 complex_func_result_on_stack, dstvar))
3211       return UDM_FALSE;
3212     if (!UdmGenerateExpressionToNativeReg0(compiler, expr, NULL) ||
3213         !UdmGenerateIsNotTrueTest(compiler, UdmExprHandler(expr)))
3214       return UDM_FALSE;
3215     UdmExprSetHandler(expr, &UdmValueHandlerInt);
3216     return UDM_TRUE;
3217   }
3218   if (ParseTerm(compiler, UDM_LEX_TILDE))
3219   {
3220     if (!UdmParseCastExpression(compiler, expr,
3221                                 complex_func_result_on_stack, dstvar))
3222       return UDM_FALSE;
3223     if (UdmExprHandler(expr)->native_reg_type != UDM_VALUE_DATA_TYPE_INT)
3224       return UdmProgCompilerNotSupported(compiler, "unary ~ for this data type");
3225     if (!UdmGenerateExpressionToNativeReg0(compiler, expr, NULL) ||
3226         !UdmGenerateOp(compiler, UDM_PROG_NOT_IREG0))
3227       return UDM_FALSE;
3228     UdmExprSetHandler(expr, &UdmValueHandlerInt);
3229     return UDM_TRUE;
3230   }
3231   if (ParseTerm(compiler, UDM_LEX_MINUS))
3232   {
3233     if (!UdmParseCastExpression(compiler, expr,
3234                                 complex_func_result_on_stack, dstvar))
3235       return UDM_FALSE;
3236     if (UdmValueHandlerIsComplex(UdmExprHandler(expr)))
3237       return UdmProgCompilerNotSupported(compiler, "unary '-' for this data type");
3238     if (!UdmGenerateExpressionToNativeReg0(compiler, expr, NULL))
3239       return UDM_FALSE;
3240     if (!UdmGenerateMovNativeReg0ToReg1(compiler, UdmExprHandler(expr)))
3241       return UDM_FALSE;
3242     if (!UdmGenerateClearNativeReg0(compiler, UdmExprHandler(expr)))
3243       return UDM_FALSE;
3244 
3245     if (!UdmGenerateAddNativeReg0Reg1(compiler,
3246                                       &expr->primary_expr.Var.value.handler,
3247                                       UDM_LEX_MINUS))
3248       return UDM_FALSE;
3249     return UDM_TRUE;
3250   }
3251   if (ParseTerm(compiler, UDM_LEX_PLUS))
3252   {
3253     if (!UdmParseCastExpression(compiler, expr,
3254                                 complex_func_result_on_stack, dstvar))
3255       return UDM_FALSE;
3256     if (UdmValueHandlerIsComplex(UdmExprHandler(expr)))
3257       return UdmProgCompilerNotSupported(compiler, "unary '+' for this data type");
3258     return UDM_TRUE;
3259   }
3260   return ParseUnaryExpressionInternal(compiler, expr,
3261                                       complex_func_result_on_stack, dstvar);
3262 }
3263 
3264 
3265 /**
3266   <cast-expression> ::=   <unary-expression>
3267                         | ( <type-name> ) <cast-expression>
3268 */
3269 static udm_bool_t
UdmParseCastExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3270 UdmParseCastExpression(UDM_PROG_COMPILER *compiler,
3271                        UDM_PROG_EXPRESSION *expr,
3272                        UDM_PROG_VAR *complex_func_result_on_stack,
3273                        const UDM_PROG_VAR *dstvar)
3274 {
3275   const UDM_VALUE_HANDLER *ha;
3276   /*
3277     The cast operator starts from parenthesis, so does the
3278     parenthesized expression. This rule needs one more look-ahead.
3279     TestParenthesizedTypeSpecifier() makes one more look-ahead with rollback.
3280   */
3281   if (!TestParenthesizedTypeSpecifier(compiler))
3282     return ParseUnaryExpression(compiler, expr,
3283                                 complex_func_result_on_stack, dstvar);
3284 
3285   if (!ParseTerm(compiler, UDM_LEX_LP) ||
3286       !ParseTypeSpecifier(compiler, &ha) ||
3287       !ParseTermOrError(compiler, UDM_LEX_RP))
3288     return UDM_FALSE;
3289 
3290   if (!UdmParseCastExpression(compiler, expr,
3291                               complex_func_result_on_stack, dstvar))
3292     return UDM_FALSE;
3293   if (UdmExprHandler(expr) == ha)
3294     return UDM_TRUE;
3295 
3296   if (UdmValueHandlerIsComplex(ha))
3297     return UdmProgCompilerNotSupported(compiler, "cast to this data type");
3298   if (UdmValueHandlerIsComplex(UdmExprHandler(expr)))
3299     return UdmProgCompilerNotSupported(compiler, "cast from this data type");
3300   if (!UdmGenerateExpressionToNativeReg0(compiler, expr, NULL) ||
3301       !UdmGenerateNativeReg0TypeConversion(compiler, ha, UdmExprHandler(expr)))
3302     return UDM_FALSE;
3303   UdmExprSetHandler(expr, ha);
3304   return UDM_TRUE;
3305 }
3306 
3307 
3308 static udm_bool_t
UdmGenerateSaveNativeReg0ToTempVariableOnStack(UDM_PROG_COMPILER * c,const UDM_VALUE_HANDLER * h,UDM_PROG_VAR * dst)3309 UdmGenerateSaveNativeReg0ToTempVariableOnStack(UDM_PROG_COMPILER *c,
3310                                                const UDM_VALUE_HANDLER *h,
3311                                                UDM_PROG_VAR *dst)
3312 {
3313   return UdmGenerateReserveNonInitializedTemporaryVariableOnStack(c, h, dst) &&
3314          UdmGenerateConstructor(c, dst) &&
3315          UdmGenerateNativeReg0ToVar(c, dst);
3316 }
3317 
3318 
3319 static udm_bool_t
UdmGenerateAggregateAndConvertReg0Reg1(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * b,const UDM_VALUE_HANDLER * a,const UDM_VALUE_HANDLER ** agg)3320 UdmGenerateAggregateAndConvertReg0Reg1(UDM_PROG_COMPILER *compiler,
3321                                        const UDM_VALUE_HANDLER *b,
3322                                        const UDM_VALUE_HANDLER *a,
3323                                        const UDM_VALUE_HANDLER **agg)
3324 {
3325   *agg= a->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE ||
3326         b->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE ?
3327        &UdmValueHandlerDouble : &UdmValueHandlerInt;
3328   return UdmGenerateNativeReg1TypeConversion(compiler, *agg, a) &&
3329          UdmGenerateNativeReg0TypeConversion(compiler, *agg, b);
3330 }
3331 
3332 
3333 static udm_bool_t
3334 ParseMultiplicativeExpression(UDM_PROG_COMPILER *compiler,
3335                               UDM_PROG_EXPRESSION *expr,
3336                               UDM_PROG_VAR *complex_func_result_on_stack,
3337                               const UDM_PROG_VAR *dstvar);
3338 static udm_bool_t
3339 ParseAdditiveExpression(UDM_PROG_COMPILER *compiler,
3340                         UDM_PROG_EXPRESSION *expr,
3341                         UDM_PROG_VAR *complex_func_result_on_stack,
3342                         const UDM_PROG_VAR *dstvar);
3343 
3344 static udm_bool_t
3345 UdmParseShiftExpression(UDM_PROG_COMPILER *compiler,
3346                         UDM_PROG_EXPRESSION *expr,
3347                         UDM_PROG_VAR *complex_func_result_on_stack,
3348                         const UDM_PROG_VAR *dstvar);
3349 
3350 
3351 static udm_bool_t
3352 UdmParseRelationalExpression(UDM_PROG_COMPILER *compiler,
3353                              UDM_PROG_EXPRESSION *expr,
3354                              UDM_PROG_VAR *complex_func_result_on_stack,
3355                              const UDM_PROG_VAR *dstvar);
3356 
3357 static udm_bool_t
3358 UdmParseEqualityExpression(UDM_PROG_COMPILER *compiler,
3359                            UDM_PROG_EXPRESSION *expr,
3360                            UDM_PROG_VAR *complex_func_result_on_stack,
3361                            const UDM_PROG_VAR *dstvar);
3362 
3363 
3364 static udm_bool_t
3365 UdmParseAndExpression(UDM_PROG_COMPILER *compiler,
3366                       UDM_PROG_EXPRESSION *expr,
3367                       UDM_PROG_VAR *complex_func_result_on_stack,
3368                       const UDM_PROG_VAR *dstvar);
3369 
3370 
3371 static udm_bool_t
3372 UdmParseOrExpression(UDM_PROG_COMPILER *compiler,
3373                      UDM_PROG_EXPRESSION *expr,
3374                      UDM_PROG_VAR *complex_func_result_on_stack,
3375                      const UDM_PROG_VAR *dstvar);
3376 
3377 
3378 static udm_bool_t
UdmGenerateDiadicOperationPart2(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,udm_lex_t op)3379 UdmGenerateDiadicOperationPart2(UDM_PROG_COMPILER *compiler,
3380                                 UDM_PROG_EXPRESSION *expr,
3381                                 udm_lex_t op)
3382 {
3383   UDM_PROG_EXPRESSION expr2;
3384   UDM_PROG_VAR tmp;
3385   const UDM_VALUE_HANDLER *agg;
3386 
3387   if (!UdmExprHandler(expr))
3388     return UdmProgCompilerVoidValueIsNotIgnored(compiler);
3389 
3390   switch (UdmExprHandler(expr)->datatype)
3391   {
3392   case UDM_VALUE_DATA_TYPE_CHAR:
3393   case UDM_VALUE_DATA_TYPE_INT:
3394   case UDM_VALUE_DATA_TYPE_DOUBLE:
3395     break;
3396   case UDM_VALUE_DATA_TYPE_STR:
3397   case UDM_VALUE_DATA_TYPE_ENV:
3398   case UDM_VALUE_DATA_TYPE_RESULT:
3399   case UDM_VALUE_DATA_TYPE_DOCUMENT:
3400   case UDM_VALUE_DATA_TYPE_SQLRESULT:
3401   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
3402     return UdmProgCompilerNotSupported(compiler, "Dyadic operation for this data type");
3403   }
3404 
3405   if (!UdmGenerateExpressionToNativeReg0(compiler, expr, NULL))
3406     return UDM_FALSE;
3407 
3408   /* Save the current value in reg0 to a temporary variable */
3409   if (!UdmProgCompilerEnterBlock(compiler) ||
3410       !UdmGenerateSaveNativeReg0ToTempVariableOnStack(compiler,
3411                                                       UdmExprHandler(expr),
3412                                                       &tmp))
3413     return UDM_FALSE;
3414   /* Parse the second operand and bring its value to reg0  */
3415   switch (op)
3416   {
3417   case UDM_LEX_VBAR:
3418     if (!UdmParseOrExpression(compiler, &expr2, NULL, NULL))
3419       return UDM_FALSE;
3420     break;
3421   case UDM_LEX_CARET:
3422     if (!UdmParseAndExpression(compiler, &expr2, NULL, NULL))
3423       return UDM_FALSE;
3424     break;
3425   case UDM_LEX_AMPERSAND:
3426     if (!UdmParseEqualityExpression(compiler, &expr2, NULL, NULL))
3427       return UDM_FALSE;
3428     break;
3429   case UDM_LEX_EQ_EQ:
3430   case UDM_LEX_NOT_EQ:
3431     if (!UdmParseRelationalExpression(compiler, &expr2, NULL, NULL))
3432       return UDM_FALSE;
3433     break;
3434   case UDM_LEX_LE:
3435   case UDM_LEX_GE:
3436   case UDM_LEX_LT:
3437   case UDM_LEX_GT:
3438     if (!UdmParseShiftExpression(compiler, &expr2, NULL, NULL))
3439       return UDM_FALSE;
3440     break;
3441   case UDM_LEX_LSHIFT:
3442   case UDM_LEX_RSHIFT:
3443     if (!ParseAdditiveExpression(compiler, &expr2, NULL, NULL))
3444       return UDM_FALSE;
3445     break;
3446   case UDM_LEX_PLUS:
3447   case UDM_LEX_MINUS:
3448   case UDM_LEX_PERCENT:
3449     if (!ParseMultiplicativeExpression(compiler, &expr2, NULL, NULL))
3450       return UDM_FALSE;
3451     break;
3452   case UDM_LEX_ASTERISK:
3453   case UDM_LEX_SLASH:
3454     if (!UdmParseCastExpression(compiler, &expr2, NULL, NULL))
3455       return UDM_FALSE;
3456     break;
3457   default:
3458     UDM_ASSERT(0);
3459     return 0;
3460   }
3461 
3462   if (!UdmExprHandler(&expr2))
3463     return UdmProgCompilerVoidValueIsNotIgnored(compiler);
3464 
3465   if (!UdmGenerateExpressionToNativeReg0(compiler, &expr2, NULL))
3466     return UDM_FALSE;
3467   /* Restore the first operant to reg1 */
3468   if (!UdmGenerateVarToNativeReg1(compiler, &tmp))
3469     return UDM_FALSE;
3470   if (!UdmProgCompilerLeaveBlock(compiler))
3471     return UDM_FALSE;
3472 
3473   /* Now we have the left operant in reg1 and the right operand in reg0 */
3474   if (!UdmGenerateAggregateAndConvertReg0Reg1(compiler,
3475                                               UdmExprHandler(&expr2),
3476                                               UdmExprHandler(expr),
3477                                               &agg))
3478     return UDM_FALSE;
3479 
3480   switch (op)
3481   {
3482   case UDM_LEX_VBAR:
3483   case UDM_LEX_CARET:
3484   case UDM_LEX_AMPERSAND:
3485   case UDM_LEX_ASTERISK:
3486   case UDM_LEX_PLUS:
3487   case UDM_LEX_EQ_EQ:
3488   case UDM_LEX_NOT_EQ:
3489     break; /* Reverse operation, the order of arguments does not matter. */
3490   case UDM_LEX_SLASH:
3491   case UDM_LEX_PERCENT:
3492   case UDM_LEX_MINUS:
3493   case UDM_LEX_LSHIFT:
3494   case UDM_LEX_RSHIFT:
3495   case UDM_LEX_LE:
3496   case UDM_LEX_GE:
3497   case UDM_LEX_LT:
3498   case UDM_LEX_GT:
3499     if (!UdmGenerateSwapNativeReg0Reg1(compiler, agg))
3500       return UDM_FALSE;
3501     break;
3502   default:
3503     UDM_ASSERT(0);
3504     return UDM_FALSE;
3505   }
3506   if (!UdmGenerateDiadicOperationNativeReg0Reg1(compiler, &agg, op))
3507     return UDM_FALSE;
3508   UdmExprSetHandler(expr, agg);
3509   return UDM_TRUE;
3510 }
3511 
3512 
3513 /*
3514   <multiplicative-expression> ::= <cast-expression>
3515                                   { <mul-op>   <cast-expression>  }*
3516   <cast-expression> ::= [ ( <type-name> )] <unary-expression>
3517 */
3518 static udm_bool_t
ParseMultiplicativeExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3519 ParseMultiplicativeExpression(UDM_PROG_COMPILER *compiler,
3520                               UDM_PROG_EXPRESSION *expr,
3521                               UDM_PROG_VAR *complex_func_result_on_stack,
3522                               const UDM_PROG_VAR *dstvar)
3523 {
3524   udm_lex_t cmd;
3525   if (!UdmParseCastExpression(compiler, expr,
3526                               complex_func_result_on_stack, dstvar))
3527     return UDM_FALSE;
3528   for (; ParseTerm(compiler, (cmd= UDM_LEX_ASTERISK)) ||
3529          ParseTerm(compiler, (cmd= UDM_LEX_SLASH)) ||
3530          ParseTerm(compiler, (cmd= UDM_LEX_PERCENT)) ; )
3531   {
3532     if (!UdmGenerateDiadicOperationPart2(compiler, expr, cmd))
3533       return UDM_FALSE;
3534   }
3535   return UDM_TRUE;
3536 }
3537 
3538 
3539 
3540 /*
3541   <additive-expression> ::= <multiplicative-expression>
3542                             { <add-op>   <multiplicative-expression> }*
3543 */
3544 static udm_bool_t
ParseAdditiveExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3545 ParseAdditiveExpression(UDM_PROG_COMPILER *compiler,
3546                         UDM_PROG_EXPRESSION *expr,
3547                         UDM_PROG_VAR *complex_func_result_on_stack,
3548                         const UDM_PROG_VAR *dstvar)
3549 {
3550   udm_lex_t cmd;
3551   if (!ParseMultiplicativeExpression(compiler, expr,
3552                                      complex_func_result_on_stack, dstvar))
3553     return UDM_FALSE;
3554   for (; (ParseTerm(compiler, (cmd= UDM_LEX_PLUS)) ||
3555           ParseTerm(compiler, (cmd= UDM_LEX_MINUS))) ; )
3556   {
3557     if (!UdmGenerateDiadicOperationPart2(compiler, expr, cmd))
3558       return UDM_FALSE;
3559   }
3560   return UDM_TRUE;
3561 }
3562 
3563 
3564 /*
3565   <shift-expression> ::= <additive-expression>
3566                          { <shift-op> <additive-expression>  }*
3567 */
3568 static udm_bool_t
UdmParseShiftExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3569 UdmParseShiftExpression(UDM_PROG_COMPILER *compiler,
3570                         UDM_PROG_EXPRESSION *expr,
3571                         UDM_PROG_VAR *complex_func_result_on_stack,
3572                         const UDM_PROG_VAR *dstvar)
3573 {
3574   udm_lex_t cmd;
3575   if (!ParseAdditiveExpression(compiler, expr,
3576                                complex_func_result_on_stack, dstvar))
3577     return UDM_FALSE;
3578   for (; ParseTerm(compiler, (cmd= UDM_LEX_LSHIFT)) ||
3579          ParseTerm(compiler, (cmd= UDM_LEX_RSHIFT)); )
3580   {
3581     if (!UdmGenerateDiadicOperationPart2(compiler, expr, cmd))
3582       return UDM_FALSE;
3583   }
3584   return UDM_TRUE;
3585 }
3586 
3587 
3588 /*
3589   <relational-expression>     ::= <shift-expression>
3590                                   { <rel-op>   <shift-expression>
3591 */
3592 static udm_bool_t
UdmParseRelationalExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3593 UdmParseRelationalExpression(UDM_PROG_COMPILER *compiler,
3594                              UDM_PROG_EXPRESSION *expr,
3595                              UDM_PROG_VAR *complex_func_result_on_stack,
3596                              const UDM_PROG_VAR *dstvar)
3597 {
3598   udm_lex_t cmd;
3599   if (!UdmParseShiftExpression(compiler, expr,
3600                                complex_func_result_on_stack, dstvar))
3601     return UDM_FALSE;
3602   for (; ParseTerm(compiler, (cmd= UDM_LEX_LT)) ||
3603          ParseTerm(compiler, (cmd= UDM_LEX_LE)) ||
3604          ParseTerm(compiler, (cmd= UDM_LEX_GT)) ||
3605          ParseTerm(compiler, (cmd= UDM_LEX_GE)); )
3606   {
3607     if (!UdmGenerateDiadicOperationPart2(compiler, expr, cmd))
3608       return UDM_FALSE;
3609   }
3610   return UDM_TRUE;
3611 }
3612 
3613 
3614 /*
3615   <equality-expression> ::= <relational-expression>
3616                             { <eq-op>    <relational-expression> }*
3617 */
3618 static udm_bool_t
UdmParseEqualityExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3619 UdmParseEqualityExpression(UDM_PROG_COMPILER *compiler,
3620                            UDM_PROG_EXPRESSION *expr,
3621                            UDM_PROG_VAR *complex_func_result_on_stack,
3622                            const UDM_PROG_VAR *dstvar)
3623 {
3624   udm_lex_t cmd;
3625   if (!UdmParseRelationalExpression(compiler, expr,
3626                                     complex_func_result_on_stack, dstvar))
3627     return UDM_FALSE;
3628   for (; ParseTerm(compiler, (cmd= UDM_LEX_EQ_EQ)) ||
3629          ParseTerm(compiler, (cmd= UDM_LEX_NOT_EQ)); )
3630   {
3631     if (!UdmGenerateDiadicOperationPart2(compiler, expr, cmd))
3632       return UDM_FALSE;
3633   }
3634   return UDM_TRUE;
3635 }
3636 
3637 
3638 /*
3639   <and-expression> ::= <equality-expression>
3640                        { &  <equality-expression> }*
3641 */
3642 static udm_bool_t
UdmParseAndExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3643 UdmParseAndExpression(UDM_PROG_COMPILER *compiler,
3644                       UDM_PROG_EXPRESSION *expr,
3645                       UDM_PROG_VAR *complex_func_result_on_stack,
3646                       const UDM_PROG_VAR *dstvar)
3647 {
3648   udm_lex_t cmd;
3649   if (!UdmParseEqualityExpression(compiler, expr,
3650                                   complex_func_result_on_stack, dstvar))
3651     return UDM_FALSE;
3652   for (; ParseTerm(compiler, (cmd= UDM_LEX_AMPERSAND)); )
3653   {
3654     if (!UdmGenerateDiadicOperationPart2(compiler, expr, cmd))
3655       return UDM_FALSE;
3656   }
3657   return UDM_TRUE;
3658 }
3659 
3660 
3661 /*
3662   <exclusive-or-expression> ::= <and-expression>  { ^  <and-expression> }*
3663 */
3664 static udm_bool_t
UdmParseXorExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3665 UdmParseXorExpression(UDM_PROG_COMPILER *compiler,
3666                       UDM_PROG_EXPRESSION *expr,
3667                       UDM_PROG_VAR *complex_func_result_on_stack,
3668                       const UDM_PROG_VAR *dstvar)
3669 {
3670   udm_lex_t cmd;
3671   if (!UdmParseAndExpression(compiler, expr,
3672                              complex_func_result_on_stack, dstvar))
3673     return UDM_FALSE;
3674   for (; ParseTerm(compiler, (cmd= UDM_LEX_CARET)); )
3675   {
3676     if (!UdmGenerateDiadicOperationPart2(compiler, expr, cmd))
3677       return UDM_FALSE;
3678   }
3679   return UDM_TRUE;
3680 }
3681 
3682 
3683 /*
3684   <inclusive-or-expression>   ::= <exclusive-or-expression>
3685                                  { |  <exclusive-or-expression>  }*
3686 */
3687 static udm_bool_t
UdmParseOrExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)3688 UdmParseOrExpression(UDM_PROG_COMPILER *compiler,
3689                       UDM_PROG_EXPRESSION *expr,
3690                       UDM_PROG_VAR *complex_func_result_on_stack,
3691                       const UDM_PROG_VAR *dstvar)
3692 {
3693   udm_lex_t cmd;
3694   if (!UdmParseXorExpression(compiler, expr,
3695                              complex_func_result_on_stack, dstvar))
3696     return UDM_FALSE;
3697   for (; ParseTerm(compiler, (cmd= UDM_LEX_VBAR)); )
3698   {
3699     if (!UdmGenerateDiadicOperationPart2(compiler, expr, cmd))
3700       return UDM_FALSE;
3701   }
3702   return UDM_TRUE;
3703 }
3704 
3705 
3706 static udm_bool_t
UdmGenerateExpressionToBool(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr)3707 UdmGenerateExpressionToBool(UDM_PROG_COMPILER *compiler,
3708                             UDM_PROG_EXPRESSION *expr)
3709 {
3710   if (!UdmGenerateExpressionToNativeReg0(compiler, expr, NULL) ||
3711       !UdmGenerateIsTrueTest(compiler, UdmExprHandler(expr)))
3712     return UDM_FALSE;
3713   UdmExprSetHandler(expr, &UdmValueHandlerInt);
3714   return UDM_TRUE;
3715 }
3716 
3717 
3718 static udm_bool_t
UdmParseBoolAndExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dst)3719 UdmParseBoolAndExpression(UDM_PROG_COMPILER *compiler,
3720                           UDM_PROG_EXPRESSION *expr,
3721                           UDM_PROG_VAR *complex_func_result_on_stack,
3722                           const UDM_PROG_VAR *dst)
3723 {
3724   size_t start= UdmProgCompilerGetProg(compiler)->nitems;
3725   if (!UdmParseOrExpression(compiler, expr, complex_func_result_on_stack, dst))
3726     return UDM_FALSE;
3727   if (!ParseTerm(compiler, UDM_LEX_BOOL_AND))
3728     return UDM_TRUE;
3729   if (!UdmGenerateExpressionToBool(compiler, expr))
3730     return UDM_FALSE;
3731   if (!UdmGenerateOp(compiler, UDM_PROG_JE))
3732     return UDM_FALSE;
3733 
3734   for ( ; ; )
3735   {
3736     UDM_PROG_EXPRESSION expr2;
3737     if (!UdmParseOrExpression(compiler, &expr2, NULL, dst))
3738       return UDM_FALSE;
3739     if (!UdmGenerateExpressionToBool(compiler, &expr2))
3740       return UDM_FALSE;
3741     if (!UdmGenerateOp(compiler, UDM_PROG_JE))
3742       return UDM_FALSE;
3743     if (!ParseTerm(compiler, UDM_LEX_BOOL_AND))
3744       break;
3745   }
3746   UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler),
3747                         start,
3748                         UdmProgCompilerGetProg(compiler)->nitems);
3749   return UDM_TRUE;
3750 }
3751 
3752 
3753 static udm_bool_t
UdmParseBoolOrExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dst)3754 UdmParseBoolOrExpression(UDM_PROG_COMPILER *compiler,
3755                          UDM_PROG_EXPRESSION *expr,
3756                          UDM_PROG_VAR *complex_func_result_on_stack,
3757                          const UDM_PROG_VAR *dst)
3758 {
3759   size_t start= UdmProgCompilerGetProg(compiler)->nitems;
3760   if (!UdmParseBoolAndExpression(compiler, expr, complex_func_result_on_stack, dst))
3761     return UDM_FALSE;
3762   if (!ParseTerm(compiler, UDM_LEX_BOOL_OR))
3763     return UDM_TRUE;
3764   if (!UdmGenerateExpressionToBool(compiler, expr))
3765     return UDM_FALSE;
3766   if (!UdmGenerateOp(compiler, UDM_PROG_JNE))
3767     return UDM_FALSE;
3768 
3769   for ( ; ; )
3770   {
3771     UDM_PROG_EXPRESSION expr2;
3772     if (!UdmParseBoolAndExpression(compiler, &expr2, NULL, dst))
3773       return UDM_FALSE;
3774     if (!UdmGenerateExpressionToBool(compiler, &expr2))
3775       return UDM_FALSE;
3776     if (!UdmGenerateOp(compiler, UDM_PROG_JNE))
3777       return UDM_FALSE;
3778     if (!ParseTerm(compiler, UDM_LEX_BOOL_OR))
3779       break;
3780   }
3781   UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler),
3782                         start,
3783                         UdmProgCompilerGetProg(compiler)->nitems);
3784   return UDM_TRUE;
3785 }
3786 
3787 
3788 static udm_bool_t
3789 UdmGenerateVarAssignmentFromExpression(UDM_PROG_COMPILER *compiler,
3790                                        const UDM_PROG_VAR *dst,
3791                                        const UDM_PROG_EXPRESSION *expr);
3792 static udm_bool_t
3793 UdmGenerateAssignmentOperator(UDM_PROG_COMPILER *compiler,
3794                               const UDM_PROG_VAR *Var,
3795                               const UDM_PROG_PRIMARY_EXPRESSION *Src,
3796                               udm_expression_t type);
3797 
3798 static udm_bool_t
3799 UdmParseAssignmentExpression(UDM_PROG_COMPILER *compiler,
3800                              UDM_PROG_EXPRESSION *expr,
3801                              UDM_PROG_VAR *complex_func_result_on_stack,
3802                              const UDM_PROG_VAR *dstvar);
3803 
3804 
3805 /**
3806   <conditional-expression> ::= <logical-or-expression>
3807                                { ? <expression> : <conditional-expression> }*
3808 
3809   The conditional expression works like functions.
3810   - In case of a complex result type, it creates a temporary stack variable.
3811   - In case of a simple result type, the result is returned in registers.
3812 
3813   For example:
3814     string0= cond ? string1 : string2;
3815 
3816   The temporal stack variable is assigned to either string1 or string2,
3817   then copied to string 0.
3818 
3819   NOTE: Interesting: The right choice expression cannot be an assignment.
3820   Only the left can be:
3821      cond ? x= 10 : y;      // This is correct
3822      cond ? x     : y= 10;  // This is wrong
3823 */
3824 static udm_bool_t
UdmParseConditionalExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dst)3825 UdmParseConditionalExpression(UDM_PROG_COMPILER *compiler,
3826                               UDM_PROG_EXPRESSION *expr,
3827                               UDM_PROG_VAR *complex_func_result_on_stack,
3828                               const UDM_PROG_VAR *dst)
3829 {
3830   size_t jmp0, jmp1;
3831   UDM_PROG_EXPRESSION expr2;
3832   if (!UdmParseBoolOrExpression(compiler, expr,
3833                                 complex_func_result_on_stack, dst))
3834     return UDM_FALSE;
3835   if (!ParseTerm(compiler, UDM_LEX_QUESTION))
3836     return UDM_TRUE;
3837 
3838   if (!UdmGenerateExpressionToBool(compiler, expr))
3839     return UDM_FALSE;
3840   jmp0= UdmProgCompilerGetProg(compiler)->nitems;
3841   if (!UdmGenerateOp(compiler, UDM_PROG_JE)) /* To the second part */
3842     return UDM_FALSE;
3843 
3844   UDM_BZERO(expr, sizeof(*expr));
3845   if (!UdmParseExpression(compiler, expr,
3846                           complex_func_result_on_stack, dst))
3847     return UdmProgCompilerExpectedRule(compiler, "<expression>");
3848 
3849   if (UdmExprHandler(expr))
3850   {
3851     if (UdmValueHandlerIsComplex(UdmExprHandler(expr)))
3852     {
3853       if (expr->primary_expr.type == UDM_EXPRESSION_OBJECT)
3854       {
3855         /* The result variable was created on stack */
3856         UDM_ASSERT(UdmProgVarHandler(complex_func_result_on_stack) ==
3857                    UdmExprHandler(expr));
3858       }
3859       else
3860       {
3861         UDM_ASSERT(expr->primary_expr.type == UDM_EXPRESSION_IDENT ||
3862                    expr->primary_expr.type == UDM_EXPRESSION_CONST);
3863         /* Create the result variable on stack */
3864         if (!UdmGenerateReserveNonInitializedTemporaryVariableOnStack(compiler,
3865                                                           UdmExprHandler(expr),
3866                                                  complex_func_result_on_stack))
3867           return UDM_FALSE;
3868 
3869         if (!UdmGenerateConstructor(compiler, complex_func_result_on_stack))
3870           return UDM_FALSE;
3871         if (!UdmGenerateAssignmentOperator(compiler,
3872                                            complex_func_result_on_stack,
3873                                            &expr->primary_expr,
3874                                            expr->primary_expr.type))
3875           return UDM_FALSE;
3876       }
3877     }
3878     else
3879     {
3880       if (!UdmGenerateExpressionToNativeReg0(compiler, expr,
3881                                              complex_func_result_on_stack))
3882         return UDM_FALSE;
3883     }
3884   }
3885 
3886   jmp1= UdmProgCompilerGetProg(compiler)->nitems;
3887   if (!UdmGenerateOp(compiler, UDM_PROG_JMP)) /* To the end */
3888     return UDM_FALSE;
3889 
3890   if (!ParseTermOrError(compiler, UDM_LEX_COLON))
3891     return UDM_TRUE;
3892 
3893   UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler), jmp0, jmp0 + 1);
3894 
3895   UDM_BZERO(&expr2, sizeof(expr2));
3896   /*
3897     If the left choice expression generated a new temporary variable
3898     (e.g. in case of a function or a method call), then the right
3899     choice expression should store the result into the same variable.
3900   */
3901   if (!UdmParseConditionalExpression(compiler, &expr2, NULL, complex_func_result_on_stack))
3902     return UdmProgCompilerExpectedRule(compiler, "<conditional-expression>");
3903 
3904   if (UdmExprHandler(expr) != UdmExprHandler(&expr2))
3905     return UdmProgCompilerNotSupported(compiler, "conditional expression with different argument types");
3906 
3907   if (UdmExprHandler(expr))
3908   {
3909     if (!UdmValueHandlerIsComplex(UdmExprHandler(expr)))
3910     {
3911       if (!UdmGenerateExpressionToNativeReg0(compiler, &expr2, NULL))
3912         return UDM_FALSE;
3913     }
3914     else
3915     {
3916       if (expr2.primary_expr.type != UDM_EXPRESSION_OBJECT)
3917       {
3918         /*
3919           Function call returns an initialized variable.
3920           For the other expression types call the costructor now.
3921         */
3922         if (!UdmGenerateConstructor(compiler, complex_func_result_on_stack))
3923           return UDM_FALSE;
3924         if (!UdmGenerateAssignmentOperator(compiler,
3925                                            complex_func_result_on_stack,
3926                                            &expr2.primary_expr,
3927                                            expr2.primary_expr.type))
3928         return UDM_FALSE;
3929       }
3930     }
3931   }
3932 
3933   UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler), jmp1, jmp1 + 1);
3934   expr->primary_expr.type= UDM_EXPRESSION_OBJECT;
3935   return UDM_TRUE;
3936 }
3937 
3938 
3939 /*
3940 <assignment-operator> ::= =
3941                         | *=
3942                         | /=
3943                         | %=
3944                         | +=
3945                         | -=
3946                         | <<=
3947                         | >>=
3948                         | &=
3949                         | ^=
3950                         | |=
3951 */
3952 
3953 static udm_bool_t
ParseEqAssignmentOperator(UDM_PROG_COMPILER * compiler)3954 ParseEqAssignmentOperator(UDM_PROG_COMPILER *compiler)
3955 {
3956   return ParseTerm(compiler, UDM_LEX_EQ);
3957 }
3958 
3959 
3960 static udm_bool_t
ParseSpecialAssignmentOperator(UDM_PROG_COMPILER * compiler,udm_special_assignment_t * op,udm_tmpl_cmd_t * cmd)3961 ParseSpecialAssignmentOperator(UDM_PROG_COMPILER *compiler,
3962                                udm_special_assignment_t *op,
3963                                udm_tmpl_cmd_t *cmd)
3964 {
3965   *cmd= UdmProgCompilerLastTokenType(compiler);
3966   if (ParseTerm(compiler, UDM_LEX_MUL_EQ))
3967   {
3968     *op= UDM_ASSIGNMENT_MUL;
3969     return UDM_TRUE;
3970   }
3971   if (ParseTerm(compiler, UDM_LEX_DIV_EQ))
3972   {
3973     *op= UDM_ASSIGNMENT_DIV;
3974     return UDM_TRUE;
3975   }
3976   if (ParseTerm(compiler, UDM_LEX_REM_EQ))
3977   {
3978     *op= UDM_ASSIGNMENT_REM;
3979     return UDM_TRUE;
3980   }
3981   if (ParseTerm(compiler, UDM_LEX_INC_EQ))
3982   {
3983     *op= UDM_ASSIGNMENT_ADD;
3984     return UDM_TRUE;
3985   }
3986   if (ParseTerm(compiler, UDM_LEX_AND_EQ))
3987   {
3988     *op= UDM_ASSIGNMENT_AND;
3989     return UDM_TRUE;
3990   }
3991   if (ParseTerm(compiler, UDM_LEX_OR_EQ))
3992   {
3993     *op= UDM_ASSIGNMENT_OR;
3994     return UDM_TRUE;
3995   }
3996   if (ParseTerm(compiler, UDM_LEX_XOR_EQ))
3997   {
3998     *op= UDM_ASSIGNMENT_XOR;
3999     return UDM_TRUE;
4000   }
4001   if (ParseTerm(compiler, UDM_LEX_DEC_EQ))
4002   {
4003     *op= UDM_ASSIGNMENT_SUB;
4004     return UDM_TRUE;
4005   }
4006   if (ParseTerm(compiler, UDM_LEX_LSHIFT_EQ))
4007   {
4008     *op= UDM_ASSIGNMENT_LSHIFT;
4009     return UDM_TRUE;
4010   }
4011   if (ParseTerm(compiler, UDM_LEX_RSHIFT_EQ))
4012   {
4013     *op= UDM_ASSIGNMENT_RSHIFT;
4014     return UDM_TRUE;
4015   }
4016   return UDM_FALSE;
4017 }
4018 
4019 
4020 static udm_bool_t
UdmSpecialAssignmentOpDouble(UDM_PROG_COMPILER * c,udm_tmpl_cmd_t * cmd,udm_special_assignment_t op,const UDM_VALUE_HANDLER * dst,const UDM_VALUE_HANDLER * src)4021 UdmSpecialAssignmentOpDouble(UDM_PROG_COMPILER *c,
4022                              udm_tmpl_cmd_t *cmd, udm_special_assignment_t op,
4023                              const UDM_VALUE_HANDLER *dst,
4024                              const UDM_VALUE_HANDLER *src)
4025 {
4026   switch (op)
4027   {
4028   case UDM_ASSIGNMENT_ADD: *cmd= UDM_PROG_ADD_DREG0_DREG1; return UDM_TRUE;
4029   case UDM_ASSIGNMENT_SUB: *cmd= UDM_PROG_SUB_DREG0_DREG1; return UDM_TRUE;
4030   case UDM_ASSIGNMENT_MUL: *cmd= UDM_PROG_MUL_DREG0_DREG1; return UDM_TRUE;
4031   case UDM_ASSIGNMENT_DIV: *cmd= UDM_PROG_DIV_DREG0_DREG1; return UDM_TRUE;
4032   case UDM_ASSIGNMENT_REM:
4033     return UdmProgCompilerBadDataTypeForOperator2(c, "%=", dst, src);
4034   case UDM_ASSIGNMENT_AND:
4035     return UdmProgCompilerBadDataTypeForOperator2(c, "&=", dst, src);
4036   case UDM_ASSIGNMENT_OR:
4037     return UdmProgCompilerBadDataTypeForOperator2(c, "|=", dst, src);
4038   case UDM_ASSIGNMENT_XOR:
4039     return UdmProgCompilerBadDataTypeForOperator2(c, "^=", dst, src);
4040   case UDM_ASSIGNMENT_LSHIFT:
4041     return UdmProgCompilerBadDataTypeForOperator2(c, "<<=", dst, src);
4042   case UDM_ASSIGNMENT_RSHIFT:
4043     return UdmProgCompilerBadDataTypeForOperator2(c, ">>=", dst, src);
4044   }
4045   UDM_ASSERT(0);
4046   return UDM_FALSE;
4047 }
4048 
4049 
4050 static udm_bool_t
UdmSpecialAssignmentOpInt(UDM_PROG_COMPILER * c,udm_tmpl_cmd_t * cmd,udm_special_assignment_t op,const UDM_VALUE_HANDLER * dst,const UDM_VALUE_HANDLER * src)4051 UdmSpecialAssignmentOpInt(UDM_PROG_COMPILER *c,
4052                           udm_tmpl_cmd_t *cmd, udm_special_assignment_t op,
4053                           const UDM_VALUE_HANDLER *dst,
4054                           const UDM_VALUE_HANDLER *src)
4055 {
4056   switch (op)
4057   {
4058   case UDM_ASSIGNMENT_ADD: *cmd= UDM_PROG_ADD_IREG0_IREG1; return UDM_TRUE;
4059   case UDM_ASSIGNMENT_SUB: *cmd= UDM_PROG_SUB_IREG0_IREG1; return UDM_TRUE;
4060   case UDM_ASSIGNMENT_MUL: *cmd= UDM_PROG_MUL_IREG0_IREG1; return UDM_TRUE;
4061   case UDM_ASSIGNMENT_DIV: *cmd= UDM_PROG_DIV_IREG0_IREG1; return UDM_TRUE;
4062   case UDM_ASSIGNMENT_REM: *cmd= UDM_PROG_REM_IREG0_IREG1; return UDM_TRUE;
4063   case UDM_ASSIGNMENT_AND: *cmd= UDM_PROG_AND_IREG0_IREG1; return UDM_TRUE;
4064   case UDM_ASSIGNMENT_OR:  *cmd= UDM_PROG_OR_IREG0_IREG1;  return UDM_TRUE;
4065   case UDM_ASSIGNMENT_XOR: *cmd= UDM_PROG_XOR_IREG0_IREG1;  return UDM_TRUE;
4066   case UDM_ASSIGNMENT_LSHIFT: *cmd= UDM_PROG_SHL_IREG0_IREG1;  return UDM_TRUE;
4067   case UDM_ASSIGNMENT_RSHIFT: *cmd= UDM_PROG_SHR_IREG0_IREG1;  return UDM_TRUE;
4068   }
4069   UDM_ASSERT(0);
4070   return UDM_FALSE;
4071 }
4072 
4073 
4074 static udm_bool_t
UdmSpecialAssignmentOp(UDM_PROG_COMPILER * c,udm_tmpl_cmd_t * cmd,udm_special_assignment_t op,const UDM_VALUE_HANDLER * dst,const UDM_VALUE_HANDLER * src,const UDM_VALUE_HANDLER * agg)4075 UdmSpecialAssignmentOp(UDM_PROG_COMPILER *c,
4076                        udm_tmpl_cmd_t *cmd,
4077                        udm_special_assignment_t op,
4078                        const UDM_VALUE_HANDLER *dst,
4079                        const UDM_VALUE_HANDLER *src,
4080                        const UDM_VALUE_HANDLER *agg)
4081 {
4082   UDM_ASSERT(!UdmValueHandlerIsComplex(agg));
4083   UDM_ASSERT(!UdmValueHandlerIsComplex(agg));
4084   return agg->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE ?
4085          UdmSpecialAssignmentOpDouble(c, cmd, op, dst, src):
4086          UdmSpecialAssignmentOpInt(c, cmd, op, dst, src);
4087 }
4088 
4089 
4090 static udm_bool_t
UdmGenerateSpecialAssignmentConvertAndPerform(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * dst,const UDM_VALUE_HANDLER * src,udm_special_assignment_t op)4091 UdmGenerateSpecialAssignmentConvertAndPerform(UDM_PROG_COMPILER *compiler,
4092                                               const UDM_PROG_VAR *dst,
4093                                               const UDM_VALUE_HANDLER *src,
4094                                               udm_special_assignment_t op)
4095 {
4096   UDM_VALUE_HANDLER *agg=
4097     src->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE ||
4098     UdmProgVarHandler(dst)->native_reg_type == UDM_VALUE_DATA_TYPE_DOUBLE ?
4099     &UdmValueHandlerDouble : &UdmValueHandlerInt;
4100   UDM_PROG_CMD *cmdstore=  agg == &UdmValueHandlerDouble ?
4101                            &udm_tmpl_set_var_from_dreg0 :
4102                            &udm_tmpl_set_var_from_ireg0;
4103   udm_tmpl_cmd_t cmd;
4104   UDM_ASSERT(!UdmValueHandlerIsComplex(UdmProgVarHandler(dst)));
4105   UDM_ASSERT(!UdmValueHandlerIsComplex(src));
4106   return
4107     UdmSpecialAssignmentOp(compiler, &cmd, op,
4108                            UdmProgVarHandler(dst), src, agg) &&
4109     UdmGenerateNativeReg0TypeConversion(compiler, agg,
4110                                         UdmProgVarHandler(dst)) &&
4111     UdmGenerateNativeReg1TypeConversion(compiler, agg, src) &&
4112     UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg, cmd) &&
4113     UdmGenerateVariableOperation(compiler, dst, cmdstore);
4114 }
4115 
4116 
4117 /*
4118   Generate expression value in reg1,
4119   or move expression result from reg0 to reg1.
4120   Used to handle source expressions in special assignment operators,
4121   e.g. x<<=1.
4122 */
4123 static udm_bool_t
UdmGenerateExpressionToNativeReg1(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var,UDM_PROG_EXPRESSION * expr)4124 UdmGenerateExpressionToNativeReg1(UDM_PROG_COMPILER *compiler,
4125                                  const UDM_PROG_VAR *Var,
4126                                  UDM_PROG_EXPRESSION *expr)
4127 {
4128   switch (expr->primary_expr.type)
4129   {
4130   case UDM_EXPRESSION_CONST:
4131     expr->primary_expr.type= UDM_EXPRESSION_COMPUTED;
4132     return UdmGenerateLiteralToNativeRegN(compiler, &expr->primary_expr, 1);
4133   case UDM_EXPRESSION_IDENT:
4134     expr->primary_expr.type= UDM_EXPRESSION_COMPUTED;
4135     return UdmGenerateVarToNativeReg1(compiler, &expr->primary_expr.Var);
4136   case UDM_EXPRESSION_OBJECT:
4137     expr->primary_expr.type= UDM_EXPRESSION_COMPUTED;
4138     if (UdmValueHandlerIsComplex(UdmExprHandler(expr)))
4139       return UdmProgCompilerNotSupported(compiler, "Function of a complex return type in this context");
4140   case UDM_EXPRESSION_COMPUTED:
4141     return
4142       UdmGenerateMovNativeReg0ToReg1(compiler, UdmExprHandler(expr));
4143   }
4144   UDM_ASSERT(0);
4145   return UDM_FALSE;
4146 }
4147 
4148 
4149 static udm_bool_t
UdmGenerateExpressionSpecialAssignment(UDM_PROG_COMPILER * c,const UDM_PROG_VAR * Var,UDM_PROG_EXPRESSION * expr,udm_special_assignment_t op)4150 UdmGenerateExpressionSpecialAssignment(UDM_PROG_COMPILER *c,
4151                                        const UDM_PROG_VAR *Var,
4152                                        UDM_PROG_EXPRESSION *expr,
4153                                        udm_special_assignment_t op)
4154 {
4155 
4156   return
4157     UdmGenerateExpressionToNativeReg1(c, Var, expr) &&
4158     UdmGenerateVarToNativeReg0(c, Var) &&
4159     UdmGenerateSpecialAssignmentConvertAndPerform(c, Var,
4160                                                   UdmExprHandler(expr), op);
4161 }
4162 
4163 
4164 static udm_bool_t
UdmGenerateVarFromNativeReg0(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * dst)4165 UdmGenerateVarFromNativeReg0(UDM_PROG_COMPILER *compiler,
4166                              const UDM_PROG_VAR *dst)
4167 {
4168   switch (UdmProgVarHandler(dst)->datatype)
4169   {
4170   case UDM_VALUE_DATA_TYPE_INT:
4171   case UDM_VALUE_DATA_TYPE_CHAR:
4172     return UdmGenerateVariableOperation(compiler, dst, &udm_tmpl_set_var_from_ireg0);
4173   case UDM_VALUE_DATA_TYPE_DOUBLE:
4174     return UdmGenerateVariableOperation(compiler, dst, &udm_tmpl_set_var_from_dreg0);
4175   default:
4176     return UdmGenerateVariableOperation(compiler, dst, &udm_tmpl_set_var_from_cs0_z0);
4177   }
4178   UDM_ASSERT(0);
4179   return UDM_FALSE;
4180 }
4181 
4182 
4183 /*
4184   @param name    - variable  name
4185   @param vname   - value name (e.g. function)
4186   @param handler - value handler
4187 */
4188 static udm_bool_t
UdmGenerateVarAssignedFromFunctionCallResult(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * dst,const UDM_VALUE_HANDLER * function_type_handler)4189 UdmGenerateVarAssignedFromFunctionCallResult(UDM_PROG_COMPILER *compiler,
4190                                              const UDM_PROG_VAR *dst,
4191                                              const UDM_VALUE_HANDLER *function_type_handler)
4192 {
4193   switch (function_type_handler->datatype)
4194   {
4195   case UDM_VALUE_DATA_TYPE_INT:
4196   case UDM_VALUE_DATA_TYPE_DOUBLE:
4197     return
4198       UdmGenerateNativeReg0TypeConversion(compiler,
4199                                           UdmProgVarHandler(dst),
4200                                           function_type_handler) &&
4201       UdmGenerateVarFromNativeReg0(compiler, dst);
4202   case UDM_VALUE_DATA_TYPE_STR:
4203   {
4204     return
4205       UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_HREG0_0) &&
4206       UDM_OK == UdmProgAddArg0SimpleOp(compiler->prg, UDM_PROG_MOV_SREG0_0);
4207   }
4208   case UDM_VALUE_DATA_TYPE_CHAR:
4209   case UDM_VALUE_DATA_TYPE_ENV:
4210   case UDM_VALUE_DATA_TYPE_RESULT:
4211   case UDM_VALUE_DATA_TYPE_DOCUMENT:
4212   case UDM_VALUE_DATA_TYPE_SQLRESULT:
4213   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
4214     break;
4215   }
4216   UDM_ASSERT(0);
4217   return UDM_FALSE;
4218 }
4219 
4220 
4221 static udm_bool_t
GenerateVarAssignedFromLiteral(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * dst,const UDM_PROG_PRIMARY_EXPRESSION * expr)4222 GenerateVarAssignedFromLiteral(UDM_PROG_COMPILER *compiler,
4223                                const UDM_PROG_VAR *dst,
4224                                const UDM_PROG_PRIMARY_EXPRESSION *expr)
4225 {
4226   UDM_PROG_ITEM i;
4227   switch (UdmPrimaryExprHandler(expr)->datatype)
4228   {
4229   case UDM_VALUE_DATA_TYPE_INT:
4230   case UDM_VALUE_DATA_TYPE_CHAR:
4231   case UDM_VALUE_DATA_TYPE_DOUBLE:
4232     return UdmGenerateLiteralToNativeRegN(compiler, expr, 0) &&
4233            UdmGenerateNativeReg0TypeConversion(compiler,
4234                                                UdmProgVarHandler(dst),
4235                                                UdmPrimaryExprHandler(expr)) &&
4236            UdmGenerateVarFromNativeReg0(compiler, dst);
4237   case UDM_VALUE_DATA_TYPE_ENV:
4238   case UDM_VALUE_DATA_TYPE_RESULT:
4239   case UDM_VALUE_DATA_TYPE_DOCUMENT:
4240   case UDM_VALUE_DATA_TYPE_SQLRESULT:
4241   case UDM_VALUE_DATA_TYPE_EXCERPT_FRAGMENT:
4242     UDM_ASSERT(0);
4243     /* Pass through */
4244   case UDM_VALUE_DATA_TYPE_STR:
4245     break;
4246   }
4247   UdmProgItemInit(&i);
4248   UdmProgItemArgInitFromVar(&i.item_args, dst);
4249   UdmProgItemArgInitFromLiteral(&i.item_args, &expr->Var.name, &expr->textdata_addr);
4250   i.cmd= &udm_tmpl_set_var_from_text0;
4251   return UdmProgAdd(compiler->prg, &i) == UDM_OK;
4252 }
4253 
4254 
4255 static udm_bool_t
GenerateVarAssignedFromVar(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * dst,const UDM_PROG_VAR * src)4256 GenerateVarAssignedFromVar(UDM_PROG_COMPILER *compiler,
4257                            const UDM_PROG_VAR *dst,
4258                            const UDM_PROG_VAR *src)
4259 {
4260   return UdmGenerateVarToNativeReg0(compiler, src) &&
4261          UdmGenerateNativeReg0TypeConversion(compiler,
4262                                              UdmProgVarHandler(dst),
4263                                              UdmProgVarHandler(src)) &&
4264          UdmGenerateVarFromNativeReg0(compiler, dst);
4265 }
4266 
4267 
4268 /**
4269   Generate an assignment:
4270     x= expr;
4271   The variable must be initialized
4272   (i.e. a contructor call was previously generated).
4273 */
4274 static udm_bool_t
UdmGenerateVarAssignmentFromExpression(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * dst,const UDM_PROG_EXPRESSION * expr)4275 UdmGenerateVarAssignmentFromExpression(UDM_PROG_COMPILER *compiler,
4276                                        const UDM_PROG_VAR *dst,
4277                                        const UDM_PROG_EXPRESSION *expr)
4278 {
4279   switch (expr->primary_expr.type)
4280   {
4281   case UDM_EXPRESSION_IDENT:
4282     return GenerateVarAssignedFromVar(compiler, dst, &expr->primary_expr.Var);
4283   case UDM_EXPRESSION_CONST:
4284     return GenerateVarAssignedFromLiteral(compiler, dst, &expr->primary_expr);
4285   case UDM_EXPRESSION_OBJECT:
4286     UDM_ASSERT(!UdmValueHandlerIsComplex(UdmExprHandler(expr)));
4287     return UdmGenerateVarAssignedFromFunctionCallResult(compiler, dst,
4288                                                         UdmExprHandler(expr));
4289   case UDM_EXPRESSION_COMPUTED:
4290     return UdmGenerateNativeReg0TypeConversion(compiler,
4291                                                UdmProgVarHandler(dst),
4292                                                UdmExprHandler(expr)) &&
4293            UdmGenerateVarFromNativeReg0(compiler, dst);
4294   }
4295   UDM_ASSERT(0);
4296   return UdmProgCompilerNotSupported(compiler, "This type of <postfix epxression> as a variable initializer");
4297 }
4298 
4299 
4300 static udm_bool_t
UdmProgAddAssignmentNone(UDM_PROG_COMPILER * compiler,const UDM_PROG_EXPRESSION * expr)4301 UdmProgAddAssignmentNone(UDM_PROG_COMPILER *compiler,
4302                          const UDM_PROG_EXPRESSION *expr)
4303 {
4304   if (0 && !ExpressionHasEffect(expr))
4305   {
4306     char tmp[128];
4307     size_t tmplen;
4308     tmplen= udm_snprintf(tmp, sizeof(tmp),
4309                          "WARNING: statement has no effect: '%.*s'\n",
4310     (int) UdmConstTokenLength(&expr->primary_expr.Var.name),
4311             UdmConstTokenStr(&expr->primary_expr.Var.name));
4312     UdmProgGenerateCoutText(compiler, tmp, tmp + tmplen, UDM_TRUE);
4313     return UDM_TRUE;
4314   }
4315   return UDM_TRUE;
4316 }
4317 
4318 
4319 /**
4320   Parsee the right side of an assignment:
4321 
4322   int x= expr;
4323   x= expr;
4324   x+= expr;
4325 */
4326 static udm_bool_t
UdmParseAssignmentSource(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_func_result_on_stack,const UDM_PROG_VAR * dstvar)4327 UdmParseAssignmentSource(UDM_PROG_COMPILER *compiler,
4328                          UDM_PROG_EXPRESSION *expr,
4329                          UDM_PROG_VAR *complex_func_result_on_stack,
4330                          const UDM_PROG_VAR *dstvar)
4331 {
4332   UDM_BZERO(expr, sizeof(*expr));
4333   /* Notice, it's <assignment-expression> here, not <expression> */
4334   if (!UdmParseAssignmentExpression(compiler, expr,
4335                                     complex_func_result_on_stack, dstvar))
4336     return UdmProgCompilerExpectedRule(compiler, "<assignment-expression>");
4337   if (!UdmExprHandler(expr))
4338     return UdmProgCompilerVoidValueIsNotIgnored(compiler);
4339   return UDM_TRUE;
4340 }
4341 
4342 
4343 static udm_bool_t
UdmExpressionIsGoodAssignmentTarget(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr)4344 UdmExpressionIsGoodAssignmentTarget(UDM_PROG_COMPILER *compiler,
4345                                     UDM_PROG_EXPRESSION *expr)
4346 {
4347   switch (expr->primary_expr.type)
4348   {
4349   case UDM_EXPRESSION_IDENT:
4350     return UDM_TRUE;
4351   case UDM_EXPRESSION_CONST:
4352   case UDM_EXPRESSION_OBJECT:
4353   case UDM_EXPRESSION_COMPUTED:
4354     break;
4355   }
4356   return UdmProgCompilerNotSupported(compiler,
4357                                      "This type of expression as an assignment target");
4358 }
4359 
4360 
4361 static udm_bool_t
UdmFindAssignmentOperatorForArgs(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler,const UDM_PROG_FUNCTION_CALL_ARGUMENTS * args,const UDM_FUNCTION ** func)4362 UdmFindAssignmentOperatorForArgs(UDM_PROG_COMPILER *compiler,
4363                                  const UDM_VALUE_HANDLER *handler,
4364                                  const UDM_PROG_FUNCTION_CALL_ARGUMENTS *args,
4365                                  const UDM_FUNCTION **func)
4366 {
4367   if (!(func[0]= UdmValueHandlerMethodFind(handler,
4368                                            UDM_CSTR_WITH_LEN("operator="),
4369                                            args)))
4370   {
4371     UDM_CONST_TOKEN name;
4372     UdmConstTokenSet(&name, UDM_CSTR_WITH_LEN("operator="));
4373     return UdmProgCompilerUnknownMethodError(compiler, handler, &name, args);
4374   }
4375   return UDM_TRUE;
4376 }
4377 
4378 
4379 static udm_bool_t
UdmFindAssignmentOperator(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * dst,const UDM_VALUE_HANDLER * src,const UDM_FUNCTION ** func)4380 UdmFindAssignmentOperator(UDM_PROG_COMPILER *compiler,
4381                           const UDM_VALUE_HANDLER *dst,
4382                           const UDM_VALUE_HANDLER *src,
4383                           const UDM_FUNCTION **func)
4384 {
4385   UDM_PROG_FUNCTION_CALL_ARGUMENTS args;
4386   UDM_BZERO(&args, sizeof(args));
4387   UdmProgVarSetHandler(&args.args[0].Var, src);
4388   args.args[0].type= UDM_EXPRESSION_IDENT;
4389   args.nargs= 1;
4390   return UdmFindAssignmentOperatorForArgs(compiler, dst, &args, func);
4391 }
4392 
4393 
4394 static udm_bool_t
UdmGenerateAssignmentOperator(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var,const UDM_PROG_PRIMARY_EXPRESSION * Src,udm_expression_t type)4395 UdmGenerateAssignmentOperator(UDM_PROG_COMPILER *compiler,
4396                               const UDM_PROG_VAR *Var,
4397                               const UDM_PROG_PRIMARY_EXPRESSION *Src,
4398                               udm_expression_t type)
4399 {
4400   const UDM_FUNCTION *func;
4401   UDM_PROG_FUNCTION_CALL_ARGUMENTS args;
4402   UDM_BZERO(&args, sizeof(args));
4403   args.args[0].Var= Src[0].Var;
4404   args.args[0].textdata_addr= Src->textdata_addr;
4405   args.args[0].type= type;
4406   args.nargs= 1;
4407   return
4408     UdmFindAssignmentOperatorForArgs(compiler, UdmProgVarHandler(Var),
4409                                      &args, &func) &&
4410     UdmGenerateNewFunctionCall(compiler, func, Var, &args, NULL, Var);
4411 }
4412 
4413 
4414 /**
4415   Assign an expression to a variable.
4416   The variable must be initialized
4417   (i.e. a constructor call was previously generated).
4418 */
4419 static udm_bool_t
UdmGenerateAssignment(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var,const UDM_PROG_EXPRESSION * value,const UDM_PROG_PRIMARY_EXPRESSION * tmp)4420 UdmGenerateAssignment(UDM_PROG_COMPILER *compiler,
4421                       const UDM_PROG_VAR *Var,
4422                       const UDM_PROG_EXPRESSION *value,
4423                       const UDM_PROG_PRIMARY_EXPRESSION *tmp)
4424 {
4425   if (UdmPrimaryExprHandler(tmp))
4426   {
4427     /*
4428       The expression was a function call returning a complex object.
4429       Copy temporary variable to the destination variable.
4430     */
4431     UDM_ASSERT(UdmValueHandlerIsComplex(UdmPrimaryExprHandler(tmp)));
4432     return UdmGenerateAssignmentOperator(compiler, Var, tmp,
4433                                          UDM_EXPRESSION_IDENT);
4434   }
4435   else if (!UdmValueHandlerIsComplex(UdmProgVarHandler(Var)))
4436   {
4437     if (!UdmDyadicOperatorFindWithError(compiler, assignment_operators,
4438                                         UdmProgVarHandler(Var),
4439                                         UdmExprHandler(value),
4440                                         "="))
4441       return UDM_FALSE;
4442     if (!UdmGenerateVarAssignmentFromExpression(compiler, Var, value))
4443       return UDM_FALSE;
4444 
4445   }
4446   else
4447   {
4448     UDM_ASSERT(UdmValueHandlerIsComplex(UdmProgVarHandler(Var)));
4449     switch (value->primary_expr.type)
4450     {
4451     case UDM_EXPRESSION_IDENT:
4452     case UDM_EXPRESSION_CONST:
4453       return UdmGenerateAssignmentOperator(compiler, Var,
4454                                            &value->primary_expr,
4455                                            value->primary_expr.type);
4456     case UDM_EXPRESSION_OBJECT:
4457       UDM_ASSERT(0);
4458       return UDM_FALSE;
4459     case UDM_EXPRESSION_COMPUTED:
4460       {
4461         /*
4462           TODO: get rid of this.
4463           <conditional-expression> currenly returns complex values in cs0/z0.
4464           This is limited to string type only and should be changed
4465           to support all other complex data types.
4466         */
4467         const UDM_FUNCTION *func;
4468         if (!UdmFindAssignmentOperator(compiler,
4469                                        UdmProgVarHandler(Var),
4470                                        UdmExprHandler(value), &func))
4471           return UDM_FALSE;
4472         if (!UdmGenerateVarAssignmentFromExpression(compiler, Var, value))
4473           return UDM_FALSE;
4474       }
4475       break;
4476     }
4477   }
4478 
4479   return UDM_TRUE;
4480 }
4481 
4482 
4483 
4484 /**
4485   Parse the expression in the right side of an assignment,
4486   and generate the assignment.
4487   TODO: this crashes:
4488     string x= "abcd";
4489     string y;
4490     y= x.substr(1,3).substr(0,2).length();
4491 */
4492 static udm_bool_t
UdmParseAssignmentPart2(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * dst)4493 UdmParseAssignmentPart2(UDM_PROG_COMPILER *compiler,
4494                         const UDM_PROG_VAR *dst)
4495 {
4496   /*
4497     For an expression like this:
4498       string x= "test"; x= x.left();
4499     we create a temporary variable for the function/method result,
4500     which then copied to the final destination.
4501     If there are multiple temporary values in the same <assignment-expression>:
4502       x= x.left(), y= y.left();
4503     then all temporary values destructed at once at the end
4504     (e.g. when the semicolon is read).
4505   */
4506   UDM_PROG_EXPRESSION rvalue;
4507   UDM_PROG_PRIMARY_EXPRESSION tmp;
4508   UDM_BZERO(&tmp, sizeof(tmp));
4509   tmp.type= UDM_EXPRESSION_IDENT; /*TODO: get rid if this, pass UDM_PROG_VAR*/
4510   return UdmParseAssignmentSource(compiler, &rvalue, &tmp.Var, NULL) &&
4511          UdmGenerateAssignment(compiler, dst, &rvalue, &tmp);
4512 }
4513 
4514 
4515 /**
4516   <assignment-expression> ::=
4517       <conditional-expression>
4518     | <unary-expression> <assignment-operator> <assignment-expression>
4519 */
4520 static udm_bool_t
UdmParseAssignmentExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_result_on_stack,const UDM_PROG_VAR * dstvar)4521 UdmParseAssignmentExpression(UDM_PROG_COMPILER *compiler,
4522                              UDM_PROG_EXPRESSION *expr,
4523                              UDM_PROG_VAR *complex_result_on_stack,
4524                              const UDM_PROG_VAR *dstvar)
4525 {
4526   udm_special_assignment_t op;
4527   udm_tmpl_cmd_t cmd;
4528   if (!UdmParseConditionalExpression(compiler, expr,
4529                                      complex_result_on_stack, dstvar))
4530     return UDM_FALSE;
4531   if (ParseEqAssignmentOperator(compiler))  /* x= expression; */
4532   {
4533     return UdmExpressionIsGoodAssignmentTarget(compiler, expr) &&
4534            UdmParseAssignmentPart2(compiler, &expr->primary_expr.Var);
4535   }
4536   if (ParseSpecialAssignmentOperator(compiler, &op, &cmd)) /* e.g. x+= expression; */
4537   {
4538     UDM_PROG_EXPRESSION rvalue;
4539     UDM_PROG_VAR complex_result_on_stack2;
4540     UDM_BZERO(&complex_result_on_stack2, sizeof(complex_result_on_stack2));
4541     if (!UdmExpressionIsGoodAssignmentTarget(compiler, expr))
4542       return UDM_FALSE;
4543     if (!UdmParseAssignmentSource(compiler, &rvalue,
4544                                   &complex_result_on_stack2, NULL))
4545       return UDM_FALSE;
4546     if (!UdmDyadicOperatorFindWithError(compiler, assignment_operators,
4547                                         UdmExprHandler(expr),
4548                                         UdmExprHandler(&rvalue),
4549                                         UdmLex2str(cmd)))
4550       return UDM_FALSE;
4551     /* Special assignment operators for complex types are not supported yet */
4552     UDM_ASSERT(!UdmValueHandlerIsComplex(UdmExprHandler(&rvalue)));
4553     UDM_ASSERT(!UdmProgVarHandler(&complex_result_on_stack2));
4554     return UdmGenerateExpressionSpecialAssignment(compiler,
4555                                                   &expr->primary_expr.Var,
4556                                                   &rvalue, op);
4557   }
4558   if (!UdmProgAddAssignmentNone(compiler, expr))
4559     return UDM_FALSE;
4560   return UDM_TRUE;
4561 }
4562 
4563 
4564 /*
4565 <expression> ::= <assignment-expression> {, <assignment-expression> }
4566 */
4567 static udm_bool_t
UdmParseExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,UDM_PROG_VAR * complex_result_on_stack,const UDM_PROG_VAR * dstvar)4568 UdmParseExpression(UDM_PROG_COMPILER *compiler,
4569                    UDM_PROG_EXPRESSION *expr,
4570                    UDM_PROG_VAR *complex_result_on_stack,
4571                    const UDM_PROG_VAR *dstvar)
4572 {
4573   if (!UdmParseAssignmentExpression(compiler, expr,
4574                                     complex_result_on_stack, dstvar))
4575     return UDM_FALSE;
4576   for ( ; ; )
4577   {
4578     if (!ParseTerm(compiler, UDM_LEX_COMMA))
4579       return UDM_TRUE;
4580     UDM_BZERO(expr, sizeof(*expr));
4581     if (!UdmParseAssignmentExpression(compiler, expr,
4582                                       complex_result_on_stack, dstvar))
4583       return UdmProgCompilerExpectedRule(compiler, "<assignment-expression>");
4584   }
4585   return UDM_TRUE;
4586 }
4587 
4588 
4589 /**
4590   Parse an assignment expression in its own block.
4591   If the expression returns a value which is not used,
4592   it needs to be destructed immediately, e.g.:
4593   {
4594     string str= "xxx";
4595     str.left();
4596   }
4597   UdmProgCompilerLeaveBlock makes sure it's destructed.
4598   This effectively converts expressions like:
4599     str.left();
4600   into
4601     {
4602       string str= str.left(); // str is destructed here
4603     }
4604 */
4605 static udm_bool_t
UdmParseExpressionIgnoreResult(UDM_PROG_COMPILER * compiler)4606 UdmParseExpressionIgnoreResult(UDM_PROG_COMPILER *compiler)
4607 {
4608   udm_bool_t rc;
4609   UDM_PROG_EXPRESSION expr;
4610   UDM_PROG_VAR complex_result_on_stack;
4611   UDM_BZERO(&expr, sizeof(expr));
4612   UDM_BZERO(&complex_result_on_stack, sizeof(complex_result_on_stack));
4613   if (!UdmProgCompilerEnterBlock(compiler))
4614     return UDM_FALSE;
4615   rc= UdmParseExpression(compiler, &expr,
4616                          &complex_result_on_stack, NULL);
4617   if (!UdmProgCompilerLeaveBlock(compiler))
4618     return UDM_FALSE;
4619   return rc;
4620 }
4621 
4622 
4623 static udm_bool_t
UdmGenerateCoutReg0(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * handler)4624 UdmGenerateCoutReg0(UDM_PROG_COMPILER *compiler,
4625                     const UDM_VALUE_HANDLER *handler)
4626 {
4627   switch (handler->type)
4628   {
4629     case UDM_VALUE_HANDLER_TYPE_CHAR:
4630       return UDM_OK == UdmProgAddArg0Simple(compiler->prg, &udm_tmpl_cout_ireg0_char);
4631     case UDM_VALUE_HANDLER_TYPE_INT:
4632       return UDM_OK == UdmProgAddArg0Simple(compiler->prg, &udm_tmpl_cout_ireg0);
4633     case UDM_VALUE_HANDLER_TYPE_DOUBLE:
4634       return UDM_OK == UdmProgAddArg0Simple(compiler->prg, &udm_tmpl_cout_dreg0);
4635     case UDM_VALUE_HANDLER_TYPE_STR:
4636     case UDM_VALUE_HANDLER_TYPE_ENV:
4637     case UDM_VALUE_HANDLER_TYPE_RESULT:
4638     case UDM_VALUE_HANDLER_TYPE_DOCUMENT:
4639     case UDM_VALUE_HANDLER_TYPE_SQLRESULT:
4640     case UDM_VALUE_HANDLER_TYPE_EXCERPT_FRAGMENT:
4641       return UDM_OK == UdmProgAddArg0Simple(compiler->prg, &udm_tmpl_cout_cs0_z0);
4642   }
4643   UDM_ASSERT(0);
4644   return UDM_FALSE;
4645 }
4646 
4647 
4648 /*
4649   Return UDM_TRUE on success, UDM_FALSE on error.
4650 */
4651 static udm_bool_t
UdmGenerateCoutExpression(UDM_PROG_COMPILER * compiler,UDM_PROG_EXPRESSION * expr,const UDM_PROG_VAR * func_result)4652 UdmGenerateCoutExpression(UDM_PROG_COMPILER *compiler,
4653                           UDM_PROG_EXPRESSION *expr,
4654                           const UDM_PROG_VAR *func_result)
4655 {
4656   udm_expression_t orig_type= expr->primary_expr.type;
4657   if (!UdmGenerateExpressionToNativeReg0(compiler, expr, func_result))
4658     return UDM_FALSE;
4659   switch (orig_type)
4660   {
4661     case UDM_EXPRESSION_IDENT:
4662     case UDM_EXPRESSION_CONST:
4663     case UDM_EXPRESSION_COMPUTED:
4664       return UdmGenerateCoutReg0(compiler, UdmExprHandler(expr));
4665     case UDM_EXPRESSION_OBJECT:
4666       if (!UdmExprHandler(expr))
4667         return UdmProgCompilerVoidValueIsNotIgnored(compiler);
4668       if (UdmProgVarHandler(func_result))
4669       {
4670         UDM_ASSERT(UdmProgVarHandler(func_result) == UdmExprHandler(expr));
4671         UDM_ASSERT(UdmValueHandlerIsComplex(UdmExprHandler(expr)));
4672         return UdmGenerateCoutReg0(compiler, UdmProgVarHandler(func_result));
4673       }
4674       else
4675       {
4676         UDM_ASSERT(!UdmValueHandlerIsComplex(UdmExprHandler(expr)));
4677         return UdmGenerateCoutReg0(compiler, UdmExprHandler(expr));
4678       }
4679   }
4680   UDM_ASSERT(0);
4681   return UDM_FALSE;
4682 }
4683 
4684 
4685 static udm_bool_t
ParseEchoExpression(UDM_PROG_COMPILER * compiler)4686 ParseEchoExpression(UDM_PROG_COMPILER *compiler)
4687 {
4688   UDM_PROG_EXPRESSION expr;
4689   if (!ParseTerm(compiler, UDM_LEX_COUT))
4690     return UDM_FALSE;
4691   if (!ParseTermOrError(compiler, UDM_LEX_LSHIFT))
4692     return UDM_FALSE;
4693   for ( ; ; )
4694   {
4695     UDM_PROG_VAR func_result;
4696     bzero(&func_result, sizeof(UDM_PROG_VAR));
4697     if (!UdmProgCompilerEnterBlock(compiler)) /* In case if expr is a function call */
4698       return UDM_FALSE;
4699     if (!ParseAdditiveExpression(compiler, &expr, &func_result, NULL))
4700       return UDM_FALSE;
4701     if (!UdmGenerateCoutExpression(compiler, &expr, &func_result))
4702       return UDM_FALSE;
4703     if (!UdmProgCompilerLeaveBlock(compiler))
4704       return UDM_FALSE;
4705     if (!ParseTerm(compiler, UDM_LEX_LSHIFT))
4706       break;
4707   }
4708   return UDM_TRUE;
4709 }
4710 
4711 
4712 /*
4713 <expression-statement> ::= {<expression>}? ;
4714 */
4715 static udm_bool_t
ParseExpressionStatement(UDM_PROG_COMPILER * compiler)4716 ParseExpressionStatement(UDM_PROG_COMPILER *compiler)
4717 {
4718   if (ParseEchoExpression(compiler))
4719     return ParseTermOrError(compiler, UDM_LEX_SEMICOLON);
4720   if (UdmParseExpressionIgnoreResult(compiler))
4721     return ParseTermOrError(compiler, UDM_LEX_SEMICOLON);
4722   return ParseTerm(compiler, UDM_LEX_SEMICOLON);
4723 }
4724 
4725 
4726 static udm_bool_t ParseStatement(UDM_PROG_COMPILER *compiler);
4727 
4728 
4729 static udm_bool_t
ParseIfCondition(UDM_PROG_COMPILER * compiler)4730 ParseIfCondition(UDM_PROG_COMPILER *compiler)
4731 {
4732   UDM_PROG_EXPRESSION expr;
4733   return
4734     UdmParseExpression(compiler, &expr, NULL, NULL) &&
4735     UdmGenerateExpressionToBool(compiler, &expr);
4736 }
4737 
4738 
4739 static udm_bool_t
ParseParenthesizedCondition(UDM_PROG_COMPILER * compiler)4740 ParseParenthesizedCondition(UDM_PROG_COMPILER *compiler)
4741 {
4742   if (!ParseTermOrError(compiler, UDM_LEX_LP))
4743     return UDM_FALSE;
4744   if (!ParseIfCondition(compiler))
4745     return UDM_FALSE;
4746   if (!ParseTermOrError(compiler, UDM_LEX_RP))
4747     return UDM_FALSE;
4748   return UDM_TRUE;
4749 }
4750 
4751 
4752 /*
4753 <selection-statement> ::= if ( <expression> ) <statement>
4754                         | if ( <expression> ) <statement> else <statement>
4755                         | switch ( <expression> ) <statement>
4756 */
ParseSelectionStatement(UDM_PROG_COMPILER * compiler)4757 static udm_bool_t ParseSelectionStatement(UDM_PROG_COMPILER *compiler)
4758 {
4759   size_t jne_to_end_of_if_block;
4760   if (!ParseTerm(compiler, UDM_LEX_IF))
4761     return UDM_FALSE;
4762   if (!ParseParenthesizedCondition(compiler))
4763     return UDM_FALSE;
4764 
4765   /* jne to end_of_if_block if the condition failed */
4766   jne_to_end_of_if_block= UdmProgCompilerGetProg(compiler)->nitems;
4767   if (UdmProgAddJmp(compiler->prg, UDM_PROG_JE, 0))
4768     return UDM_FALSE;
4769 
4770   if (!ParseStatement(compiler))
4771     return UdmProgCompilerExpectedRule(compiler, "<statement>");
4772 
4773   if (ParseTerm(compiler, UDM_LEX_ELSE))
4774   {
4775     /*
4776       We are at the end of the "if" block, and there is "else".
4777       Add unconditional JMP to the end of "else".
4778     */
4779     size_t start_of_else= UdmProgCompilerGetProg(compiler)->nitems;
4780     if (UdmProgAddJmp(compiler->prg, UDM_PROG_JMP, 0))
4781       return UDM_FALSE;
4782 
4783     /*
4784       Now we know the start address of the "else" block.
4785       Fix the jump address of the command pointed by jne_to_end_of_if_block
4786       to the current address, which is the beginning of the "else" block.
4787     */
4788     UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler),
4789                           jne_to_end_of_if_block,
4790                           jne_to_end_of_if_block + 1);
4791     if (!ParseStatement(compiler))
4792       return UdmProgCompilerExpectedRule(compiler, "<statement>");
4793 
4794     UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler),
4795                           start_of_else, start_of_else + 1);
4796   }
4797   else
4798   {
4799     /*
4800       No else, just fix the command pointed by
4801       jne_to_end_of_if_block to jump to the current address,
4802       which is the end of the entire "if" statement.
4803     */
4804     UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler),
4805                           jne_to_end_of_if_block,
4806                           jne_to_end_of_if_block + 1);
4807   }
4808   return UDM_TRUE;
4809 }
4810 
4811 
4812 /*
4813   while ( <expression> ) <statement>
4814 */
4815 static udm_bool_t
ParseWhileStatement(UDM_PROG_COMPILER * compiler)4816 ParseWhileStatement(UDM_PROG_COMPILER *compiler)
4817 {
4818   size_t backup_current_loop_continue;
4819   if (!ParseTerm(compiler, UDM_LEX_WHILE))
4820     return UDM_FALSE;
4821   backup_current_loop_continue= compiler->current_loop_continue;
4822   compiler->current_loop_continue= UdmProgCompilerGetProg(compiler)->nitems;
4823   if (!ParseParenthesizedCondition(compiler))
4824     return UDM_FALSE;
4825 
4826   /* Break the loop if the condition failed */
4827   if (UdmProgAddJmpWithComment(compiler->prg,
4828                                UDM_PROG_JE, 0, "while condition failed"))
4829     return UDM_FALSE;
4830 
4831   if (!ParseStatement(compiler))
4832     return UdmProgCompilerExpectedRule(compiler, "<statement>");
4833 
4834   /* Jump to the beginning */
4835   if (UdmProgAddJmpWithComment(compiler->prg, UDM_PROG_JMP,
4836                                compiler->current_loop_continue,
4837                                "implicit continue"))
4838     return UDM_FALSE;
4839 
4840   UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler),
4841                         compiler->current_loop_continue,
4842                         UdmProgCompilerGetProg(compiler)->nitems - 1);
4843   compiler->current_loop_continue= backup_current_loop_continue;
4844   return UDM_TRUE;
4845 }
4846 
4847 
4848 static udm_bool_t
4849 ParseDeclaration(UDM_PROG_COMPILER *compiler);
4850 
4851 
4852 static udm_bool_t
UdmParseForStatementInitialization(UDM_PROG_COMPILER * compiler)4853 UdmParseForStatementInitialization(UDM_PROG_COMPILER *compiler)
4854 {
4855   return ParseDeclaration(compiler) ||
4856          UdmParseExpressionIgnoreResult(compiler);
4857 }
4858 
4859 
4860 /*
4861   The C grammar looks like:
4862     for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>
4863 
4864   We allow declaraions:
4865     for ( {<declaration>|<expression>}? ;
4866           {<expression>}? ;
4867           {<expression>}? )
4868       <statement>
4869 */
4870 static udm_bool_t
ParseForStatement(UDM_PROG_COMPILER * compiler)4871 ParseForStatement(UDM_PROG_COMPILER *compiler)
4872 {
4873   udm_bool_t has_finalize_expression;
4874   size_t condition, finalize_expression, backup_current_loop_continue;
4875   if (!ParseTerm(compiler, UDM_LEX_FOR))
4876     return UDM_FALSE;
4877   if (!ParseTermOrError(compiler, UDM_LEX_LP))
4878     return UDM_FALSE;
4879   /*
4880     Create its own level, in case the initialization part will
4881     declare variables.
4882   */
4883   if (!UdmProgCompilerEnterBlock(compiler))
4884     return UDM_FALSE;
4885   /* Optional for-init expression */
4886   if (!UdmParseForStatementInitialization(compiler) &&
4887       UdmProgCompilerError(compiler))
4888     return UDM_FALSE;
4889   if (!ParseTermOrError(compiler, UDM_LEX_SEMICOLON))
4890     return UDM_FALSE;
4891 
4892   /* Condition expression, currently non-optional */
4893   condition= UdmProgCompilerGetProg(compiler)->nitems;
4894   if (!ParseIfCondition(compiler))
4895     return UDM_FALSE;
4896   /* Break the loop if the condition <expression> failed */
4897   if (UdmProgAddJmpWithComment(compiler->prg,
4898                                UDM_PROG_JE, 0, "to the FOR end"))
4899     return UDM_FALSE;
4900   if (!ParseTermOrError(compiler, UDM_LEX_SEMICOLON))
4901     return UDM_FALSE;
4902 
4903   /* Jump to the body <statement> */
4904   if (UdmProgAddJmpWithComment(compiler->prg,
4905                                UDM_PROG_JMP, 0, "to the FOR body statement"))
4906     return UDM_FALSE;
4907 
4908   /* Optional for-finalize <expression> */
4909   finalize_expression= UdmProgCompilerGetProg(compiler)->nitems;
4910   if (!(has_finalize_expression= UdmParseExpressionIgnoreResult(compiler)) &&
4911       UdmProgCompilerError(compiler))
4912     return UDM_FALSE;
4913   /* Go to the condition <expression> after for-finalize <expression> is done */
4914   if (UdmProgAddJmpWithComment(compiler->prg,
4915                                UDM_PROG_JMP, condition,
4916                                "to the FOR condition"))
4917     return UDM_FALSE;
4918   if (!ParseTermOrError(compiler, UDM_LEX_RP))
4919     return UDM_FALSE;
4920 
4921   /*
4922     Fix JMP after condition and before finalize_expression
4923     to the address of the body <statement>.
4924   */
4925   UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler),
4926                         finalize_expression - 1,
4927                         finalize_expression);
4928   backup_current_loop_continue= compiler->current_loop_continue;
4929   compiler->current_loop_continue= has_finalize_expression ?
4930                                       finalize_expression : condition;
4931   if (!ParseStatement(compiler))
4932     return UdmProgCompilerExpectedRule(compiler, "<statement>");
4933 
4934   /* Jump to for_finalize <expression> or to the condition <expression> */
4935   if (UdmProgAddJmpWithComment(compiler->prg, UDM_PROG_JMP,
4936                                has_finalize_expression ?
4937                                finalize_expression : condition,
4938                                has_finalize_expression ?
4939                                "to the FOR finalize expression" :
4940                                "to the FOR condition"))
4941     return UDM_FALSE;
4942 
4943   /* Fix the jump after the condition failure to the end of the loop */
4944   UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler),
4945                         condition,
4946                         UdmProgCompilerGetProg(compiler)->nitems - 1);
4947 
4948   compiler->current_loop_continue= backup_current_loop_continue;
4949   return UdmProgCompilerLeaveBlock(compiler);
4950 }
4951 
4952 
4953 /*
4954   do <statement> while ( <expression> ) ;
4955 */
4956 static udm_bool_t
ParseDoStatement(UDM_PROG_COMPILER * compiler)4957 ParseDoStatement(UDM_PROG_COMPILER *compiler)
4958 {
4959   size_t backup_current_loop_continue;
4960   if (!ParseTerm(compiler, UDM_LEX_DO))
4961     return UDM_FALSE;
4962 
4963   backup_current_loop_continue= compiler->current_loop_continue;
4964   compiler->current_loop_continue= UdmProgCompilerGetProg(compiler)->nitems;
4965 
4966   if (!ParseStatement(compiler))
4967     return UdmProgCompilerExpectedRule(compiler, "<statement>");
4968 
4969   if (!ParseTermOrError(compiler, UDM_LEX_WHILE))
4970     return UDM_FALSE;
4971 
4972   if (!ParseParenthesizedCondition(compiler))
4973     return UDM_FALSE;
4974 
4975   /* Jump to the beginning if the condition is true */
4976   if (UdmProgAddJmp(compiler->prg, UDM_PROG_JNE, compiler->current_loop_continue))
4977     return UDM_FALSE;
4978   /* Fix jumps for "break" statements */
4979   UdmProgFixJumpInRange(UdmProgCompilerGetProg(compiler),
4980                         compiler->current_loop_continue,
4981                         UdmProgCompilerGetProg(compiler)->nitems - 1);
4982   compiler->current_loop_continue= backup_current_loop_continue;
4983   return UDM_TRUE;
4984 }
4985 
4986 
4987 /*
4988 <iteration-statement> ::= while ( <expression> ) <statement>
4989                         | do <statement> while ( <expression> ) ;
4990                         | for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>
4991 */
4992 static udm_bool_t
ParseIterationStatement(UDM_PROG_COMPILER * compiler)4993 ParseIterationStatement(UDM_PROG_COMPILER *compiler)
4994 {
4995   return
4996     ParseWhileStatement(compiler) ||
4997     ParseDoStatement(compiler) ||
4998     ParseForStatement(compiler);
4999 }
5000 
5001 
5002 static udm_bool_t
UdmProgCompilerNotWithin(UDM_PROG_COMPILER * compiler,const char * item,const char * where)5003 UdmProgCompilerNotWithin(UDM_PROG_COMPILER *compiler, const char *item, const char *where)
5004 {
5005   udm_snprintf(compiler->errstr, sizeof(compiler->errstr),
5006                "'%s' not within a %s", item, where);
5007   return UDM_FALSE;
5008 }
5009 
5010 
5011 static udm_bool_t
ParseJumpStatement(UDM_PROG_COMPILER * compiler)5012 ParseJumpStatement(UDM_PROG_COMPILER *compiler)
5013 {
5014   if (ParseTerm(compiler, UDM_LEX_CONTINUE))
5015   {
5016     if (!compiler->current_loop_continue)
5017       return UdmProgCompilerNotWithin(compiler, "continue", "loop");
5018     return UDM_OK == UdmProgAddJmpWithComment(compiler->prg,
5019                                               UDM_PROG_JMP,
5020                                               compiler->current_loop_continue,
5021                                               "explicit continue");
5022   }
5023   if (ParseTerm(compiler, UDM_LEX_BREAK))
5024   {
5025     if (!compiler->current_loop_continue)
5026       return UdmProgCompilerNotWithin(compiler, "continue", "loop or switch");
5027     return UDM_OK == UdmProgAddJmpWithComment(compiler->prg,
5028                                               UDM_PROG_JMP, 0, "break");
5029   }
5030   return UDM_FALSE;
5031 }
5032 
5033 
5034 static udm_bool_t
UdmLexScannerScanUntilNativePIStart(UDM_PROG_COMPILER * compiler)5035 UdmLexScannerScanUntilNativePIStart(UDM_PROG_COMPILER *compiler)
5036 {
5037   const UDM_CONST_STR native= {UDM_CSTR_WITH_LEN("<?mnogosearch")};
5038   return UdmLexScannerScanUntil(&compiler->scanner, &native,
5039                                 UDM_LEX_TEXT, UDM_LEX_EOF);
5040 }
5041 
5042 
5043 /*
5044   Embedded text:
5045   ?>some text<?mnogosearch
5046 
5047 */
5048 static udm_bool_t
ParseEmbeddedTextStatement(UDM_PROG_COMPILER * compiler)5049 ParseEmbeddedTextStatement(UDM_PROG_COMPILER *compiler)
5050 {
5051   const char *start, *end;
5052   if (UdmProgCompilerLastTokenType(compiler) != UDM_LEX_QUESTION)
5053     return UDM_FALSE;
5054   if (UdmLexScannerCur(&compiler->scanner)[0] != '>')
5055     return UDM_FALSE;
5056   start= UdmLexScannerCur(&compiler->scanner) + 1; /* Skip '>' */
5057   UdmLexScannerScanUntilNativePIStart(compiler);
5058   end= compiler->scanner.token.token.end;
5059   /* Skip the newline that immediately follows the closing '?>' */
5060   if (start < end && *start == '\r')
5061     start++;
5062   if (start < end && *start == '\n')
5063     start++;
5064   UdmProgGenerateCoutText(compiler, start, end, UDM_FALSE);
5065   UdmProgCompilerScan(compiler);
5066   return UDM_TRUE;
5067 }
5068 
5069 
5070 static udm_bool_t ParseCompoundStatement(UDM_PROG_COMPILER *compilerarser);
5071 /*
5072 <statement> ::= <labeled-statement>
5073               | <expression-statement>
5074               | <compound-statement>
5075               | <selection-statement>
5076               | <iteration-statement>
5077               | <jump-statement>
5078 */
5079 static udm_bool_t
ParseStatement(UDM_PROG_COMPILER * compiler)5080 ParseStatement(UDM_PROG_COMPILER *compiler)
5081 {
5082   return ParseExpressionStatement(compiler) ||
5083          ParseSelectionStatement(compiler) ||
5084          ParseIterationStatement(compiler) ||
5085          ParseJumpStatement(compiler) ||
5086          ParseCompoundStatement(compiler) ||
5087          ParseEmbeddedTextStatement(compiler);
5088 }
5089 
5090 
5091 static udm_bool_t
ParseStatementList(UDM_PROG_COMPILER * compiler)5092 ParseStatementList(UDM_PROG_COMPILER *compiler)
5093 {
5094   for ( ; ; )
5095   {
5096     if (!ParseStatement(compiler))
5097     {
5098       if (UdmProgCompilerError(compiler))
5099         return UDM_FALSE;
5100       break;
5101     }
5102   }
5103   return UDM_TRUE;
5104 }
5105 
5106 
5107 /*
5108 <direct-declarator> ::= <identifier>
5109                       | ( <declarator> )
5110                       | <direct-declarator> [ {<constant-expression>}? ]
5111                       | <direct-declarator> ( <parameter-type-list> )
5112                       | <direct-declarator> ( {<identifier>}* )
5113 */
5114 static udm_bool_t
ParseDirectDeclarator(UDM_PROG_COMPILER * compiler,UDM_CONST_TOKEN * Var)5115 ParseDirectDeclarator(UDM_PROG_COMPILER *compiler, UDM_CONST_TOKEN *Var)
5116 {
5117   if (UdmProgCompilerLastTokenType(compiler) == UDM_LEX_IDENT)
5118     *Var= compiler->scanner.token.token;
5119   return ParseTerm(compiler, UDM_LEX_IDENT);
5120 }
5121 
5122 
5123 /*
5124 <declarator> ::= {<pointer>}? <direct-declarator>
5125 */
5126 static udm_bool_t
ParseDeclarator(UDM_PROG_COMPILER * compiler,UDM_CONST_TOKEN * Var)5127 ParseDeclarator(UDM_PROG_COMPILER *compiler,  UDM_CONST_TOKEN *Var)
5128 {
5129   return ParseDirectDeclarator(compiler, Var);
5130 }
5131 
5132 
5133 /*
5134   TODO:
5135   <initializer> ::= <assignment-expression>
5136                     | { <initializer-list> }
5137                     | { <initializer-list> , }
5138 */
5139 static udm_bool_t
ParseVarInitializer(UDM_PROG_COMPILER * compiler,const UDM_PROG_VAR * Var)5140 ParseVarInitializer(UDM_PROG_COMPILER *compiler, const UDM_PROG_VAR *Var)
5141 {
5142   return UdmParseAssignmentPart2(compiler, Var);
5143 }
5144 
5145 
5146 /*
5147 <init-declarator> ::= <declarator>
5148                     | <declarator> = <initializer>
5149 */
5150 static udm_bool_t
ParseInitDeclarator(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * ha)5151 ParseInitDeclarator(UDM_PROG_COMPILER *compiler, const UDM_VALUE_HANDLER *ha)
5152 {
5153   UDM_PROG_VAR Var;
5154   if (!ParseDeclarator(compiler, &Var.name))
5155     return UDM_FALSE;
5156 
5157   UdmProgStackVarInitAttributes(&Var, compiler, ha);
5158   if (!UdmGenerateDeclareNonInitializedVariable(compiler, &Var))
5159     return UDM_FALSE;
5160   if (!UdmGenerateConstructor(compiler, &Var))
5161     return UDM_FALSE;
5162   if (!ParseTerm(compiler, UDM_LEX_EQ))
5163     return UDM_TRUE;
5164   if (!ParseVarInitializer(compiler, &Var))
5165     return UdmProgCompilerExpectedRule(compiler, "<initializer>");
5166   return UDM_TRUE;
5167 }
5168 
5169 
5170 static udm_bool_t
ParseOptInitDeclaratorList(UDM_PROG_COMPILER * compiler,const UDM_VALUE_HANDLER * ha)5171 ParseOptInitDeclaratorList(UDM_PROG_COMPILER *compiler,
5172                            const UDM_VALUE_HANDLER *ha)
5173 {
5174   /*
5175     Check for an empty declaration,
5176     type not followed by an identifier name, e.g.:
5177     { int; }
5178   */
5179   if (!ParseInitDeclarator(compiler, ha))
5180     return UdmProgCompilerGenericError(compiler,
5181                                        "declaration does not declare anything");
5182   while (ParseTerm(compiler, UDM_LEX_COMMA))
5183   {
5184     if (!ParseInitDeclarator(compiler, ha))
5185       return UdmProgCompilerExpectedRule(compiler, "<init-declarator>");
5186   }
5187   return UDM_TRUE;
5188 }
5189 
5190 
5191 /*
5192 <declaration> ::=  {<declaration-specifier>}+ {<init-declarator>}*
5193 */
5194 static udm_bool_t
ParseDeclaration(UDM_PROG_COMPILER * compiler)5195 ParseDeclaration(UDM_PROG_COMPILER *compiler)
5196 {
5197   const UDM_VALUE_HANDLER *ha;
5198   if (!ParseDeclarationSpecifier(compiler, &ha))
5199     return UDM_FALSE;
5200   if (!ParseOptInitDeclaratorList(compiler, ha) &&
5201        UdmProgCompilerError(compiler))
5202     return UDM_FALSE;
5203   return UDM_TRUE;
5204 }
5205 
5206 
5207 static udm_bool_t
ParseOptDeclarationList(UDM_PROG_COMPILER * compiler)5208 ParseOptDeclarationList(UDM_PROG_COMPILER *compiler)
5209 {
5210   for ( ; ; )
5211   {
5212     if (!ParseDeclaration(compiler))
5213     {
5214       if (UdmProgCompilerError(compiler))
5215         return UDM_FALSE;
5216       break;
5217     }
5218     if (!ParseTermOrError(compiler, UDM_LEX_SEMICOLON))
5219       return UDM_FALSE;
5220   }
5221   return UDM_TRUE;
5222 }
5223 
5224 
5225 /*
5226 <compound-statement> ::= { {<declaration>}* {<statement>}* }
5227 */
5228 static udm_bool_t
ParseCompoundStatement(UDM_PROG_COMPILER * compiler)5229 ParseCompoundStatement(UDM_PROG_COMPILER *compiler)
5230 {
5231   if (!ParseLCB(compiler))
5232     return UDM_FALSE;
5233   if (!UdmProgCompilerEnterBlock(compiler))
5234     return UDM_FALSE;
5235   if (!ParseOptDeclarationList(compiler))
5236     return UDM_FALSE;
5237   if (!ParseStatementList(compiler))
5238     return !UdmProgCompilerError(compiler);
5239   if (!UdmProgCompilerLeaveBlock(compiler))
5240     return UDM_FALSE;
5241   return ParseTermOrError(compiler, UDM_LEX_RCB);
5242 }
5243 
5244 
5245 static udm_bool_t
ParsePI(UDM_PROG_COMPILER * compiler)5246 ParsePI(UDM_PROG_COMPILER *compiler)
5247 {
5248   if (!UdmProgCompilerEnterBlock(compiler))
5249     return UDM_FALSE;
5250   if (!ParseOptDeclarationList(compiler))
5251     return UDM_FALSE;
5252   if (!ParseStatementList(compiler))
5253     return UDM_FALSE;
5254   if (!UdmProgCompilerLeaveBlock(compiler))
5255     return UDM_FALSE;
5256   return ParseTermOrError(compiler, UDM_LEX_EOF);
5257 }
5258 
5259 
5260 udm_rc_t
UdmCompilePI(UDM_PROG_COMPILER * compiler,const UDM_CONST_STR * src)5261 UdmCompilePI(UDM_PROG_COMPILER *compiler, const UDM_CONST_STR *src)
5262 {
5263   udm_bool_t rc;
5264   UdmPIParserInit(compiler, src->str, src->length);
5265   UdmProgCompilerScan(compiler);
5266   if (!(rc= ParsePI(compiler)))
5267   {
5268     char tmp[124];
5269     size_t tmplen;
5270     tmplen= udm_snprintf(tmp, sizeof(tmp), "%s\n", compiler->errstr);
5271     UdmProgGenerateCoutText(compiler, tmp, tmp + tmplen, UDM_FALSE);
5272   }
5273   /*
5274   for (UdmProgCompilerScan(&parser);
5275        parser.scanner.token.type != UDM_LEX_UNKNOWN &&
5276        parser.scanner.token.type != UDM_LEX_EOF ;
5277        UdmProgCompilerScan(&parser))
5278   {
5279   }
5280   */
5281   UdmPIParserFree(compiler);
5282   return UDM_OK;
5283 }
5284 
5285 
5286 static udm_bool_t
UdmProgCompilerScanPrefixText(UDM_PROG_COMPILER * compiler)5287 UdmProgCompilerScanPrefixText(UDM_PROG_COMPILER *compiler)
5288 {
5289   if (!UdmLexScannerScanUntilNativePIStart(compiler))
5290     return UDM_TRUE;
5291   UdmProgGenerateCoutText(compiler,
5292                           compiler->scanner.token.token.str,
5293                           compiler->scanner.token.token.end,
5294                           UDM_FALSE);
5295   compiler->pi_count++;
5296   UdmProgCompilerScan(compiler); /* For look-ahead */
5297   return UDM_TRUE;
5298 }
5299 
5300 
5301 static udm_bool_t
ParsePIProgram(UDM_PROG_COMPILER * compiler)5302 ParsePIProgram(UDM_PROG_COMPILER *compiler)
5303 {
5304   if (!UdmProgCompilerEnterBlock(compiler))
5305     return UDM_FALSE;
5306   if (!UdmProgCompilerScanPrefixText(compiler))
5307     return UDM_FALSE;
5308   if (!ParseOptDeclarationList(compiler))
5309     return UDM_FALSE;
5310   if (!ParseStatementList(compiler))
5311     return UDM_FALSE;
5312   if (!UdmProgCompilerLeaveBlock(compiler))
5313     return UDM_FALSE;
5314   return ParseTermOrError(compiler, UDM_LEX_EOF);
5315 }
5316 
5317 
5318 udm_rc_t
UdmCompilePIProgram(UDM_PROG_COMPILER * compiler,const UDM_CONST_STR * src)5319 UdmCompilePIProgram(UDM_PROG_COMPILER *compiler, const UDM_CONST_STR *src)
5320 {
5321   udm_bool_t rc;
5322   UdmPIParserInit(compiler, src->str, src->length);
5323   if (!(rc= ParsePIProgram(compiler)))
5324   {
5325     char tmp[124];
5326     size_t tmplen;
5327     tmplen= udm_snprintf(tmp, sizeof(tmp), "%s\n", compiler->errstr);
5328     UdmProgGenerateCoutText(compiler, tmp, tmp + tmplen, UDM_FALSE);
5329   }
5330   UdmPIParserFree(compiler);
5331   return rc == UDM_TRUE ? UDM_OK : UDM_ERROR;
5332 }
5333