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.
28 reserve_string (char ** s
, size_t actual
, size_t needed
);
31 mala_macrocheck_list (MalaStringList list
, int * max_arg
, int argt
[10]);
34 mala_macrocheck_string (MalaString string
, int * max_arg
, int argt
[10]);
38 MALA_PARSER("--MAP", mala_map_parser
, NULL
, NULL
, NULL
),
39 MALA_PARSER_BRIEF("--MAP", "TODO applies an action to each element of a nested list"),
40 MALA_PARSER_HELP("--MAP", ("TODO")),
41 MALA_PARSER_SIGNATURE_TYPE("--FOREACH-WORD", ("DEFINED-ACTION", "MACRO-LIST")),
42 MALA_PARSER_SIGNATURE_USAGE("--FOREACH-WORD", ("Action to be applied",
44 MALA_PARSER_RESULT_TYPE("--MAP", ("SEQUENCE")),
45 MALA_PARSER_RESULT_USAGE("--MAP", ("Resulting Sequence")),
48 MALA_PARSER("--LENGTH", mala_length_parser
, NULL
, NULL
, NULL
),
49 MALA_PARSER_BRIEF("--LENGTH", "returns the length of a sequence"),
50 MALA_PARSER_HELP("--LENGTH", ("TODO")),
51 MALA_PARSER_SIGNATURE_TYPE("--LENGTH", ("SEQUENCE")),
52 MALA_PARSER_SIGNATURE_USAGE("--LENGTH", ("list of lists")),
53 MALA_PARSER_RESULT_TYPE("--LENGTH", ("INTEGER")),
54 MALA_PARSER_RESULT_USAGE("--LENGTH", ("Length of the Sequence")),
58 mala_substitute_parser (MalaEngine eng
,
59 MalaStringListNode_ref pptr
,
65 mala_stringlistnode_substitute_string (*pptr
, (MalaString
) data
);
72 mala_expand_parser (MalaEngine eng
,
73 MalaStringListNode_ref pptr
,
76 MalaStringListNode itr
;
77 MalaStringListNode end
;
81 end
= mala_stringlistnode_next (*pptr
);
83 for (itr
= mala_stringlist_tail ((MalaStringList
) data
);
84 !mala_stringlist_is_end ((MalaStringList
) data
, itr
);
85 mala_stringlistnode_rev (&itr
))
87 if (!mala_stringlist_after_new (&eng
->program
, *pptr
,
88 mala_stringlistnode_string (itr
)))
94 mala_engine_command_done (eng
, pptr
, 0);
98 /* remove already added things */
99 for (itr
= mala_stringlistnode_next (*pptr
);
101 mala_stringlist_elem_delete_fwd (&eng
->program
, &itr
));
108 mala_macro_parser (MalaEngine eng
,
109 MalaStringListNode_ref pptr
,
112 MalaStringListNode itr
;
113 MalaStringListNode last
= NULL
;
121 MalaString str
= NULL
;
123 // scan how much args are needed
124 mala_macrocheck_list ((MalaStringList
) data
, &max_arg
, argt
);
126 // evaluate args, fill arg-array
127 args
[0] = mala_stringlistnode_string (*pptr
);
129 for (i
= 1; i
<= max_arg
; ++i
)
131 if (!(last
= mala_engine_arg_eval (eng
, pptr
, i
, argt
[i
] == 1 ? -1 : 0, NULL
, NULL
))
132 || eng
->state
> MALA_EFAULT
)
135 args
[i
] = mala_stringlistnode_string (last
);
138 MALA_SIDEEFFECT_BEGIN
140 // build list with substitutions
141 list
= mala_stringlist_new ();
145 for (itr
= mala_stringlist_head ((MalaStringList
) data
);
146 !mala_stringlist_is_end ((MalaStringList
) data
, itr
);
147 mala_stringlistnode_fwd (&itr
))
150 if (!(p
= malloc (size
)))
153 for (c
= mala_string_cstr (mala_stringlistnode_string (itr
)), i
= 0; *c
; ++c
,++i
)
163 else if (*c
>= '0' && *c
<= '9')
166 if (size
<= i
+mala_string_length (args
[*c
-'0'])
167 && !(size
= reserve_string (&p
,
169 1 + i
+ mala_string_length (args
[*c
-'0']))))
171 strcpy(p
+i
, mala_string_cstr (args
[*c
-'0']));
172 i
+= (mala_string_length (args
[*c
-'0']) - 1);
177 if (*c
>= '0' && *c
<= '9')
180 if (size
<= i
+mala_string_length (args
[*c
-'0'])
181 && !(size
= reserve_string (&p
,
184 mala_string_length (args
[*c
-'0']))))
186 strcpy(p
+i
, mala_string_cstr (args
[*c
-'0']));
187 i
+= (mala_string_length (args
[*c
-'0']) - 1);
195 if (size
<= (size_t) i
&& !(size
= reserve_string (&p
, size
, (size_t) i
+1)))
204 if (!(ptmp
= realloc (p
, size
)))
207 str
= mala_string_new_cstr_attach (ptmp
, &eng
->words
);
211 if (!mala_stringlist_tail_new (list
, str
))
214 mala_string_free (str
);
219 for (itr
= mala_stringlist_tail (list
);
220 !mala_stringlist_is_end (list
, itr
);
221 mala_stringlistnode_rev (&itr
))
223 if (!mala_stringlist_after_new (&eng
->program
, last
,
224 mala_stringlistnode_string (itr
)))
229 mala_stringlist_free (list
);
234 mala_engine_command_done (eng
, pptr
, max_arg
);
235 return MALA_CONTINUE
;
239 mala_string_free (str
);
245 mala_stringlist_free (list
);
251 mala_defined_parser (MalaEngine eng
,
252 MalaStringListNode_ref pptr
,
255 MalaStringListNode result
;
260 result
= mala_engine_arg_eval (eng
, pptr
, 1, -1, NULL
, NULL
);
264 MALA_SIDEEFFECT_BEGIN
266 desc
= (MalaActionDesc
) mala_stringlistnode_user_get (result
);
268 mala_engine_command_done (eng
, pptr
, 1);
270 if (desc
&& mala_actiondesc_top (desc
))
286 mala_map_parser (MalaEngine eng
,
287 MalaStringListNode_ref pptr
,
290 MalaStringListNode function
;
291 MalaStringListNode list_of_lists
;
295 result
= mala_engine_arg_eval (eng
, pptr
, 1, -1, NULL
, NULL
);
299 MALA_SIDEEFFECT_BEGIN
301 desc
= (MalaActionDesc
) mala_stringlistnode_user_get (result
);
303 mala_engine_command_done (eng
, pptr
, 1);
305 if (desc
&& mala_actiondesc_top (desc
))
321 mala_if_parser (MalaEngine eng
,
322 MalaStringListNode_ref pptr
,
325 MalaStringListNode result
;
327 /*TODO negated, blocks, parse long double 0.0 as false*/
328 /* what with syntax errors like --IF foo --ELSE .. (missing 'then' part)*/
331 result
= mala_engine_arg_eval (eng
, pptr
, 1, -1, NULL
, NULL
);
335 MALA_SIDEEFFECT_BEGIN
337 if (eng
->state
== MALA_LITERAL
)
339 if (mala_engine_string_istrue (eng
, mala_stringlistnode_string (result
)))
340 eng
->state
= MALA_SUCCESS
;
342 eng
->state
= MALA_FAILURE
;
347 if (eng
->state
== MALA_FAILURE
)
348 eng
->state
= MALA_REMOVE
;
350 result
= mala_engine_arg_eval (eng
, pptr
, 2, -1, NULL
, NULL
);
354 if (eng
->state
== MALA_REMOVE
)
355 eng
->state
= MALA_FAILURE
;
359 if (eng
->state
== MALA_LITERAL
)
360 mala_engine_command_done (eng
, pptr
, 1);
362 mala_engine_command_done (eng
, pptr
, 2);
367 mala_else_parser (MalaEngine eng
,
368 MalaStringListNode_ref pptr
,
371 MalaStringListNode result
;
375 MALA_SIDEEFFECT_BEGIN
377 if (eng
->state
== MALA_SUCCESS
)
378 eng
->state
= MALA_REMOVE
;
380 result
= mala_engine_arg_eval (eng
, pptr
, 1, -1, NULL
, NULL
);
384 if (eng
->state
== MALA_REMOVE
)
385 eng
->state
= MALA_SUCCESS
;
389 if (eng
->state
== MALA_LITERAL
)
390 mala_engine_command_done (eng
, pptr
, 0);
392 mala_engine_command_done (eng
, pptr
, 0);
397 mala_pass_parser (MalaEngine eng
,
398 MalaStringListNode_ref pptr
,
403 mala_stringlist_elem_delete_fwd (&eng
->program
, pptr
);
409 mala_trace_parser (MalaEngine eng
,
410 MalaStringListNode_ref pptr
,
415 MALA_SIDEEFFECT_BEGIN
416 eng
->trace
= !eng
->negated
;
419 mala_engine_command_done (eng
, pptr
, 0);
423 /*TODO to predicates*/
425 mala_predicate_greaterorequal_double (double * a
, double * b
)
431 mala_sleep_parser (MalaEngine eng
,
432 MalaStringListNode_ref pptr
,
441 if (mala_engine_arg_eval_fmt (eng
, pptr
, 1, "%lf", &duration
,
442 (MalaPredicate
) mala_predicate_greaterorequal_double
, &zero
446 MALA_SIDEEFFECT_BEGIN
448 req
.tv_sec
= (time_t) duration
;
449 req
.tv_nsec
= (long) 1000000000 * (duration
- ((double) req
.tv_sec
));
451 (void) nanosleep (&req
, NULL
);
455 mala_engine_command_done (eng
, pptr
, 1);
460 mala_literal_parser (MalaEngine eng
,
461 MalaStringListNode_ref pptr
,
466 MALA_SIDEEFFECT_BEGIN
468 if (mala_stringlist_is_tail (&eng
->program
, *pptr
))
469 return mala_engine_exception (eng
, pptr
, *pptr
,
470 eng
->common_string
[MALA_STRING_ERROR_MISSING_ARGUMENT
]);
474 mala_stringlist_elem_delete_fwd (&eng
->program
, pptr
);
479 mala_not_parser (MalaEngine eng
,
480 MalaStringListNode_ref pptr
,
485 MALA_SIDEEFFECT_BEGIN
487 if (mala_stringlist_is_tail (&eng
->program
, *pptr
))
488 return mala_engine_exception (eng
, pptr
, *pptr
,
489 eng
->common_string
[MALA_STRING_ERROR_MISSING_ARGUMENT
]);
490 } /*TODO remove unfinished*/
493 mala_stringlist_elem_delete_fwd (&eng
->program
, pptr
);
494 eng
->negated
= !eng
->negated
;
495 return MALA_SUCCESS
; /*TODO*/
499 mala_begin_parser (MalaEngine eng
,
500 MalaStringListNode_ref pptr
,
503 MalaStringListNode itr
;
504 MalaStringListNode end
;
507 MalaString name
= NULL
;
511 if (mala_stringlist_is_tail (&eng
->program
, *pptr
))
512 return mala_engine_exception (eng
, pptr
, *pptr
,
513 eng
->common_string
[MALA_STRING_ERROR_MISSING_END
]);
515 // find matching --END
516 for (end
= mala_stringlistnode_next (*pptr
);
517 !mala_stringlist_is_end (&eng
->program
, end
);
518 mala_stringlistnode_fwd (&end
))
520 if (mala_string_same(mala_stringlistnode_string (end
),
521 eng
->common_string
[MALA_STRING_BEGIN
]))
523 else if (mala_string_same(mala_stringlistnode_string (end
),
524 eng
->common_string
[MALA_STRING_END
]))
531 return mala_engine_exception (eng
, pptr
, mala_stringlistnode_prev (end
),
532 eng
->common_string
[MALA_STRING_ERROR_MISSING_END
]);
534 MALA_SIDEEFFECT_BEGIN
536 list
= mala_stringlist_new ();
540 // copy the block content to list
541 for (itr
= mala_stringlistnode_next (*pptr
); itr
!= end
; mala_stringlistnode_fwd (&itr
))
542 if (!mala_stringlist_tail_new (list
, mala_stringlistnode_string (itr
)))
545 // allocate new block name
547 mala_string_free (name
);
548 name
= mala_string_new_print (&eng
->words
, "--BLOCK_%08X", ++eng
->blockcnt
);
551 } while (mala_actiondesc_top ((MalaActionDesc
)mala_string_user_get (name
)));
553 if (MALA_SUCCESS
!= mala_engine_add_action (eng
, name
, list
,
555 (MalaDataFactory
)mala_stringlist_factory
,
559 // insert new --BLOCK_... in program
560 if (!mala_stringlist_after_new (&eng
->program
, end
, name
))
562 mala_string_free (name
);
566 if (!mala_stringlist_after_new (&eng
->program
,
568 eng
->common_string
[MALA_STRING_PASS
]))
573 // and remove definition
575 mala_stringlist_elem_delete_fwd (&eng
->program
, pptr
);
577 mala_stringlist_elem_delete_fwd (&eng
->program
, pptr
);
579 return MALA_CONTINUE
;
582 mala_string_free (name
);
585 mala_stringlist_free (list
);
591 mala_block_parser (MalaEngine eng
,
592 MalaStringListNode_ref pptr
,
595 MalaStringListNode itr
;
596 MalaStringListNode end
;
598 MALA_SIDEEFFECT_BEGIN
600 end
= mala_stringlistnode_next (*pptr
);
602 for (itr
= mala_stringlist_tail ((MalaStringList
) data
);
603 !mala_stringlist_is_end ((MalaStringList
) data
, itr
);
604 mala_stringlistnode_rev (&itr
))
606 if (!mala_stringlist_after_new (&eng
->program
, *pptr
,
607 mala_stringlistnode_string (itr
)))
613 mala_actiondesc_pop_delete (mala_stringlistnode_user_get (*pptr
));
614 mala_engine_command_done (eng
, pptr
, 0);
615 return MALA_CONTINUE
;
618 /* remove already added things */
619 for (itr
= mala_stringlistnode_next (*pptr
);
621 mala_stringlist_elem_delete_fwd (&eng
->program
, &itr
));
627 mala_macrodelete_parser (MalaEngine eng
,
628 MalaStringListNode_ref pptr
,
633 mala_engine_arg_eval (eng
, pptr
, 1, -1, NULL
, NULL
);
635 MALA_SIDEEFFECT_BEGIN
637 if (mala_stringlist_is_tail (&eng
->program
, *pptr
))
638 return mala_engine_exception (eng
, pptr
, *pptr
,
639 eng
->common_string
[MALA_STRING_ERROR_MISSING_ARGUMENT
]);
641 mala_actiondesc_pop_delete (mala_stringlistnode_user_get (mala_stringlistnode_next (*pptr
)));
645 mala_engine_command_done (eng
, pptr
, 1);
650 mala_exception_parser (MalaEngine eng
,
651 MalaStringListNode_ref pptr
,
654 // TODO needs better semantics --EXCEPTION n error -> --ERROR-error 1 .. n --HERE
658 mala_engine_arg_eval (eng
, pptr
, 1, -1, NULL
, NULL
);
660 //TODO MALA_SIDEEFFECT_BEGIN
662 if (mala_stringlist_is_tail (&eng
->program
, *pptr
))
663 return mala_engine_exception (eng
, pptr
, *pptr
,
664 eng
->common_string
[MALA_STRING_ERROR_MISSING_ARGUMENT
]);
666 if (eng
->state
> MALA_EFAULT
)
669 MalaString ex
= mala_string_new_print (&eng
->words
, "--ERROR-%s",
670 mala_stringlistnode_cstr (mala_stringlistnode_next (*pptr
)));
672 mala_stringlist_elem_delete_fwd (&eng
->program
, pptr
);
673 int state
= mala_engine_exception (eng
, pptr
, *pptr
, ex
);
674 mala_stringlist_elem_delete (&eng
->program
, mala_stringlistnode_next (*pptr
));
676 mala_string_free (ex
);
677 // MALA_SIDEEFFECT_END;
683 mala_end_parser (MalaEngine eng
,
684 MalaStringListNode_ref pptr
,
689 return mala_engine_exception (eng
, pptr
, *pptr
,
690 eng
->common_string
[MALA_STRING_ERROR_END_WITHOUT_BEGIN
]);
694 mala_macrocheck_list (MalaStringList list
, int * max_arg
, int argt
[10])
696 MalaStringListNode itr
;
697 for (itr
= mala_stringlist_head (list
);
698 !mala_stringlist_is_end (list
, itr
);
699 mala_stringlistnode_fwd (&itr
))
701 mala_macrocheck_string (mala_stringlistnode_string (itr
), max_arg
, argt
);
708 mala_macrocheck_string (MalaString string
, int * max_arg
, int argt
[10])
711 for (c
= mala_string_cstr (string
); *c
; ++c
)
725 if (*c
>= '0' && *c
<= '9')
728 if (argt
[*c
- '0'] == 1)
730 if (*c
> (char) *max_arg
+ '0')
737 else if (*c
>= '0' && *c
<= '9')
740 if (argt
[*c
- '0'] == -1)
742 if (*c
> (char) *max_arg
+ '0')
758 mala_macrodef_parser (MalaEngine eng
,
759 MalaStringListNode_ref pptr
,
763 MalaStringListNode itr
;
764 MalaStringListNode arg
[2];
770 // evaluate both args
771 if (!mala_engine_arg_eval (eng
, pptr
, 1, -1, NULL
, NULL
))
773 if (!mala_engine_arg_eval (eng
, pptr
, 2, -1, NULL
, mala_block_parser
))
776 MALA_SIDEEFFECT_BEGIN
778 // test if 2 arguments left and assign them to arg[], else error
779 for (i
= 0, itr
= *pptr
; i
<2; ++i
, mala_stringlistnode_fwd(&itr
))
781 if (mala_stringlist_is_tail (&eng
->program
, itr
))
782 return mala_engine_exception (eng
, pptr
, itr
,
783 eng
->common_string
[MALA_STRING_ERROR_MISSING_ARGUMENT
]);
784 arg
[i
] = mala_stringlistnode_next (itr
);
787 // if name is a block then error
788 name
= mala_stringlistnode_string (arg
[0]);
789 act
= mala_actiondesc_top ((MalaActionDesc
) mala_string_user_get (name
));
790 if (act
&& act
->parser
== mala_block_parser
)
791 return mala_engine_exception (eng
, pptr
, arg
[0],
792 eng
->common_string
[MALA_STRING_ERROR_BLOCK_NOT_ALLOWED
]);
794 //expansion check and optimize block
795 act
= mala_actiondesc_top ((MalaActionDesc
) mala_stringlistnode_user_get (arg
[1]));
796 if (act
&& act
->factory
== (MalaDataFactory
) mala_stringlist_factory
)
800 mala_macrocheck_list ((MalaStringList
) act
->data
, &max_arg
, argt
);
801 // convert block to expansion
806 desc
= mala_actiondesc_ensure (name
);
810 act
= mala_actiondesc_pop ((MalaActionDesc
) mala_stringlistnode_user_get (arg
[1]));
812 act
->parser
= mala_macro_parser
;
813 mala_actiondesc_push_action (desc
, act
);
815 else if (mala_stringlist_is_single ((MalaStringList
) act
->data
))
819 subst
= mala_stringlist_head_string_copy ((MalaStringList
) act
->data
);
821 if (MALA_SUCCESS
!= mala_engine_add_action (eng
, name
, subst
,
822 mala_substitute_parser
,
823 (MalaDataFactory
) mala_string_factory
,
827 mala_action_free(act
);
829 else if (max_arg
== 0)
833 desc
= mala_actiondesc_ensure (name
);
837 act
= mala_actiondesc_pop ((MalaActionDesc
) mala_stringlistnode_user_get (arg
[1]));
839 act
->parser
= mala_expand_parser
;
840 mala_actiondesc_push_action (desc
, act
);
843 return mala_engine_exception (eng
, pptr
, arg
[1],
844 eng
->common_string
[MALA_STRING_ERROR_PARAMETER_SYNTAX
]);
846 else //if (act && act->factory == (MalaDataFactory)mala_string_factory)
851 mala_macrocheck_string (mala_stringlistnode_string (arg
[1]), &max_arg
, argt
);
855 if (MALA_SUCCESS
!= mala_engine_add_action (eng
, name
,
856 mala_stringlistnode_string_copy (arg
[1]),
857 mala_substitute_parser
,
858 (MalaDataFactory
) mala_string_factory
,
862 else if (max_arg
> 0)
867 list
= mala_stringlist_new ();
871 mala_stringlist_tail_new (list
, mala_stringlistnode_string (arg
[1]));
873 if (MALA_SUCCESS
!= mala_engine_add_action (eng
, name
, list
,
875 (MalaDataFactory
) mala_stringlist_factory
,
880 return mala_engine_exception (eng
, pptr
, arg
[1],
881 eng
->common_string
[MALA_STRING_ERROR_PARAMETER_SYNTAX
]);
886 mala_engine_command_done (eng
, pptr
, 2);
891 mala_foreach_word_parser (MalaEngine eng
,
892 MalaStringListNode_ref pptr
,
896 MalaStringListNode first
;
897 MalaStringListNode second
;
898 MalaStringListNode last
;
899 MalaStringListNode itr
;
902 /*TODO bugs, rename to --APPLY fixit etc*/
904 first
= mala_engine_arg_eval (eng
, pptr
, 1, -1, NULL
, NULL
);
907 act
= mala_actiondesc_top ((MalaActionDesc
) mala_stringlistnode_user_get (first
));
908 // TODO allow blocks as first arg (define macro and delete it at later)
909 if (act
&& act
->parser
== mala_block_parser
)
910 return mala_engine_exception (eng
, pptr
, first
,
911 eng
->common_string
[MALA_STRING_ERROR_BLOCK_NOT_ALLOWED
]);
913 second
= mala_engine_arg_eval (eng
, pptr
, 2, -1, (MalaDataFactory
) mala_stringlist_factory
, NULL
);
917 last
= mala_stringlistnode_next (second
);
919 act
= mala_actiondesc_top ((MalaActionDesc
) mala_stringlistnode_user_get (second
));
922 if (eng
->state
!= MALA_LITERAL
)
923 for (itr
= mala_stringlist_tail ((MalaStringList
) act
->data
);
924 !mala_stringlist_is_end ((MalaStringList
) act
->data
, itr
);
925 mala_stringlistnode_rev (&itr
))
927 if (!mala_stringlist_after_new (&eng
->program
,
929 mala_stringlistnode_string (itr
)))
931 if (!mala_stringlist_after_new (&eng
->program
,
933 mala_stringlistnode_string (first
)))
938 if (!mala_stringlist_after_new (&eng
->program
,
940 mala_stringlistnode_string (second
)))
942 if (!mala_stringlist_after_new (&eng
->program
,
944 mala_stringlistnode_string (first
)))
949 // was a block? delete it
950 if (act
&& act
->parser
== mala_block_parser
)
951 mala_actiondesc_pop_delete (mala_stringlistnode_user_get (second
));
953 mala_engine_command_done (eng
, pptr
, 2);
957 for (itr
= mala_stringlistnode_next (second
);
959 mala_stringlistnode_fwd (&itr
))
961 mala_stringlist_elem_delete (&eng
->program
, itr
);
964 return MALA_EALLOC
; // TODO exception instead (needs pools, no allocation possible further)
971 realloc a string to at least needed size
972 return the amount really reserved or 0 on error
975 reserve_string (char ** s
, size_t actual
, size_t needed
)
980 for (n
= actual
>64?actual
:64; n
<= needed
; n
+= (n
>>1)); /*n = n * 1.5*/
985 /* that was to much, try conservatively */
986 r
= realloc (*s
, n
= needed
);
998 // c-file-style: "gnu"
1000 // arch-tag: 195047fd-d18b-4af6-a627-43e5655162ed