371d2b4653d3541bc08b6304cec2d582948a12f0
[egate.git] / fml / fml.c
1 /*
2  * FML interpreter. Europagate, 1995
3  *
4  * $Log: fml.c,v $
5  * Revision 1.8  1995/02/10 18:15:52  adam
6  * FML function 'strcmp' implemented. This function can be used to
7  * test for existence of MARC fields.
8  *
9  * Revision 1.7  1995/02/10  15:50:54  adam
10  * MARC interface implemented. Minor bugs fixed. fmltest can
11  * be used to format single MARC records. New function '\list'
12  * implemented.
13  *
14  * Revision 1.6  1995/02/09  16:06:06  adam
15  * FML can be called from the outside multiple times by the functions:
16  * fml_exec_call and fml_exec_call_str.
17  * An interactive parameter (-i) to fmltest starts a shell-like
18  * interface to FML by using the fml_exec_call_str function.
19  *
20  * Revision 1.5  1995/02/09  14:33:36  adam
21  * Split source fml.c and define relevant build-in functions in separate
22  * files. New operators mult, div, not, llen implemented.
23  *
24  * Revision 1.4  1995/02/09  13:07:14  adam
25  * Nodes are freed now. Many bugs fixed.
26  *
27  * Revision 1.3  1995/02/07  16:09:23  adam
28  * The \ character is no longer INCLUDED when terminating a token.
29  * Major changes in tokenization routines. Bug fixes in expressions
30  * with lists (fml_sub0).
31  *
32  * Revision 1.2  1995/02/06  15:23:25  adam
33  * Added some more relational operators (le,ne,ge). Added increment
34  * and decrement operators. Function index changed, so that first
35  * element is 1 - not 0. Function fml_atom_val edited.
36  *
37  * Revision 1.1.1.1  1995/02/06  13:48:10  adam
38  * First version of the FML interpreter. It's slow and memory isn't
39  * freed properly. In particular, the FML nodes aren't released yet.
40  *
41  */
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45
46 #include "fmlp.h"
47
48 static int default_read_func (void)
49 {
50     return getchar ();
51 }
52
53 static void default_err_handle (int no)
54 {
55     fprintf (stderr, "Error: %d\n", no);
56 }
57
58 static struct fml_node *fml_sub0 (Fml fml, struct fml_node *list);
59 static struct fml_node *fml_sub1 (Fml fml, struct fml_node **lp,
60                                   struct token *tp);
61 static struct fml_node *fml_sub2 (Fml fml, struct fml_node **lp,
62                                   struct token *tp);
63 static struct fml_node *fml_exec_space (Fml fml, struct fml_node **lp, 
64                                         struct token *tp);
65 static struct fml_node *fml_exec_nl (Fml fml, struct fml_node **lp, 
66                                      struct token *tp);
67                                   
68 static int indent = 0;
69
70 static void pr_indent (int n)
71 {
72     assert (indent >= 0);
73     if (n >= 0)
74     {
75         int i = indent;
76         while (--i >= 0)
77             putchar(' ');
78     }
79     if (n > 0)
80     {
81         printf ("[");
82         ++indent;
83     } 
84     else if (n < 0)
85     {
86         printf ("]\n");
87         --indent;
88     }
89 }
90
91 Fml fml_open (void)
92 {
93     struct fml_sym_info *sym_info;
94
95     Fml fml = malloc (sizeof(*fml));
96
97     if (!fml)
98         return NULL;
99
100     fml->escape_char = '\\';
101     fml->comment_char = '#';
102     fml->eof_mark = EOF;
103     fml->white_chars = " \t\f\r\n";
104     fml->read_func = default_read_func;
105     fml->err_handle = default_err_handle;
106
107     fml->list = NULL;
108     fml->sym_tab = fml_sym_open ();
109     fml->atom_free_list = NULL;
110     fml->node_free_list = NULL;
111     fml->debug = 0;
112
113     sym_info = fml_sym_add (fml->sym_tab, "func");
114     sym_info->kind = FML_FUNC;
115     sym_info = fml_sym_add (fml->sym_tab, "bin");
116     sym_info->kind = FML_BIN;
117     sym_info = fml_sym_add (fml->sym_tab, "if");
118     sym_info->kind = FML_IF;
119     sym_info = fml_sym_add (fml->sym_tab, "else");
120     sym_info->kind = FML_ELSE;
121     sym_info = fml_sym_add (fml->sym_tab, "foreach");
122     sym_info->kind = FML_FOREACH;
123     sym_info = fml_sym_add (fml->sym_tab, "set");
124     sym_info->kind = FML_SET;
125     sym_info = fml_sym_add (fml->sym_tab, "while");
126     sym_info->kind = FML_WHILE;
127     sym_info = fml_sym_add (fml->sym_tab, "return");
128     sym_info->kind = FML_RETURN;
129
130     fml_list_init (fml);
131     fml_arit_init (fml);
132     fml_rel_init (fml);
133     fml_str_init (fml);
134
135     sym_info = fml_sym_add (fml->sym_tab, "s");
136     sym_info->kind = FML_CPREFIX;
137     sym_info->prefix = fml_exec_space;
138     sym_info = fml_sym_add (fml->sym_tab, " ");
139     sym_info->kind = FML_CPREFIX;
140     sym_info->prefix = fml_exec_space;
141     sym_info = fml_sym_add (fml->sym_tab, "n");
142     sym_info->kind = FML_CPREFIX;
143     sym_info->prefix = fml_exec_nl;
144
145     return fml;
146 }
147
148 static Fml fml_pop_handler = NULL;
149 static void pop_handler (struct fml_sym_info *info)
150 {
151     assert (fml_pop_handler);
152     switch (info->kind)
153     {
154     case FML_VAR:
155         fml_node_delete (fml_pop_handler, info->body);
156         break;
157     }
158 }
159 static void fml_do_pop (Fml fml)
160 {
161     fml_pop_handler = fml;
162     fml_sym_pop (fml->sym_tab, pop_handler);
163 }
164
165 int fml_preprocess (Fml fml)
166 {
167     fml->list = fml_tokenize (fml);
168     return 0;
169 }
170
171
172 void fml_init_token (struct token *tp, Fml fml)
173 {
174     tp->maxbuf = FML_ATOM_BUF*2;
175     tp->offset = 0;
176     tp->atombuf = tp->sbuf;
177     tp->tokenbuf = tp->sbuf + tp->maxbuf;
178     tp->escape_char = fml->escape_char;
179 }
180
181 void fml_del_token (struct token *tp, Fml fml)
182 {
183     if (tp->maxbuf != FML_ATOM_BUF*2)
184         free (tp->atombuf);
185 }
186
187 void fml_cmd_lex (struct fml_node **np, struct token *tp)
188 {
189     char *cp;
190     char *dst;
191     if (!*np)
192     {
193         tp->kind = '\0';
194         return;
195     }
196     if (tp->offset == 0)
197     {
198         tp->separate = 1;
199         if ((*np)->is_atom)
200         {
201             tp->atom = (*np)->p[0];
202             if (!tp->atom->next)
203                 fml_atom_str (tp->atom, tp->atombuf);
204             else
205             {
206                 int l = fml_atom_str (tp->atom, NULL);
207                 if (l >= tp->maxbuf-1)
208                 {
209                     if (tp->maxbuf != FML_ATOM_BUF*2)
210                         free (tp->atombuf);
211                     tp->maxbuf = l + 40;
212                     tp->atombuf = malloc (tp->maxbuf*2);
213                     tp->tokenbuf = tp->atombuf + tp->maxbuf;
214                 }
215                 fml_atom_str (tp->atom, tp->atombuf);
216             }
217         }
218         else
219         {
220             tp->sub = (*np)->p[0];
221             tp->kind = 'g';
222             *np = (*np)->p[1];
223             return ;
224         }
225     }
226     else
227         tp->separate = 0;
228     cp = tp->atombuf + tp->offset;
229     dst = tp->tokenbuf;
230     if (*cp == tp->escape_char)
231     {
232         tp->kind = 'e';
233         cp++;
234         if (*cp == '\0')
235         {
236             strcpy (dst, " ");
237             tp->offset = 0;
238             *np = (*np)->p[1];
239             return ;
240         }
241     }
242     else
243     {
244         tp->kind = 't';
245     }
246     while (*cp)
247     {
248         if (*cp == tp->escape_char)
249         {
250             *dst = '\0';
251             tp->offset = cp - tp->atombuf;
252             return ;
253         }
254         *dst++ = *cp++;
255     }
256     *dst = '\0';
257     tp->offset = 0;
258     *np = (*np)->p[1];
259 }
260
261 struct fml_node *fml_expr_term (Fml fml, struct fml_node **lp, 
262                                 struct token *tp)
263 {
264     struct fml_node *fn;
265     if (tp->kind == 'g')
266     {
267         fn = fml_sub0 (fml, tp->sub);
268         fml_cmd_lex (lp, tp);
269     }
270     else
271         fn = fml_sub2 (fml, lp, tp);
272     return fn;
273 }
274
275 void fml_lr_values (Fml fml, struct fml_node *l, int *left_val,
276                            struct fml_node *r, int *right_val)
277 {
278     if (l && l->is_atom)
279         *left_val = fml_atom_val (l->p[0]);
280     else
281         *left_val = 0;
282     if (r && r->is_atom)
283         *right_val = fml_atom_val (r->p[0]);
284     else
285         *right_val = 0;
286     fml_node_delete (fml, l);
287     fml_node_delete (fml, r);
288 }
289
290 static struct fml_node *fml_exec_space (Fml fml, struct fml_node **lp, 
291                                         struct token *tp)
292 {
293     fml_cmd_lex (lp, tp);
294     if (fml->debug & 1)
295         putchar ('_');
296     else
297         putchar (' ');
298     return NULL;
299 }
300
301 static struct fml_node *fml_exec_nl (Fml fml, struct fml_node **lp, 
302                                      struct token *tp)
303 {
304     fml_cmd_lex (lp, tp);
305     putchar ('\n');
306     return NULL;
307 }
308
309 static struct fml_node *fml_exec_prefix (struct fml_sym_info *info, Fml fml,
310                                          struct fml_node **lp,
311                                          struct token *tp)
312 {
313     struct fml_node *fn;
314     struct fml_sym_info *arg_info;
315     struct fml_node *return_value;
316     static char arg[128];
317
318     if (fml->debug & 1)
319     {
320         pr_indent (1);
321         printf ("exec_prefix ");
322     }
323     fml_sym_push (fml->sym_tab);
324     fml_cmd_lex (lp, tp);
325     for (fn = info->args; fn; fn = fn->p[1])
326     {
327
328         assert (fn->is_atom);
329         fml_atom_strx (fn->p[0], arg, 127);
330         if (fml->debug & 1)
331         {
332             pr_indent (1);
333             printf ("%s=", arg);
334         }
335         arg_info = fml_sym_add_local (fml->sym_tab, arg);
336         arg_info->kind = FML_VAR;
337
338         if (tp->kind == 'g')
339         {
340             arg_info->body = fml_sub0 (fml, tp->sub);
341             fml_cmd_lex (lp, tp);
342         }
343         else
344             arg_info->body = fml_sub2 (fml, lp, tp);
345         if (fml->debug & 1)
346         {
347             fml_pr_list (arg_info->body);
348             pr_indent (-1);
349         }
350     }
351     return_value = fml_exec_group (info->body, fml);
352     if (fml->debug & 1)
353     {
354         pr_indent(0);
355         pr_indent (-1);
356     }
357     fml_do_pop (fml);
358     return return_value;
359 }
360
361
362 static void fml_emit (struct fml_node *list)
363 {
364     int s = 0;
365     while (list)
366     {
367         if (list->is_atom)
368         {
369             struct fml_atom *a;
370             if (s)
371                 printf (" ");
372             s++;
373             for (a = list->p[0]; a; a=a->next)
374                 printf ("%.*s", FML_ATOM_BUF, a->buf);
375         }
376         else
377             fml_emit (list->p[0]);
378         list = list->p[1];
379     }
380 }
381
382
383 static struct fml_node *fml_sub2 (Fml fml, struct fml_node **lp,
384                                   struct token *tp)
385 {
386     struct fml_node *fn;
387     struct fml_sym_info *info;
388     if (tp->kind == 'e')
389     {
390         info = fml_sym_lookup (fml->sym_tab, tp->tokenbuf);
391         assert (info);
392         switch (info->kind)
393         {
394         case FML_VAR:
395             fn = fml_node_copy (fml, info->body);           
396             fml_cmd_lex (lp, tp);
397             break;
398         case FML_PREFIX:
399             fn = fml_exec_prefix (info, fml, lp, tp);
400             break;
401         case FML_CPREFIX:
402             fn = (*info->prefix) (fml, lp, tp);
403             break;
404         default:
405             fml_cmd_lex (lp, tp);
406             fn = NULL;
407         }
408     }
409     else if (tp->kind == 'g')
410     {
411         if (tp->sub)
412             fn = fml_sub0 (fml, tp->sub);
413         else
414             fn = NULL;
415         fml_cmd_lex (lp, tp);
416     }
417     else if (tp->kind == 't')
418     {
419         fn = fml_node_alloc (fml);
420         fn->is_atom = 1;
421         fn->p[0] = fml_atom_alloc (fml, tp->tokenbuf);
422         fml_cmd_lex (lp, tp);
423     }
424     else
425         fn = NULL;
426     return fn;
427 }
428
429 static struct fml_node *fml_sub1 (Fml fml, struct fml_node **lp,
430                                   struct token *tp)
431 {
432     struct fml_node *f1, *f2, *fn;
433     struct fml_sym_info *info;
434
435     f1 = fml_sub2 (fml, lp, tp);
436     while (tp->kind == 'e')
437     {
438         info = fml_sym_lookup (fml->sym_tab, tp->tokenbuf);
439         if (!info)
440         {
441             fprintf (stderr, "cannot locate `%s'", tp->tokenbuf);
442             exit (1);
443         }
444         if (info->kind == FML_CBINARY)
445         {
446             fml_cmd_lex (lp, tp);
447             f2 = fml_sub2 (fml, lp, tp);
448             fn = (*info->binary) (fml, f1, f2);
449             f1 = fn;
450             continue;
451         }
452         else if (info->kind == FML_BINARY)
453         {
454             struct fml_sym_info *arg_info;
455             char arg[127];
456
457             if (fml->debug & 1)
458             {
459                 pr_indent (1);
460                 printf ("exec binary %s", tp->tokenbuf);
461             }
462             fml_cmd_lex (lp, tp);
463             f2 = fml_sub2 (fml, lp, tp);
464             fml_sym_push (fml->sym_tab);
465
466             fml_atom_strx (info->args->p[0], arg, 127);
467             arg_info = fml_sym_add_local (fml->sym_tab, arg);
468             arg_info->kind = FML_VAR;
469             arg_info->body = f1;
470             if (fml->debug & 1)
471             {
472                 printf (" left=");
473                 fml_pr_list (f1);
474             }
475             fml_atom_strx ( ((struct fml_node *) info->args->p[1])->p[0],
476                            arg, 127);
477             arg_info = fml_sym_add_local (fml->sym_tab, arg);
478             arg_info->kind = FML_VAR;
479             arg_info->body = f2;
480             if (fml->debug & 1)
481             {
482                 printf (" right=");
483                 fml_pr_list (f2);
484                 putchar ('\n');
485             }
486             f1 = fml_exec_group (info->body, fml);
487             fml_do_pop (fml);
488             if (fml->debug & 1)
489             {
490                 pr_indent (0);
491                 pr_indent (-1);
492             }
493         }
494         else
495             break;
496     }
497     return f1;
498 }
499
500 #if 0
501 static struct fml_node *fml_sub0 (Fml fml, struct fml_node *list)
502 {
503     struct token token;
504     struct fml_node *fn, *fn1;
505
506     fml_init_token (&token, fml);
507     assert (list);
508     fml_cmd_lex (&list, &token);
509     fn = fml_sub1 (fml, &list, &token);
510     if (token.kind == '\0')
511     {
512         fml_del_token (&token, fml);
513         return fn;
514     }
515     fn1 = fml_node_alloc (fml);
516     fn1->p[0] = fn;
517     fn = fn1;
518     while (token.kind != '\0')
519     {
520         fn1 = fn1->p[1] = fml_node_alloc (fml);
521         fn1->p[0] = fml_sub1 (fml, &list, &token);
522     }
523     fml_del_token (&token, fml);
524     return fn;
525 }
526 #else
527 static struct fml_node *fml_sub0 (Fml fml, struct fml_node *list)
528 {
529     struct token token;
530     struct fml_node *fn, *fn0, *fn1;
531
532     if (!list)
533         return NULL;
534     fml_init_token (&token, fml);
535     assert (list);
536     fml_cmd_lex (&list, &token);
537     fn1 = fn = fml_sub1 (fml, &list, &token);
538     if (fn->p[1] && token.kind != '\0')
539     {
540         fn1 = fml_node_alloc (fml);
541         fn1->p[0] = fn;
542     }
543     fn0 = fn1;
544     while (token.kind != '\0')
545     {
546         fn = fml_sub1 (fml, &list, &token);
547         if (fn->p[1])
548         {
549             fn1 = fn1->p[1] = fml_node_alloc (fml);
550             fn1->p[0] = fn;
551         }
552         else
553         {
554             fn1 = fn1->p[1] = fn;
555         }
556     }
557     fml_del_token (&token, fml);
558     return fn0;
559 }
560 #endif
561
562 static struct fml_node *fml_exec_foreach (struct fml_sym_info *info, Fml fml,
563                                           struct fml_node **lp,
564                                           struct token *tp)
565 {
566     struct fml_sym_info *info_var;
567     struct fml_node *fn, *body;
568     struct fml_node *return_value = NULL, *rv;
569
570     fml_cmd_lex (lp, tp);
571     assert (tp->kind == 't');
572     
573     info_var = fml_sym_lookup_local (fml->sym_tab, tp->tokenbuf);
574     if (!info_var)
575     {
576         info_var = fml_sym_add_local (fml->sym_tab, tp->tokenbuf);
577         info_var->body = NULL;
578         info_var->kind = FML_VAR;
579     }
580     else
581     {
582         if (info_var->kind == FML_VAR)
583             fml_node_delete (fml, info_var->body);
584         info_var->body = NULL;
585     }
586     if (fml->debug & 1)
587     {
588         pr_indent (1);
589         printf ("[foreach %s ", tp->tokenbuf);
590     }
591     fml_cmd_lex (lp, tp);
592     assert (tp->kind == 'g');
593     fn = fml_sub0 (fml, tp->sub);
594  
595     fml_cmd_lex (lp, tp);
596     assert (tp->kind == 'g');
597     body = tp->sub;
598  
599     while (fn)
600     {
601         struct fml_node *fn1;
602
603         fn1 = fn->p[1];
604         fn->p[1] = NULL;
605         if (fn->is_atom)
606             info_var->body = fn;
607         else
608             info_var->body = fn->p[0];
609         if (fml->debug & 1)
610         {
611             pr_indent (1);
612             printf ("[foreach loop var=");
613             fml_pr_list (info_var->body);
614             pr_indent (-1);
615         }
616         rv = fml_exec_group (body, fml);
617         if (rv)
618             return_value = rv;
619         fml_node_delete (fml, fn);
620         fn = fn1;
621     }
622     info_var->body = NULL;
623     if (fml->debug & 1)
624         pr_indent (-1);
625     return return_value;
626 }
627
628 static struct fml_node *fml_exec_if (struct fml_sym_info *info, Fml fml,
629                                      struct fml_node **lp, struct token *tp)
630 {
631     struct fml_node *fn, *body;
632     struct fml_node *rv, *return_value = NULL;
633
634     fml_cmd_lex (lp, tp);
635     assert (tp->kind == 'g');
636     fn = fml_sub0 (fml, tp->sub);
637     fml_cmd_lex (lp, tp);
638     assert (tp->kind == 'g');
639     if (fn)
640     {
641         rv = fml_exec_group (tp->sub, fml);
642         if (rv)
643             return_value = rv;
644     }
645     fml_cmd_lex (lp, tp);
646     if (tp->kind == 'e')
647     {
648         info = fml_sym_lookup (fml->sym_tab, tp->tokenbuf);
649         if (info->kind == FML_ELSE)
650         {
651             fml_cmd_lex (lp, tp);
652             assert (tp->kind == 'g');
653             body = tp->sub;
654             if (!fn)
655             {
656                 rv = fml_exec_group (body, fml);
657                 if (rv)
658                     return_value = rv;
659             }
660             fml_cmd_lex (lp, tp);
661         }
662     }
663     fml_node_delete (fml, fn);
664     return return_value;
665 }
666
667 static struct fml_node *fml_exec_while (struct fml_sym_info *info, Fml fml,
668                                         struct fml_node **lp, struct token *tp)
669 {
670     struct fml_node *fn, *body;
671     struct fml_node *return_value = NULL;
672
673     fml_cmd_lex (lp, tp);
674     assert (tp->kind == 'g');
675     fn = tp->sub;
676
677     fml_cmd_lex (lp, tp);
678     assert (tp->kind == 'g');
679     body = tp->sub;
680     assert (tp->sub);
681     while (1)
682     {
683         struct fml_node *fn_expr;
684         struct fml_node *rv;
685         if (!fn)
686             break;
687         fn_expr = fml_sub0 (fml, fn);
688         if (!fn_expr)
689             break;
690         fml_node_delete (fml, fn_expr);
691         rv = fml_exec_group (body, fml);
692         if (rv)
693             return_value = rv;
694     }
695     return return_value;
696 }
697
698 static void fml_exec_set (struct fml_sym_info *info, Fml fml,
699                     struct fml_node **lp, struct token *tp)
700 {
701     struct fml_node *fn;
702     struct fml_sym_info *info_var;
703     
704     fml_cmd_lex (lp, tp);
705     info_var = fml_sym_lookup_local (fml->sym_tab, tp->tokenbuf);
706     if (!info_var)
707     {
708         info_var = fml_sym_add_local (fml->sym_tab, tp->tokenbuf);
709         info_var->body = NULL;
710     }
711     if (fml->debug & 1)
712     {
713         pr_indent (1);
714         printf ("set %s ", tp->tokenbuf);
715     }
716     info_var->kind = FML_VAR;
717     fml_cmd_lex (lp, tp);
718
719     if (tp->kind == 'g')
720     {
721         fn = fml_sub0 (fml, tp->sub);
722         fml_cmd_lex (lp, tp);
723     }
724     else
725         fn = fml_sub2 (fml, lp, tp);
726     fml_node_delete (fml, info_var->body); 
727     info_var->body = fn;
728     if (fml->debug & 1)
729     {
730         fml_pr_list (info_var->body);
731         pr_indent (-1);
732     }
733 }
734
735 static void fml_emit_expr (Fml fml, struct fml_node **lp, struct token *tp)
736 {
737     struct fml_node *fn;
738
739     fn = fml_sub1 (fml, lp, tp);
740     fml_emit (fn);
741     fml_node_delete (fml, fn);
742 }
743
744 struct fml_node *fml_exec_group (struct fml_node *list, Fml fml)
745 {
746     struct token token;
747     struct fml_sym_info *info;
748     int first = 1;
749     struct fml_node *return_value = NULL, *rv;
750
751     if (!list)
752         return NULL;
753     fml_init_token (&token, fml);
754     fml_cmd_lex (&list, &token);
755     while (token.kind)
756     {
757         switch (token.kind)
758         {
759         case 'g':
760             rv = fml_exec_group (token.sub, fml);
761             if (rv)
762                 return_value = rv;
763             break;
764         case 'e':
765             info = fml_sym_lookup (fml->sym_tab, token.tokenbuf);
766             if (info)
767             {
768                 struct fml_node *fn;
769
770                 switch (info->kind)
771                 {
772                 case FML_FUNC:
773                     fml_cmd_lex (&list, &token);
774                     assert (token.kind == 't');
775                     info = fml_sym_lookup (fml->sym_tab, token.tokenbuf);
776                     if (!info)
777                         info = fml_sym_add (fml->sym_tab, token.tokenbuf);
778                     info->kind = FML_PREFIX;
779                     info->args = NULL;
780                     while (1)
781                     {
782                         fml_cmd_lex (&list, &token);
783                         if (token.kind != 't')
784                             break;
785                         if (!info->args)
786                         {
787                             info->args = fn = fml_node_alloc (fml);
788                         }
789                         else
790                         {
791                             for (fn = info->args; fn->p[1]; fn=fn->p[1])
792                                 ;
793                             fn = fn->p[1] = fml_node_alloc (fml);
794                         }
795                         fn->p[0] = token.atom;
796                         fn->is_atom = 1;
797                     }
798                     assert (token.kind == 'g');
799                     info->body = token.sub;
800                     break;
801                 case FML_BIN:
802                     fml_cmd_lex (&list, &token);
803                     assert (token.kind == 't');
804                     info = fml_sym_lookup (fml->sym_tab, token.tokenbuf);
805                     if (!info)
806                         info = fml_sym_add (fml->sym_tab, token.tokenbuf);
807                     info->kind = FML_BINARY;
808
809                     fml_cmd_lex (&list, &token);
810                     assert (token.kind == 't');
811                     info->args = fn = fml_node_alloc (fml);
812                     fn->p[0] = token.atom;
813                     fn->is_atom = 1;
814
815                     fml_cmd_lex (&list, &token);
816                     assert (token.kind == 't');
817                     fn = fn->p[1] = fml_node_alloc (fml);
818                     fn->p[0] = token.atom;
819                     fn->is_atom = 1;
820
821                     fml_cmd_lex (&list, &token);
822                     assert (token.kind == 'g');
823                     info->body = token.sub;
824                     break;
825                 case FML_VAR:
826                 case FML_PREFIX:
827                 case FML_CPREFIX:
828                     if (token.separate && !first)
829                         putchar (' ');
830                     first = 1;
831                     fml_emit_expr (fml, &list, &token);
832                     fml_node_stat (fml);
833                     continue;
834                 case FML_FOREACH:
835                     rv = fml_exec_foreach (info, fml, &list, &token);
836                     if (rv)
837                         return_value = rv;
838                     break;
839                 case FML_IF:
840                     rv = fml_exec_if (info, fml, &list, &token);
841                     if (rv)
842                         return_value = rv;
843                     continue;
844                 case FML_SET:
845                     fml_exec_set (info, fml, &list, &token);
846                     fml_node_stat (fml);
847                     continue;
848                 case FML_WHILE:
849                     rv = fml_exec_while (info, fml, &list, &token);
850                     if (rv)
851                         return_value = rv;
852                     break;
853                 case FML_RETURN:
854                     fml_cmd_lex (&list, &token);
855
856                     if (token.kind == 'g')
857                     {
858                         return_value = fml_sub0 (fml, token.sub);
859                         fml_cmd_lex (&list, &token);
860                     }
861                     else
862                         return_value = fml_sub2 (fml, &list, &token);
863                     if (fml->debug & 1)
864                     {
865                         pr_indent (1);
866                         printf ("return of:");
867                         fml_pr_list (return_value);
868                         pr_indent (-1);
869                     }
870                     continue;
871                 default:
872                     printf ("unknown token: `%s'", token.tokenbuf);
873                     fml_cmd_lex (&list, &token);
874                 }
875             }
876             else
877             {
878                 printf ("<unknown>");
879             }
880             break;
881         case 't':
882             if (token.separate && !first)
883                 putchar (' ');
884             first = 0;
885             fml_emit_expr (fml, &list, &token);
886             fml_node_stat (fml);
887             continue;
888         }
889         fml_cmd_lex (&list, &token);
890     }
891     fml_del_token (&token, fml);
892     return return_value;
893 }
894
895 void fml_exec (Fml fml)
896 {
897     fml_node_stat (fml);
898     fml_exec_group (fml->list, fml);
899     if (fml->debug & 1)
900         putchar ('\n');
901 }