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