foreach_word_parser
[mala.git] / std / std_parsers.c
blob2ef5b46280b14d2eb89b2b0cd0d902faec7d092c
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_stringlist_next (*pptr);
59 for (itr = mala_stringlist_tail ((MalaStringList) data);
60 !mala_stringlist_is_end ((MalaStringList) data, itr);
61 mala_stringlist_rev (&itr))
63 if (!mala_stringlist_after_new (&eng->program, *pptr, itr->string))
64 goto ealloc_node;
67 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
69 return MALA_SUCCESS;
71 ealloc_node:
72 /* remove already added things */
73 for (itr = mala_stringlist_next (*pptr);
74 itr != end;
75 mala_stringlist_elem_delete_fwd (&eng->program, &itr));
77 return MALA_EALLOC;
81 int
82 mala_macro_parser (MalaEngine eng,
83 MalaStringListNode_ref pptr,
84 void * data)
86 MalaStringListNode itr;
87 MalaStringListNode last = NULL;
88 MalaStringList list;
89 const char* c;
90 int i;
91 int max_arg = 0;
92 int argt[10] = {0};
93 char *p;
94 MalaString args[10];
95 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] = (*pptr)->string;
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] = last->string;
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_stringlist_fwd (&itr))
122 size_t size = 64;
123 if (!(p = malloc (size)))
124 goto ealloc_cstr;
126 for (c = mala_string_cstr (itr->string), 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_stringlist_rev (&itr))
196 if (!mala_stringlist_after_new (&eng->program, last, itr->string))
197 goto ealloc_program;
200 // cleanup
201 mala_stringlist_free (list);
204 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
205 while (max_arg--);
207 return MALA_SUCCESS;
209 ealloc_program:
210 ealloc_node:
211 mala_string_free (str);
212 ealloc_string:
213 ealloc_realloc:
214 ealloc_reserve:
215 free (p);
216 ealloc_cstr:
217 mala_stringlist_free (list);
218 ealloc_list:
219 return MALA_EALLOC;
223 mala_null_parser (MalaEngine eng,
224 MalaStringListNode_ref pptr,
225 void * data)
227 (void) data;
228 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
229 return eng->state;
233 mala_printl_parser (MalaEngine eng,
234 MalaStringListNode_ref pptr,
235 void * data)
237 (void) data;
239 mala_engine_arg_eval (eng, pptr, 1, -1, NULL);
241 if (mala_stringlist_is_tail (&eng->program, *pptr))
242 return mala_engine_exception (eng, pptr, *pptr,
243 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
245 if (eng->state > MALA_EFAULT)
246 return eng->state;
248 // TODO print blocks ?
250 printf("%s\n",mala_string_cstr (mala_stringlist_next (*pptr)->string));
252 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
253 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
254 return MALA_SUCCESS;
258 mala_print_parser (MalaEngine eng,
259 MalaStringListNode_ref pptr,
260 void * data)
262 (void) data;
264 mala_engine_arg_eval (eng, pptr, 1, -1, NULL);
266 if (mala_stringlist_is_tail (&eng->program, *pptr))
267 return mala_engine_exception (eng, pptr, *pptr,
268 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
270 if (eng->state > MALA_EFAULT)
271 return eng->state;
273 // TODO print blocks ?
275 printf("%s",mala_string_cstr (mala_stringlist_next (*pptr)->string));
277 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
278 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
279 return MALA_SUCCESS;
283 mala_literal_parser (MalaEngine eng,
284 MalaStringListNode_ref pptr,
285 void * data)
287 (void) data;
289 if (eng->state > MALA_EFAULT)
290 return eng->state;
292 if (mala_stringlist_is_tail (&eng->program, *pptr))
293 return mala_engine_exception (eng, pptr, *pptr,
294 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
296 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
297 return MALA_LITERAL;
301 mala_not_parser (MalaEngine eng,
302 MalaStringListNode_ref pptr,
303 void * data)
305 (void) data;
307 if (eng->state > MALA_EFAULT)
308 return eng->state;
310 if (mala_stringlist_is_tail (&eng->program, *pptr))
311 return mala_engine_exception (eng, pptr, *pptr,
312 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
314 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
315 eng->negated = !eng->negated;
316 return MALA_SUCCESS;
320 mala_begin_parser (MalaEngine eng,
321 MalaStringListNode_ref pptr,
322 void * data)
324 MalaStringListNode itr;
325 MalaStringListNode end;
326 MalaStringList list;
327 unsigned depth = 1;
328 MalaString name = NULL;
330 (void) data;
332 if (mala_stringlist_is_tail (&eng->program, *pptr))
333 return mala_engine_exception (eng, pptr, *pptr,
334 eng->common_string[MALA_STRING_ERROR_MISSING_END]);
336 // find matching --END
337 for (end = mala_stringlist_next (*pptr);
338 !mala_stringlist_is_end (&eng->program, end);
339 mala_stringlist_fwd (&end))
341 if (mala_string_same(end->string, eng->common_string[MALA_STRING_BEGIN]))
342 ++depth;
343 else if (mala_string_same(end->string, eng->common_string[MALA_STRING_END]))
344 --depth;
345 if (!depth)
346 break;
349 if (depth)
350 return mala_engine_exception (eng, pptr, mala_stringlist_prev (end),
351 eng->common_string[MALA_STRING_ERROR_MISSING_END]);
353 list = mala_stringlist_new ();
354 if (!list)
355 return MALA_EALLOC;
357 // copy the block content to list
358 for (itr = mala_stringlist_next (*pptr); itr != end; mala_stringlist_fwd (&itr))
359 if (!mala_stringlist_tail_new (list, itr->string))
360 goto ealloc_node;
362 // allocate new block name
363 do {
364 mala_string_free (name);
365 name = mala_string_new_print (&eng->words, "--BLOCK_%08X", ++eng->blockcnt);
366 if (!name)
367 goto ealloc_name;
368 } while (mala_actiondesc_top ((MalaActionDesc)mala_string_user_get (name)));
370 if (MALA_SUCCESS != mala_engine_add_action (eng, name, list,
371 mala_block_parser,
372 (MalaDataFactory)mala_stringlist_factory,
373 NULL))
374 goto ealloc_action;
376 // insert new --BLOCK_... in program
377 mala_stringlist_after_new (&eng->program, end, name);
378 mala_string_free (name);
379 // and remove its definition
380 while (*pptr != end)
381 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
382 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
384 return MALA_DELAY;
386 ealloc_action:
387 mala_string_free (name);
388 ealloc_name:
389 ealloc_node:
390 mala_stringlist_free (list);
391 return MALA_EALLOC;
395 mala_block_parser (MalaEngine eng,
396 MalaStringListNode_ref pptr,
397 void * data)
399 (void) data;
401 if (eng->state > MALA_EFAULT)
402 return eng->state;
404 mala_actiondesc_pop_delete (mala_string_user_get ((*pptr)->string));
406 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
407 return MALA_SUCCESS;
411 mala_macrodelete_parser (MalaEngine eng,
412 MalaStringListNode_ref pptr,
413 void * data)
415 (void) data;
417 if (eng->state > MALA_EFAULT)
418 return eng->state;
420 mala_engine_arg_eval (eng, pptr, 1, -1, NULL);
422 if (mala_stringlist_is_tail (&eng->program, *pptr))
423 return mala_engine_exception (eng, pptr, *pptr,
424 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
426 mala_actiondesc_pop_delete (mala_string_user_get (mala_stringlist_next (*pptr)->string));
428 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
429 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
430 return MALA_SUCCESS;
434 mala_exception_parser (MalaEngine eng,
435 MalaStringListNode_ref pptr,
436 void * data)
438 // TODO needs better semantics --EXCEPTION n error -> --ERROR-error 1 .. n --HERE
440 (void) data;
442 mala_engine_arg_eval (eng, pptr, 1, -1, NULL);
444 if (mala_stringlist_is_tail (&eng->program, *pptr))
445 return mala_engine_exception (eng, pptr, *pptr,
446 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
448 if (eng->state > MALA_EFAULT)
449 return eng->state;
451 MalaString ex = mala_string_new_print (&eng->words, "--ERROR-%s",
452 mala_string_cstr (mala_stringlist_next (*pptr)->string));
454 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
455 int state = mala_engine_exception (eng, pptr, *pptr, ex);
456 mala_stringlist_elem_delete (&eng->program, mala_stringlist_next (*pptr));
458 mala_string_free (ex);
460 return state;
464 mala_end_parser (MalaEngine eng,
465 MalaStringListNode_ref pptr,
466 void * data)
468 (void) data;
470 return mala_engine_exception (eng, pptr, *pptr,
471 eng->common_string[MALA_STRING_ERROR_END_WITHOUT_BEGIN]);
474 static void
475 mala_macrocheck_list (MalaStringList list, int * max_arg, int argt[10])
477 MalaStringListNode itr;
478 for (itr = mala_stringlist_head (list);
479 !mala_stringlist_is_end (list, itr);
480 mala_stringlist_fwd (&itr))
482 mala_macrocheck_string (itr->string, max_arg, argt);
483 if (*max_arg == -1)
484 return;
488 static void
489 mala_macrocheck_string (MalaString string, int * max_arg, int argt[10])
491 const char * c;
492 for (c = mala_string_cstr (string); *c; ++c)
494 // "foo%1%-2"
495 if (*c == '%')
497 // %
498 ++c;
499 if (*c == '%')
500 // %%
501 continue;
502 if (*c == '-')
504 // %-
505 ++c;
506 if (*c >= '0' && *c <= '9')
508 // %-0 .. %-9
509 if (argt[*c - '0'] == 1)
510 goto esyntax;
511 if (*c > (char) *max_arg + '0')
512 *max_arg = *c - '0';
513 argt[*c - '0'] = -1;
515 else
516 goto esyntax;
518 else if (*c >= '0' && *c <= '9')
520 // %0 .. %9
521 if (argt[*c - '0'] == -1)
522 goto esyntax;
523 if (*c > (char) *max_arg + '0')
524 *max_arg = *c - '0';
525 argt[*c - '0'] = 1;
527 else
528 goto esyntax;
531 return;
533 esyntax:
534 *max_arg = -1;
535 return;
539 mala_macrodef_parser (MalaEngine eng,
540 MalaStringListNode_ref pptr,
541 void * data)
543 int i;
544 MalaStringListNode itr;
545 MalaStringListNode arg[2];
546 MalaString name;
547 MalaAction act;
549 (void) data;
552 // evaluate both args
553 if (!mala_engine_arg_eval (eng, pptr, 1, -1, NULL))
554 return eng->state;
555 if (!mala_engine_arg_eval (eng, pptr, 2, -1, NULL))
556 return eng->state;
558 // test if 2 arguments left and assign them to arg[], else error
559 for (i = 0, itr = *pptr; i<2; ++i, mala_stringlist_fwd(&itr))
561 if (mala_stringlist_is_tail (&eng->program, itr))
562 return mala_engine_exception (eng, pptr, itr,
563 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
564 arg[i] = mala_stringlist_next (itr);
567 // if name is a block then error
568 name = arg[0]->string;
569 act = mala_actiondesc_top ((MalaActionDesc) mala_string_user_get (name));
570 if (act && act->parser == mala_block_parser)
571 return mala_engine_exception (eng, pptr, arg[0],
572 eng->common_string[MALA_STRING_ERROR_BLOCK_NOT_ALLOWED]);
574 //expansion check and optimize block
575 act = mala_actiondesc_top ((MalaActionDesc) mala_string_user_get (arg[1]->string));
576 if (act && act->factory == (MalaDataFactory) mala_stringlist_factory)
578 int max_arg = 0;
579 int argt[10] = {0};
580 mala_macrocheck_list ((MalaStringList) act->data, &max_arg, argt);
581 // convert block to expansion
582 if (max_arg > 0)
584 //macro
585 MalaActionDesc desc;
586 desc = mala_actiondesc_ensure (name);
587 if (!desc)
588 return MALA_EALLOC;
590 act = mala_actiondesc_pop ((MalaActionDesc) mala_string_user_get (arg[1]->string));
591 act->name = name;
592 act->parser = mala_macro_parser;
593 mala_actiondesc_push_action (desc, act);
595 else if (mala_stringlist_is_single ((MalaStringList) act->data))
597 //substitute
598 MalaString subst;
599 subst = mala_string_copy (mala_stringlist_head((MalaStringList) act->data)->string);
601 if (MALA_SUCCESS != mala_engine_add_action (eng, name, subst,
602 mala_substitute_parser,
603 (MalaDataFactory) mala_string_factory,
604 NULL))
605 return MALA_EALLOC;
607 mala_action_free(act);
609 else if (max_arg == 0)
611 //expand
612 MalaActionDesc desc;
613 desc = mala_actiondesc_ensure (name);
614 if (!desc)
615 return MALA_EALLOC;
617 act = mala_actiondesc_pop ((MalaActionDesc) mala_string_user_get (arg[1]->string));
618 act->name = name;
619 act->parser = mala_expand_parser;
620 mala_actiondesc_push_action (desc, act);
622 else
623 return mala_engine_exception (eng, pptr, arg[1],
624 eng->common_string[MALA_STRING_ERROR_PARAMETER_SYNTAX]);
626 else //if (act && act->factory == (MalaDataFactory)mala_string_factory)
628 // single word
629 int max_arg = 0;
630 int argt[10] = {0};
631 mala_macrocheck_string (arg[1]->string, &max_arg, argt);
632 if (max_arg == 0)
634 // substitute
635 if (MALA_SUCCESS != mala_engine_add_action (eng, name,
636 mala_string_copy (arg[1]->string),
637 mala_substitute_parser,
638 (MalaDataFactory) mala_string_factory,
639 NULL))
640 return MALA_EALLOC;
642 else if (max_arg > 0)
644 // macro
645 MalaStringList list;
647 list = mala_stringlist_new ();
648 if (!list)
649 return MALA_EALLOC;
651 mala_stringlist_tail_new (list, arg[1]->string);
653 if (MALA_SUCCESS != mala_engine_add_action (eng, name, list,
654 mala_macro_parser,
655 (MalaDataFactory) mala_stringlist_factory,
656 NULL))
657 return MALA_EALLOC;
659 else // syntax error
660 return mala_engine_exception (eng, pptr, arg[1],
661 eng->common_string[MALA_STRING_ERROR_PARAMETER_SYNTAX]);
664 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
665 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
666 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
667 return MALA_SUCCESS;
671 mala_foreach_word_parser (MalaEngine eng,
672 MalaStringListNode_ref pptr,
673 void * data)
675 MalaAction act;
676 MalaStringListNode first;
677 MalaStringListNode second;
678 MalaStringListNode last;
679 MalaStringListNode itr;
680 (void) data;
682 first = mala_engine_arg_eval (eng, pptr, 1, -1, NULL);
683 if (!first)
684 return eng->state;
685 act = mala_actiondesc_top ((MalaActionDesc) mala_string_user_get (first->string));
686 // TODO allow blocks as first arg (define macro and delete it at later)
687 if (act && act->parser == mala_block_parser)
688 return mala_engine_exception (eng, pptr, first,
689 eng->common_string[MALA_STRING_ERROR_BLOCK_NOT_ALLOWED]);
691 second = mala_engine_arg_eval (eng, pptr, 2, -1, (MalaDataFactory) mala_stringlist_factory);
692 if (!second)
693 return eng->state;
695 last = mala_stringlist_next (second);
697 act = mala_actiondesc_top ((MalaActionDesc) mala_string_user_get (second->string));
699 // expand second
700 if (eng->state != MALA_LITERAL)
701 for (itr = mala_stringlist_tail ((MalaStringList) act->data);
702 !mala_stringlist_is_end ((MalaStringList) act->data, itr);
703 mala_stringlist_rev (&itr))
705 if (!mala_stringlist_after_new (&eng->program, second, itr->string))
706 goto ealloc_node;
707 if (!mala_stringlist_after_new (&eng->program, second, first->string))
708 goto ealloc_node;
710 else
712 if (!mala_stringlist_after_new (&eng->program, second, second->string))
713 goto ealloc_node;
714 if (!mala_stringlist_after_new (&eng->program, second, first->string))
715 goto ealloc_node;
719 // was a block? delete it
720 if (act && act->parser == mala_block_parser)
721 mala_actiondesc_pop_delete (mala_string_user_get (second->string));
723 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
724 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
725 mala_stringlist_elem_delete_fwd (&eng->program, pptr);
727 return MALA_SUCCESS;
728 ealloc_node:
729 for (itr = mala_stringlist_next (second);
730 itr != last;
731 mala_stringlist_fwd (&itr))
733 mala_stringlist_elem_delete (&eng->program, itr);
736 return MALA_EALLOC; // TODO exception instead (needs pools, no allocation possible further)
743 realloc a string to at least needed size
744 return the amount really reserved or 0 on error
746 static size_t
747 reserve_string (char ** s, size_t actual, size_t needed)
749 size_t n;
750 char * r;
752 for (n = actual>64?actual:64; n <= needed; n += (n>>1)); /*n = n * 1.5*/
754 r = realloc (*s, n);
755 if (!r)
757 /* that was to much, try conservatively */
758 r = realloc (*s, n = needed);
759 if (!r)
760 return 0;
762 *s = r;
763 return n;
768 // Local Variables:
769 // mode: C
770 // c-file-style: "gnu"
771 // End:
772 // arch-tag: 687e1195-8aad-4425-983d-9767a25c3793
773 // end_of_file