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