expression fix for gcc4.0
[mala.git] / std / std_parsers.c
blob2c09a157ca38643638f48590c36cd2a867726c54
1 /*
2 std_parsers.c - MaLa standard module parsers
4 Copyright (C) 2005, Christian Thaeter <chth@gmx.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, contact me.
20 #include <stdio.h>
21 #include <string.h>
23 #include "mala.h"
24 #include "std.h"
26 static size_t
27 reserve_string (char ** s, size_t actual, size_t needed);
29 static void
30 mala_macrocheck_list (MalaStringList list, int * max_arg, int argt[10]);
32 static void
33 mala_macrocheck_string (MalaString string, int * max_arg, int argt[10]);
36 int
37 mala_substitute_parser (MalaEngine eng,
38 MalaStringListNode_ref pptr,
39 void * data)
41 if (!mala_stringlist_after_new (&eng->program, *pptr, (MalaString) data))
42 return MALA_EALLOC;
44 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
46 return MALA_SUCCESS;
49 int
50 mala_expand_parser (MalaEngine eng,
51 MalaStringListNode_ref pptr,
52 void * data)
54 MalaStringListNode itr;
55 MalaStringListNode end;
57 end = mala_stringlistnode_next (*pptr);
59 for (itr = mala_stringlist_tail ((MalaStringList) data);
60 !mala_stringlist_is_end ((MalaStringList) data, itr);
61 mala_stringlistnode_rev (&itr))
63 if (!mala_stringlist_after_new (&eng->program, *pptr,
64 mala_stringlistnode_string (itr)))
65 goto ealloc_node;
68 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
70 return MALA_SUCCESS;
72 ealloc_node:
73 /* remove already added things */
74 for (itr = mala_stringlistnode_next (*pptr);
75 itr != end;
76 mala_stringlist_elem_delete_fwd (&eng->program, &itr));
78 return MALA_EALLOC;
82 int
83 mala_macro_parser (MalaEngine eng,
84 MalaStringListNode_ref pptr,
85 void * data)
87 MalaStringListNode itr;
88 MalaStringListNode last = NULL;
89 MalaStringList list;
90 const char* c;
91 int i;
92 int max_arg = 0;
93 int argt[10] = {0};
94 char *p;
95 MalaString args[10];
96 MalaString str = NULL;
98 // scan how much args are needed
99 mala_macrocheck_list ((MalaStringList) data, &max_arg, argt);
101 // evaluate args, fill arg-array
102 args[0] = mala_stringlistnode_string (*pptr);
104 for (i = 1; i <= max_arg; ++i)
106 if (!(last = mala_engine_arg_eval (eng, pptr, i, argt[i] == 1 ? -1 : 0, NULL))
107 || eng->state > MALA_EFAULT)
108 return eng->state;
110 args[i] = mala_stringlistnode_string (last);
113 // build list with substitutions
114 list = mala_stringlist_new ();
115 if (!list)
116 goto ealloc_list;
118 for (itr = mala_stringlist_head ((MalaStringList) data);
119 !mala_stringlist_is_end ((MalaStringList) data, itr);
120 mala_stringlistnode_fwd (&itr))
122 size_t size = 64;
123 if (!(p = malloc (size)))
124 goto ealloc_cstr;
126 for (c = mala_string_cstr (mala_stringlistnode_string (itr)), i = 0; *c; ++c,++i)
128 if (*c == '%')
130 ++c;
131 if (*c == '%')
133 // %% -> %
134 goto normal_char;
136 else if (*c >= '0' && *c <= '9')
138 // %0..%9
139 if (size <= i+mala_string_length (args[*c-'0'])
140 && !(size = reserve_string (&p,
141 size,
142 1 + i + mala_string_length (args[*c-'0']))))
143 goto ealloc_reserve;
144 strcpy(p+i, mala_string_cstr (args[*c-'0']));
145 i += (mala_string_length (args[*c-'0']) - 1);
147 else if (*c == '-')
149 ++c;
150 if (*c >= '0' && *c <= '9')
152 // %0..%9
153 if (size <= i+mala_string_length (args[*c-'0'])
154 && !(size = reserve_string (&p,
155 size,
156 1 + i +
157 mala_string_length (args[*c-'0']))))
158 goto ealloc_reserve;
159 strcpy(p+i, mala_string_cstr (args[*c-'0']));
160 i += (mala_string_length (args[*c-'0']) - 1);
164 else
166 normal_char:
167 // normal char
168 if (size <= (size_t) i && !(size = reserve_string (&p, size, (size_t) i+1)))
169 goto ealloc_reserve;
170 p[i] = *c;
174 p[i] = '\0';
176 char* ptmp;
177 if (!(ptmp = realloc (p, size)))
178 goto ealloc_realloc;
180 str = mala_string_new_cstr_attach (ptmp, &eng->words); /*TODO try without bucket?*/
181 if (!str)
182 goto ealloc_string;
184 if (!mala_stringlist_tail_new (list, str))
185 goto ealloc_node;
187 mala_string_free (str);
191 // insert list
192 for (itr = mala_stringlist_tail (list);
193 !mala_stringlist_is_end (list, itr);
194 mala_stringlistnode_rev (&itr))
196 if (!mala_stringlist_after_new (&eng->program, last,
197 mala_stringlistnode_string (itr)))
198 goto ealloc_program;
201 // cleanup
202 mala_stringlist_free (list);
204 mala_stringlist_elem_delete_fwd_n (&eng->program, pptr, max_arg + 1);
206 return MALA_SUCCESS;
208 ealloc_program:
209 ealloc_node:
210 mala_string_free (str);
211 ealloc_string:
212 ealloc_realloc:
213 ealloc_reserve:
214 free (p);
215 ealloc_cstr:
216 mala_stringlist_free (list);
217 ealloc_list:
218 return MALA_EALLOC;
222 mala_null_parser (MalaEngine eng,
223 MalaStringListNode_ref pptr,
224 void * data)
226 (void) data;
227 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
228 return eng->state;
232 mala_literal_parser (MalaEngine eng,
233 MalaStringListNode_ref pptr,
234 void * data)
236 (void) data;
238 if (mala_stringlist_is_tail (&eng->program, *pptr))
239 return mala_engine_exception (eng, pptr, *pptr,
240 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
242 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
243 return MALA_LITERAL;
247 mala_not_parser (MalaEngine eng,
248 MalaStringListNode_ref pptr,
249 void * data)
251 (void) data;
253 if (mala_stringlist_is_tail (&eng->program, *pptr))
254 return mala_engine_exception (eng, pptr, *pptr,
255 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
257 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
258 eng->negated = !eng->negated;
259 return MALA_SUCCESS;
263 mala_begin_parser (MalaEngine eng,
264 MalaStringListNode_ref pptr,
265 void * data)
267 MalaStringListNode itr;
268 MalaStringListNode end;
269 MalaStringList list;
270 unsigned depth = 1;
271 MalaString name = NULL;
273 (void) data;
275 if (mala_stringlist_is_tail (&eng->program, *pptr))
276 return mala_engine_exception (eng, pptr, *pptr,
277 eng->common_string[MALA_STRING_ERROR_MISSING_END]);
279 // find matching --END
280 for (end = mala_stringlistnode_next (*pptr);
281 !mala_stringlist_is_end (&eng->program, end);
282 mala_stringlistnode_fwd (&end))
284 if (mala_string_same(mala_stringlistnode_string (end),
285 eng->common_string[MALA_STRING_BEGIN]))
286 ++depth;
287 else if (mala_string_same(mala_stringlistnode_string (end),
288 eng->common_string[MALA_STRING_END]))
289 --depth;
290 if (!depth)
291 break;
294 if (depth)
295 return mala_engine_exception (eng, pptr, mala_stringlistnode_prev (end),
296 eng->common_string[MALA_STRING_ERROR_MISSING_END]);
298 list = mala_stringlist_new ();
299 if (!list)
300 return MALA_EALLOC;
302 // copy the block content to list
303 for (itr = mala_stringlistnode_next (*pptr); itr != end; mala_stringlistnode_fwd (&itr))
304 if (!mala_stringlist_tail_new (list, mala_stringlistnode_string (itr)))
305 goto ealloc_node;
307 // allocate new block name
308 do {
309 mala_string_free (name);
310 name = mala_string_new_print (&eng->words, "--BLOCK_%08X", ++eng->blockcnt);
311 if (!name)
312 goto ealloc_name;
313 } while (mala_actiondesc_top ((MalaActionDesc)mala_string_user_get (name)));
315 if (MALA_SUCCESS != mala_engine_add_action (eng, name, list,
316 mala_block_parser,
317 (MalaDataFactory)mala_stringlist_factory,
318 NULL))
319 goto ealloc_action;
321 // insert new --BLOCK_... in program
322 mala_stringlist_after_new (&eng->program, end, name);
323 mala_string_free (name);
324 // and remove its definition
325 while (*pptr != end)
326 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
327 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
329 return MALA_DELAY;
331 ealloc_action:
332 mala_string_free (name);
333 ealloc_name:
334 ealloc_node:
335 mala_stringlist_free (list);
336 return MALA_EALLOC;
340 mala_block_parser (MalaEngine eng,
341 MalaStringListNode_ref pptr,
342 void * data)
344 (void) data;
346 mala_actiondesc_pop_delete (mala_stringlistnode_user_get (*pptr));
348 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
349 return MALA_SUCCESS;
353 mala_macrodelete_parser (MalaEngine eng,
354 MalaStringListNode_ref pptr,
355 void * data)
357 (void) data;
359 mala_engine_arg_eval (eng, pptr, 1, -1, NULL);
361 if (mala_stringlist_is_tail (&eng->program, *pptr))
362 return mala_engine_exception (eng, pptr, *pptr,
363 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
365 mala_actiondesc_pop_delete (mala_stringlistnode_user_get (mala_stringlistnode_next (*pptr)));
367 mala_stringlist_elem_delete_fwd_n (&eng->program, pptr, 2);
368 return MALA_SUCCESS;
372 mala_exception_parser (MalaEngine eng,
373 MalaStringListNode_ref pptr,
374 void * data)
376 // TODO needs better semantics --EXCEPTION n error -> --ERROR-error 1 .. n --HERE
378 (void) data;
380 mala_engine_arg_eval (eng, pptr, 1, -1, NULL);
382 if (mala_stringlist_is_tail (&eng->program, *pptr))
383 return mala_engine_exception (eng, pptr, *pptr,
384 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
386 if (eng->state > MALA_EFAULT)
387 return eng->state;
389 MalaString ex = mala_string_new_print (&eng->words, "--ERROR-%s",
390 mala_stringlistnode_cstr (mala_stringlistnode_next (*pptr)));
392 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
393 int state = mala_engine_exception (eng, pptr, *pptr, ex);
394 mala_stringlist_elem_delete (&eng->program, mala_stringlistnode_next (*pptr));
396 mala_string_free (ex);
398 return state;
402 mala_end_parser (MalaEngine eng,
403 MalaStringListNode_ref pptr,
404 void * data)
406 (void) data;
408 return mala_engine_exception (eng, pptr, *pptr,
409 eng->common_string[MALA_STRING_ERROR_END_WITHOUT_BEGIN]);
412 static void
413 mala_macrocheck_list (MalaStringList list, int * max_arg, int argt[10])
415 MalaStringListNode itr;
416 for (itr = mala_stringlist_head (list);
417 !mala_stringlist_is_end (list, itr);
418 mala_stringlistnode_fwd (&itr))
420 mala_macrocheck_string (mala_stringlistnode_string (itr), max_arg, argt);
421 if (*max_arg == -1)
422 return;
426 static void
427 mala_macrocheck_string (MalaString string, int * max_arg, int argt[10])
429 const char * c;
430 for (c = mala_string_cstr (string); *c; ++c)
432 // "foo%1%-2"
433 if (*c == '%')
435 // %
436 ++c;
437 if (*c == '%')
438 // %%
439 continue;
440 if (*c == '-')
442 // %-
443 ++c;
444 if (*c >= '0' && *c <= '9')
446 // %-0 .. %-9
447 if (argt[*c - '0'] == 1)
448 goto esyntax;
449 if (*c > (char) *max_arg + '0')
450 *max_arg = *c - '0';
451 argt[*c - '0'] = -1;
453 else
454 goto esyntax;
456 else if (*c >= '0' && *c <= '9')
458 // %0 .. %9
459 if (argt[*c - '0'] == -1)
460 goto esyntax;
461 if (*c > (char) *max_arg + '0')
462 *max_arg = *c - '0';
463 argt[*c - '0'] = 1;
465 else
466 goto esyntax;
469 return;
471 esyntax:
472 *max_arg = -1;
473 return;
477 mala_macrodef_parser (MalaEngine eng,
478 MalaStringListNode_ref pptr,
479 void * data)
481 int i;
482 MalaStringListNode itr;
483 MalaStringListNode arg[2];
484 MalaString name;
485 MalaAction act;
487 (void) data;
490 // evaluate both args
491 if (!mala_engine_arg_eval (eng, pptr, 1, -1, NULL))
492 return eng->state;
493 if (!mala_engine_arg_eval (eng, pptr, 2, -1, NULL))
494 return eng->state;
496 // test if 2 arguments left and assign them to arg[], else error
497 for (i = 0, itr = *pptr; i<2; ++i, mala_stringlistnode_fwd(&itr))
499 if (mala_stringlist_is_tail (&eng->program, itr))
500 return mala_engine_exception (eng, pptr, itr,
501 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
502 arg[i] = mala_stringlistnode_next (itr);
505 // if name is a block then error
506 name = mala_stringlistnode_string (arg[0]);
507 act = mala_actiondesc_top ((MalaActionDesc) mala_string_user_get (name));
508 if (act && act->parser == mala_block_parser)
509 return mala_engine_exception (eng, pptr, arg[0],
510 eng->common_string[MALA_STRING_ERROR_BLOCK_NOT_ALLOWED]);
512 //expansion check and optimize block
513 act = mala_actiondesc_top ((MalaActionDesc) mala_stringlistnode_user_get (arg[1]));
514 if (act && act->factory == (MalaDataFactory) mala_stringlist_factory)
516 int max_arg = 0;
517 int argt[10] = {0};
518 mala_macrocheck_list ((MalaStringList) act->data, &max_arg, argt);
519 // convert block to expansion
520 if (max_arg > 0)
522 //macro
523 MalaActionDesc desc;
524 desc = mala_actiondesc_ensure (name);
525 if (!desc)
526 return MALA_EALLOC;
528 act = mala_actiondesc_pop ((MalaActionDesc) mala_stringlistnode_user_get (arg[1]));
529 act->name = name;
530 act->parser = mala_macro_parser;
531 mala_actiondesc_push_action (desc, act);
533 else if (mala_stringlist_is_single ((MalaStringList) act->data))
535 //substitute
536 MalaString subst;
537 subst = mala_stringlist_head_string_copy ((MalaStringList) act->data);
539 if (MALA_SUCCESS != mala_engine_add_action (eng, name, subst,
540 mala_substitute_parser,
541 (MalaDataFactory) mala_string_factory,
542 NULL))
543 return MALA_EALLOC;
545 mala_action_free(act);
547 else if (max_arg == 0)
549 //expand
550 MalaActionDesc desc;
551 desc = mala_actiondesc_ensure (name);
552 if (!desc)
553 return MALA_EALLOC;
555 act = mala_actiondesc_pop ((MalaActionDesc) mala_stringlistnode_user_get (arg[1]));
556 act->name = name;
557 act->parser = mala_expand_parser;
558 mala_actiondesc_push_action (desc, act);
560 else
561 return mala_engine_exception (eng, pptr, arg[1],
562 eng->common_string[MALA_STRING_ERROR_PARAMETER_SYNTAX]);
564 else //if (act && act->factory == (MalaDataFactory)mala_string_factory)
566 // single word
567 int max_arg = 0;
568 int argt[10] = {0};
569 mala_macrocheck_string (mala_stringlistnode_string (arg[1]), &max_arg, argt);
570 if (max_arg == 0)
572 // substitute
573 if (MALA_SUCCESS != mala_engine_add_action (eng, name,
574 mala_stringlistnode_string_copy (arg[1]),
575 mala_substitute_parser,
576 (MalaDataFactory) mala_string_factory,
577 NULL))
578 return MALA_EALLOC;
580 else if (max_arg > 0)
582 // macro
583 MalaStringList list;
585 list = mala_stringlist_new ();
586 if (!list)
587 return MALA_EALLOC;
589 mala_stringlist_tail_new (list, mala_stringlistnode_string (arg[1]));
591 if (MALA_SUCCESS != mala_engine_add_action (eng, name, list,
592 mala_macro_parser,
593 (MalaDataFactory) mala_stringlist_factory,
594 NULL))
595 return MALA_EALLOC;
597 else // syntax error
598 return mala_engine_exception (eng, pptr, arg[1],
599 eng->common_string[MALA_STRING_ERROR_PARAMETER_SYNTAX]);
602 mala_stringlist_elem_delete_fwd_n (&eng->program, pptr, 3);
603 return MALA_SUCCESS;
607 mala_foreach_word_parser (MalaEngine eng,
608 MalaStringListNode_ref pptr,
609 void * data)
611 MalaAction act;
612 MalaStringListNode first;
613 MalaStringListNode second;
614 MalaStringListNode last;
615 MalaStringListNode itr;
616 (void) data;
618 first = mala_engine_arg_eval (eng, pptr, 1, -1, NULL);
619 if (!first)
620 return eng->state;
621 act = mala_actiondesc_top ((MalaActionDesc) mala_stringlistnode_user_get (first));
622 // TODO allow blocks as first arg (define macro and delete it at later)
623 if (act && act->parser == mala_block_parser)
624 return mala_engine_exception (eng, pptr, first,
625 eng->common_string[MALA_STRING_ERROR_BLOCK_NOT_ALLOWED]);
627 second = mala_engine_arg_eval (eng, pptr, 2, -1, (MalaDataFactory) mala_stringlist_factory);
628 if (!second)
629 return eng->state;
631 last = mala_stringlistnode_next (second);
633 act = mala_actiondesc_top ((MalaActionDesc) mala_stringlistnode_user_get (second));
635 // expand second
636 if (eng->state != MALA_LITERAL)
637 for (itr = mala_stringlist_tail ((MalaStringList) act->data);
638 !mala_stringlist_is_end ((MalaStringList) act->data, itr);
639 mala_stringlistnode_rev (&itr))
641 if (!mala_stringlist_after_new (&eng->program,
642 second,
643 mala_stringlistnode_string (itr)))
644 goto ealloc_node;
645 if (!mala_stringlist_after_new (&eng->program,
646 second,
647 mala_stringlistnode_string (first)))
648 goto ealloc_node;
650 else
652 if (!mala_stringlist_after_new (&eng->program,
653 second,
654 mala_stringlistnode_string (second)))
655 goto ealloc_node;
656 if (!mala_stringlist_after_new (&eng->program,
657 second,
658 mala_stringlistnode_string (first)))
659 goto ealloc_node;
663 // was a block? delete it
664 if (act && act->parser == mala_block_parser)
665 mala_actiondesc_pop_delete (mala_stringlistnode_user_get (second));
667 mala_stringlist_elem_delete_fwd_n (&eng->program, pptr, 3);
669 return MALA_SUCCESS;
670 ealloc_node:
671 for (itr = mala_stringlistnode_next (second);
672 itr != last;
673 mala_stringlistnode_fwd (&itr))
675 mala_stringlist_elem_delete (&eng->program, itr);
678 return MALA_EALLOC; // TODO exception instead (needs pools, no allocation possible further)
685 realloc a string to at least needed size
686 return the amount really reserved or 0 on error
688 static size_t
689 reserve_string (char ** s, size_t actual, size_t needed)
691 size_t n;
692 char * r;
694 for (n = actual>64?actual:64; n <= needed; n += (n>>1)); /*n = n * 1.5*/
696 r = realloc (*s, n);
697 if (!r)
699 /* that was to much, try conservatively */
700 r = realloc (*s, n = needed);
701 if (!r)
702 return 0;
704 *s = r;
705 return n;
710 // Local Variables:
711 // mode: C
712 // c-file-style: "gnu"
713 // End:
714 // arch-tag: 687e1195-8aad-4425-983d-9767a25c3793
715 // end_of_file