Increase MAX_STATIC_DATA
[bazic.git] / interpreter.h
1 constant ESTATE_NEW -3;
2 constant ESTATE_QUIT -2;
3 constant ESTATE_DANGEROUS -1;
4 constant ESTATE_NORMAL 0;
5 constant ESTATE_ERROR 1;
6
7 constant TYPE_INT = 0;
8 constant TYPE_STRING = 1;
9
10 constant STACK_NONE = 0;
11 constant STACK_FOR = 1;
12 constant STACK_REPEAT = 2;
13 constant STACK_WHILE = 3;
14 constant STACK_GOSUB = 4;
15
16 constant STACK_SIZE = 16;
17 array stack_type table STACK_SIZE;
18 array stack_cmd table STACK_SIZE;
19 array stack_line table STACK_SIZE;
20 global stack_ptr = 1;
21
22 global cmd;
23 global program_ptr = 0;
24 global program_lineno;
25
26 ! An error has occurred.
27
28 [ error msg;
29         print "^", (string) msg;
30         if (program_ptr)
31                 print " at line ", program_lineno;
32         print ".^";
33 ];
34
35 ! Miscellaneous errors.
36
37 [ error_nomore;         error("Token didn't expect more input"); ];
38 [ error_typemismatch;   error("Type mismatch"); ];
39 [ error_missingopenp;   error("Missing open parenthesis"); ];
40 [ error_missingclosep;  error("Missing close parenthesis"); ];
41 [ error_syntaxerror;    error("Syntax error"); ];
42 [ error_outofmemory;    error("Out of memory"); ];
43 [ error_notrunning;     error("Not running a program"); ];
44 [ error_stackoverflow;  error("Stack overflow"); ];
45
46 ! End of statement token?
47
48 [ eos t;
49         return ((t == TOKEN__EOL) || (t == TOKEN__COLON));
50 ];
51
52 ! Skip white space.
53
54 [ skipwhite;
55         while (cmd->0 == TOKEN__SPACE)
56                 cmd++;
57 ];
58
59 ! Read and evaluate an lvalue.
60
61 [ eval_lvalue  varname i j val;
62         skipwhite();
63
64         varname = cmd;
65         while ((cmd++)->0);
66
67         skipwhite();
68         if (cmd->0 ~= TOKEN__LPAREN)
69         {
70                 ! It's not an array, so we can return the raw name.
71                 return strdup(varname);
72         }
73
74         cmd++;
75         val = eval_expression();
76         if (val == 0)
77                 return 0;
78         if (val-->0 ~= TYPE_INT)
79         {
80                 error_typemismatch();
81                 mem_free(val);
82                 return 0;
83         }
84         i = val-->1;
85         mem_free(val);
86         val = i;
87         
88         skipwhite();
89         if (cmd->0 == TOKEN__COMMA)
90         {
91                 mem_free(val);
92                 error("Multidimensional arrays are not supported");
93                 return 0;
94         }
95         if (cmd->0 ~= TOKEN__RPAREN)
96         {
97                 mem_free(val);
98                 error_syntaxerror();
99                 return 0;
100         }
101         cmd++;
102
103         i = strlen(varname);
104         j = mem_alloc(i+2);
105         strcpy(j, varname);
106         j->i = val;
107         j->(i+1) = 0;
108
109         return j;
110 ];
111
112 ! Read and evaluate a leaf expression.
113
114 [ eval_leaf  i j ret;
115         skipwhite();
116
117         i = ((cmd++)->0);
118         switch (i)
119         {
120                 TOKEN__NUMBER:
121                         ret = mem_alloc(4);
122                         ret-->0 = TYPE_INT;
123                         ret-->1 = cmd-->0;
124                         cmd = cmd + 2;
125                         return ret;
126
127                 TOKEN__STRING:
128                         ret = mem_alloc(4);
129                         ret-->0 = TYPE_STRING;
130                         ret-->1 = string_alloc(cmd+1, cmd->0);
131                         cmd = cmd + cmd->0 + 1;
132                         return ret;
133                         
134                 TOKEN__MINUS:
135                         ret = eval_leaf();
136                         if (ret-->0 ~= TYPE_INT)
137                         {
138                                 mem_free(ret);
139                                 error("Can only use - operator on strings");
140                                 return 0;
141                         }
142                         ret-->1 = -(ret-->1);
143                         return ret;
144
145                 TOKEN__VAR:
146                         i = cmd;
147                         while ((cmd++)->0);
148                         skipwhite();
149                         if (cmd->0 ~= TOKEN__LPAREN)
150                         {
151                                 ret = store_lookup(i);
152                                 if (ret == 0)
153                                 {
154                                         error("Variable not found");
155                                         return 0;
156                                 }
157                                 return ret;
158                         }
159                         cmd++;
160
161                         ret = eval_expression();
162                         if (ret == 0)
163                                 return 0;
164                         if (ret-->0 ~= TYPE_INT)
165                         {
166                                 mem_free(ret);
167                                 error_typemismatch();
168                                 return 0;
169                         }
170
171                         skipwhite();
172                         if ((cmd++)->0 ~= TOKEN__RPAREN)
173                         {
174                                 mem_free(ret);
175                                 error_syntaxerror();
176                                 return 0;
177                         }
178                         
179                         j = mem_alloc(2+cmd-i);
180                         strcpy(j, i);
181                         i = strlen(j);
182                         j->i = ret-->1;
183                         j->(i+1) = 0;
184                         mem_free(ret);
185
186                         ret = store_lookup(j);
187                         mem_free(j);
188                         if (ret == 0)
189                         {
190                                 error("Array or array index not found");
191                                 return 0;
192                         }
193                         return ret;
194                 
195                 TOKEN__LPAREN:
196                         ret = eval_expression();
197                         if (ret == 0)
198                                 return 0;
199                         if ((cmd++)->0 ~= TOKEN__RPAREN)
200                         {
201                                 error_missingclosep();
202                                 return 0;
203                         }
204                         return ret;
205
206                 ! Simple function.
207
208                 TOKEN_RND, TOKEN_VAL:
209                         skipwhite();
210                         if ((cmd++)->0 ~= TOKEN__LPAREN)
211                         {
212                                 error_missingopenp();
213                                 return 0;
214                         }
215                         ret = eval_expression();
216                         if (ret == 0)
217                                 return 0;
218                         if ((cmd++)->0 ~= TOKEN__RPAREN)
219                         {
220                                 error_missingclosep();
221                                 return 0;
222                         }
223
224                         switch (i)
225                         {
226                                 TOKEN_RND:
227                                         if (ret-->0 ~= TYPE_INT)
228                                         {
229                                                 error_typemismatch();
230                                                 mem_free(ret);
231                                                 return 0;
232                                         }
233
234                                         ret-->1 = random(ret-->1) - 1;
235                                         break;
236
237                                 TOKEN_VAL:
238                                         if (ret-->0 ~= TYPE_STRING)
239                                         {
240                                                 error_typemismatch();
241                                                 mem_free(ret);
242                                                 return 0;
243                                         }
244
245                                         ret-->0 = TYPE_INT;
246                                         ret-->1 = string_toint(ret-->1);
247                                         break;
248                         }
249
250                         return ret;
251         }
252
253         error("Botched leaf expression");
254         return 0;
255 ];
256
257 ! Evaluate an expression.
258
259 [ eval_expression  ret val i;
260         ret = eval_leaf();
261         if (ret == 0)
262                 return ret;
263         skipwhite();
264
265         i = cmd->0;
266         switch (i)
267         {
268                 TOKEN__EOL, TOKEN__COLON, TOKEN__SEMICOLON, TOKEN__COMMA, TOKEN__RPAREN,
269                 TOKEN_THEN, TOKEN_TO, TOKEN_STEP:
270                         return ret;
271
272                 ! Operators that can work on any type.
273
274                 TOKEN__PLUS, TOKEN__LARROW, TOKEN__RARROW, TOKEN__EQUALS, TOKEN__NEQUAL:
275                         cmd++;
276                         val = eval_expression();
277                         if (val == 0)
278                                 jump reterror;
279                         if (ret-->0 ~= val-->0)
280                                 jump typemismatch;
281
282                         switch (ret-->0)
283                         {
284                                 TYPE_INT:
285                                         switch (i)
286                                         {
287                                                 TOKEN__PLUS:
288                                                         ret-->1 = (ret-->1 + val-->1);
289                                                         break;
290
291                                                 TOKEN__LARROW:
292                                                         ret-->1 = (ret-->1 < val-->1);
293                                                         break;
294
295                                                 TOKEN__RARROW:
296                                                         ret-->1 = (ret-->1 > val-->1);
297                                                         break;
298
299                                                 TOKEN__EQUALS:
300                                                         ret-->1 = (ret-->1 == val-->1);
301                                                         break;
302
303                                                 TOKEN__NEQUAL:
304                                                         ret-->1 = (ret-->1 ~= val-->1);
305                                                         break;
306                                         }
307                                         break;
308
309                                 TYPE_STRING:
310                                         switch (i)
311                                         {
312                                                 TOKEN__EQUALS:
313                                                         ret-->0 = TYPE_INT;
314                                                         ret-->1 = (string_compare(ret-->1, val-->1) == 0);
315                                                         break;
316
317                                                 TOKEN__NEQUAL:
318                                                         ret-->0 = TYPE_INT;
319                                                         ret-->1 = (string_compare(ret-->1, val-->1) ~= 0);
320                                                         break;
321
322                                                 TOKEN__PLUS, TOKEN__LARROW, TOKEN__RARROW:
323                                                         error("Unimplemented opcode");
324                                                         jump valreterror;
325                                         }
326                                         break;
327                         }
328                         mem_free(val);
329                         break;
330
331                 ! Operators that only work on ints.
332                         
333                 TOKEN__MINUS, TOKEN__STAR, TOKEN__SLASH, TOKEN_AND, TOKEN_OR:
334                         cmd++;
335                         val = eval_expression();
336                         if (val == 0)
337                                 jump reterror;
338                         if ((ret-->0 ~= TYPE_INT) || (val-->0 ~= TYPE_INT))
339                                 jump typemismatch;
340
341                         switch (i)
342                         {
343                                 TOKEN__MINUS:
344                                         ret-->1 = ret-->1 - val-->1;
345                                         break;
346
347                                 TOKEN__STAR:
348                                         ret-->1 = ret-->1 * val-->1;
349                                         break;
350
351                                 TOKEN__SLASH:
352                                         if (val-->1 == 0)
353                                         {
354                                                 error("Division by zero");
355                                                 jump valreterror;
356                                         }
357                                         ret-->1 = ret-->1 / val-->1;
358                                         break;
359
360                                 TOKEN_AND:
361                                         ret-->1 = ret-->1 && val-->1;
362                                         break;
363
364                                 TOKEN_OR:
365                                         ret-->1 = ret-->1 || val-->1;
366                                         break;
367                         }
368                         mem_free(val);
369                         break;
370
371                 default:
372                         error("Botched complex expression");
373                         jump reterror;
374         }
375
376         return ret;
377
378 .typemismatch;
379         error_typemismatch();
380 .valreterror;
381         mem_free(val);
382 .reterror;
383         mem_free(ret);
384         return 0;
385 ];
386
387 ! List the current program.
388
389 [ cmd_list  val;
390         skipwhite();
391         if (eos(cmd->0) == 0)
392                 val = eval_expression();
393         else
394         {
395                 val = mem_alloc(4);
396                 val-->0 = TYPE_INT;
397                 val-->1 = 0;
398         }
399
400         if (val-->0 ~= TYPE_INT)
401         {
402                 error_typemismatch();
403                 mem_free(val);
404                 return ESTATE_ERROR;
405         }
406
407         switch (val-->1)
408         {
409                 -2:
410                         store_listvars();
411                         break;
412
413                 -1:
414                         store_listprogramhex();
415                         break;
416
417                 default:
418                         store_listprogram();
419                         break;
420         }
421
422         mem_free(val);
423         return ESTATE_NORMAL;
424 ];
425
426 ! Prints out an expression.
427
428 [ cmd_print  val;
429         while (1)
430         {
431                 skipwhite();
432                 if (eos(cmd->0))
433                 {
434                         print "^";
435                         break;
436                 }
437
438                 val = eval_expression();
439                 if (val == 0)
440                         return ESTATE_ERROR;
441                 switch (val-->0)
442                 {
443                         TYPE_INT:
444                                 print val-->1;
445                                 break;
446
447                         TYPE_STRING:
448                                 string_print(val-->1);
449                                 break;
450
451                         default:
452                                 mem_free(val);
453                                 error("Internal error --- invalid type in print!");
454                                 return ESTATE_ERROR;
455                 }
456                 mem_free(val);
457
458                 switch (cmd->0)
459                 {
460                         TOKEN__COMMA:
461                                 print " ";
462                                 cmd++;
463                                 break;
464
465                         TOKEN__SEMICOLON:
466                                 cmd++;
467                                 if (eos(cmd->0))
468                                         return ESTATE_NORMAL;
469                                 break;
470                 }
471         }
472
473         return ESTATE_NORMAL;
474 ];
475
476 ! Invoke a script.
477
478 [ cmd_script  val id;
479         skipwhite();
480         if (eos(cmd->0))
481         {
482                 script_list();
483                 return ESTATE_NORMAL;
484         }
485         val = eval_expression();
486         if (val == 0)
487                 return ESTATE_ERROR;
488         if (val-->0 ~= TYPE_INT)
489         {
490                 mem_free(val);
491                 jump typemismatch;
492         }
493         id = val-->1;
494         mem_free(val);
495         ! When we call this, it's entirely possible that the heap will be
496         ! trashed.
497         return script_invoke(id);
498
499 .typemismatch;
500         error_typemismatch();
501         return ESTATE_ERROR;
502 ];
503
504 ! Variable assignment.
505
506 [ cmd_varassignment  varname val;
507         varname = eval_lvalue();
508         if (varname == 0)
509                 return ESTATE_ERROR;
510         skipwhite();
511
512         if ((cmd++)->0 ~= TOKEN__EQUALS)
513         {
514                 mem_free(varname);
515                 error("Unrecognised keyword");
516                 return ESTATE_ERROR;
517         }
518         skipwhite();
519
520         val = eval_expression();
521         if (val == 0)
522         {
523                 mem_free(varname);
524                 return ESTATE_ERROR;
525         }
526
527         store_assign(varname, val-->0, val-->1);
528         mem_free(varname);
529         mem_free(val);
530
531         return ESTATE_NORMAL;
532 ];
533         
534 ! Run the program.
535
536 [ cmd_run  i p;
537         cmd_clear();
538         stack_ptr = 1;
539         stack_type-->1 = STACK_NONE;
540         program_ptr = store_bottom;
541         
542         ! As the program is already tokenised, we can directly run the
543         ! bytecode in the store.
544
545         do {
546                 ! Reached the end of the program?
547
548                 if (program_ptr->0 == 0)
549                 {
550                         i = ESTATE_NORMAL;
551                         break;
552                 }
553
554                 ! Read in the line number and execute the line..
555
556                 p = program_ptr + 1;
557                 program_ptr = program_ptr + program_ptr->0;
558                 program_lineno = p-->0;
559                 p++;
560
561                 ! Execute the line. Remember execute_command needs to be
562                 ! pointed at the byte *before* the bytecode...
563
564                 i = execute_command(p);
565         } until (i ~= ESTATE_NORMAL);
566
567         program_ptr = 0;
568         return i;
569 ];
570
571 ! Read in a string.
572
573 [ cmd_input  val varname buf;
574         skipwhite();
575
576         ! Is there a label?
577
578         if (cmd->0 == TOKEN__STRING)
579         {
580                 val = eval_leaf();
581                 if (val == 0)
582                         return ESTATE_ERROR;
583                 if (val-->0 == TYPE_STRING)
584                         string_print(val-->1);
585                 else
586                 {
587                         error_typemismatch();
588                         mem_free(val);
589                         return ESTATE_ERROR;
590                 }
591                 mem_free(val);
592
593                 skipwhite();
594                 switch (cmd->0)
595                 {
596                         TOKEN__COMMA:
597                                 print " ";
598                                 break;
599
600                         TOKEN__SEMICOLON:
601                                 break;
602
603                         default:
604                                 error_syntaxerror();
605                                 return ESTATE_ERROR;
606                 }
607                 cmd++;
608
609                 skipwhite();
610         }
611         else
612                 print "? ";
613
614         ! Get the variable name to put the result into.
615
616         if ((cmd++)->0 ~= TOKEN__VAR)
617         {
618                 error_syntaxerror();
619                 return ESTATE_ERROR;
620         }
621         varname = eval_lvalue();
622         if (varname == 0)
623                 return ESTATE_ERROR;
624
625         ! Get the user's input.
626
627         buf = mem_alloc(255);
628         if (buf == 0)
629         {
630                 mem_free(varname);
631                 error_outofmemory();
632                 return ESTATE_ERROR;
633         }
634
635         buf->0 = 255;
636         read buf 0;
637
638         ! Assign to the variable.
639
640         store_assign(varname, TYPE_STRING, string_alloc(buf+2, buf->1));
641
642         ! Free the temporary buffer.
643
644         mem_free(varname);
645         mem_free(buf);
646
647         return ESTATE_NORMAL;
648 ];
649
650 ! Jump to a line number.
651
652 [ cmd_goto  val i;
653         if (program_ptr == 0)
654         {
655                 error_notrunning();
656                 return ESTATE_ERROR;
657         }
658
659         val = eval_expression();
660         if (val == 0)
661                 return ESTATE_ERROR;
662         if (val-->0 ~= TYPE_INT)
663         {
664                 mem_free(val);
665                 error_typemismatch();
666                 return ESTATE_ERROR;
667         }
668
669         i = store_findline(val-->1);
670         mem_free(val);
671         if (i == 0)
672         {
673                 error("No such line number");
674                 return ESTATE_ERROR;
675         }
676
677         program_ptr = i;
678         return ESTATE_NORMAL;
679 ];
680
681                 
682 ! Conditional execution.
683
684 [ cmd_if  val;
685         val = eval_expression();
686         if (val == 0)
687                 return ESTATE_ERROR;
688         skipwhite();
689         if ((cmd++)->0 ~= TOKEN_THEN)
690         {
691                 mem_free(val);
692                 error_syntaxerror();
693                 return ESTATE_ERROR;
694         }
695
696         if ((val-->0 == TYPE_INT) && (val-->1 == 0))
697                 cmd = 0;
698         
699         mem_free(val);
700         return ESTATE_NORMAL;
701 ];
702                 
703 ! Top half of a FOR loop.
704
705 [ cmd_for  varname val initialval targetval stepval cmdptr;
706         ! FOR can only be used when running a program.
707
708         if (program_ptr == 0)
709         {
710                 error_notrunning();
711                 return ESTATE_ERROR;
712         }
713
714         ! Store the address of the FOR instruction.
715
716         cmdptr = cmd-1;
717
718         ! Read the variable name.
719
720         skipwhite();
721         if ((cmd++)->0 ~= TOKEN__VAR)
722         {
723                 error_syntaxerror();
724                 return ESTATE_ERROR;
725         }
726         varname = eval_lvalue();
727         if (varname == 0)
728                 return ESTATE_ERROR;
729
730         ! Skip over the =.
731
732         skipwhite();
733         if ((cmd++)->0 ~= TOKEN__EQUALS)
734         {
735                 error_syntaxerror();
736                 jump varnameexit;
737         }
738
739         ! Read the initial value.
740
741         val = eval_expression();
742         if (val == 0)
743                 jump varnameexit;
744         if (val-->0 ~= TYPE_INT)
745         {
746                 error_typemismatch();
747                 jump varnameexit;
748         }
749         initialval = val-->1;
750         mem_free(val);
751
752         ! Read the TO.
753
754         skipwhite();
755         if ((cmd++)->0 ~= TOKEN_TO)
756         {
757                 error_syntaxerror();
758                 return ESTATE_ERROR;
759         }
760
761         ! Read the target value.
762
763         val = eval_expression();
764         if (val == 0)
765                 jump varnameexit;
766         if (val-->0 ~= TYPE_INT)
767         {
768                 error_typemismatch();
769                 jump varnameexit;
770         }
771         targetval = val-->1;
772         mem_free(val);
773         
774         ! Is there a STEP clause?
775
776         skipwhite();
777         if (cmd->0 == TOKEN_STEP)
778         {
779                 cmd++;
780                 skipwhite();
781
782                 ! Read the STEP value.
783
784                 val = eval_expression();
785                 if (val == 0)
786                         jump varnameexit;
787                 if (val-->0 ~= TYPE_INT)
788                 {
789                         error_typemismatch();
790                         jump valexit;
791                 }
792                 stepval = val-->1;
793                 mem_free(val);
794         }
795         else
796         {
797                 ! Otherwise, default to 1.
798
799                 stepval = 1;
800         }
801
802         ! Is this a new loop?
803
804         if (stack_type-->stack_ptr == STACK_NONE)
805         {
806                 ! Yes. Ensure there's room on the stack.
807
808                 if ((stack_ptr+1) >= STACK_SIZE)
809                 {
810                         error_stackoverflow();
811                         jump varnameexit;
812                 }
813                 stack_ptr-->stack_type = STACK_NONE;
814
815                 ! ...and set the initial value.
816
817                 store_assign(varname, TYPE_INT, initialval);
818         }
819         else
820         {
821                 ! Otherwise, load the loop counter.
822
823                 val = store_lookup(varname);
824                 if (val == 0)
825                 {
826                         error("FOR loop counter has disappeared");
827                         jump varnameexit;
828                 }
829                 if (val-->0 ~= TYPE_INT)
830                 {
831                         error_typemismatch();
832                         jump valexit;
833                 }
834                 initialval = val-->1;
835                 mem_free(val);
836
837                 ! Increment it.
838
839                 initialval = initialval + stepval;
840
841                 ! Test.
842
843                 if (((stepval < 0) && (initialval < targetval)) ||
844                     ((stepval >= 0) && (initialval > targetval)))
845                 {
846                         ! Abort! The NEXT keyword has placed the pointer to
847                         ! to the next instruction after the loop on the stack.
848
849                         cmd = stack_cmd-->stack_ptr;
850                         program_ptr = stack_line-->stack_ptr;
851                         stack_type-->stack_ptr = 0;
852                         return ESTATE_NORMAL;
853                 }
854                 else
855                 {
856                         ! Write back the new loop counter.
857
858                         store_assign(varname, TYPE_INT, initialval);
859                 }
860         }
861
862         mem_free(varname);
863         stack_type-->stack_ptr = STACK_FOR;
864         stack_cmd-->stack_ptr = cmdptr;
865         stack_line-->stack_ptr = program_ptr;
866         stack_ptr++;
867         return ESTATE_NORMAL;
868
869 .valexit;
870         mem_free(val);
871 .varnameexit;
872         mem_free(varname);
873         return ESTATE_ERROR;
874 ];
875
876 ! Bottom half of a FOR loop.
877
878 [ cmd_next  i j;
879         ! NEXT can only be used when running a program.
880
881         if (program_ptr == 0)
882         {
883                 error_notrunning();
884                 return ESTATE_ERROR;
885         }
886
887         stack_ptr--;
888         if ((stack_ptr == 0) || (stack_type-->stack_ptr ~= STACK_FOR))
889         {
890                 error("NEXT without FOR");
891                 return ESTATE_ERROR;
892         }
893
894         i = stack_cmd-->stack_ptr;
895         j = stack_line-->stack_ptr;
896         stack_cmd-->stack_ptr = cmd;
897         stack_line-->stack_ptr = program_ptr;
898         cmd = i;
899         program_ptr = j;
900
901         return ESTATE_NORMAL;
902 ];
903
904 ! Top half of a REPEAT..UNTIL loop.
905
906 [ cmd_repeat;
907         ! REPEAT can only be used when running a program.
908
909         if (program_ptr == 0)
910         {
911                 error_notrunning();
912                 return ESTATE_ERROR;
913         }
914
915         if ((stack_ptr+1) >= STACK_SIZE)
916         {
917                 error_stackoverflow();
918                 return ESTATE_ERROR;
919         }
920
921         stack_type-->stack_ptr = STACK_REPEAT;
922         stack_cmd-->stack_ptr = cmd+1;
923         stack_line-->stack_ptr = program_ptr;
924         stack_ptr++;
925         return ESTATE_NORMAL;
926 ];
927
928 ! Bottom half of a REPEAT..UNTIL loop.
929
930 [ cmd_until  val;
931         ! REPEAT can only be used when running a program.
932
933         if (program_ptr == 0)
934         {
935                 error_notrunning();
936                 return ESTATE_ERROR;
937         }
938
939         stack_ptr--;
940         if ((stack_ptr == 0) || (stack_type-->stack_ptr ~= STACK_REPEAT))
941         {
942                 error("UNTIL without REPEAT");
943                 return ESTATE_ERROR;
944         }
945
946         val = eval_expression();
947         if (val == 0)
948                 return ESTATE_ERROR;
949         if (val-->0 ~= TYPE_INT)
950         {
951                 mem_free(val);
952                 error_typemismatch();
953                 return ESTATE_ERROR;
954         }
955
956         if (val-->1 == 0)
957         {
958                 cmd = stack_cmd-->stack_ptr;
959                 program_ptr = stack_line-->stack_ptr;
960                 stack_ptr++;
961         }
962         else
963                 stack_type-->stack_ptr = STACK_NONE;
964         
965         return ESTATE_NORMAL;
966 ];
967
968 ! Execute a command.
969
970 [ execute_command _cmd  i;
971         cmd = _cmd;
972         cmd++;
973         while (1)
974         {
975                 i = (cmd++)->0;
976
977                 switch (i)
978                 {
979                         TOKEN__EOL:     return ESTATE_NORMAL;
980                         TOKEN__SPACE:   continue;
981
982                         TOKEN__NUMBER:
983                                 i = cmd-->0;
984                                 cmd = cmd + 2;
985                                 if (store_addline(i, cmd, _cmd->0 - 4))
986                                         return ESTATE_ERROR;
987                                 ! Don't execute anything else on this line.
988                                 return ESTATE_DANGEROUS;
989                                 
990                         TOKEN__VAR:
991                                 i = cmd_varassignment();
992                                 jump checkresult;
993
994                         TOKEN_CLEAR:
995                                 i = cmd_clear();
996                                 jump checkresult;
997
998                         TOKEN_CLS:
999                                 @erase_window -1;
1000                                 break;
1001                                 
1002                         TOKEN_FOR:
1003                                 i = cmd_for();
1004                                 jump checkresult;
1005
1006                         TOKEN_GOTO:
1007                                 i = cmd_goto();
1008                                 jump checkresult;
1009
1010                         TOKEN_IF:
1011                                 i = cmd_if();
1012                                 if (i ~= ESTATE_NORMAL)
1013                                         return i;
1014                                 if (cmd == 0)
1015                                         return ESTATE_NORMAL;
1016                                 continue;
1017
1018                         TOKEN_INPUT:
1019                                 i = cmd_input();
1020                                 jump checkresult;
1021
1022                         TOKEN_LIST:
1023                                 i = cmd_list();
1024                                 jump checkresult;
1025
1026                         TOKEN_LOAD:
1027                                 restore endofstatement;
1028                                 error("Load failed");
1029                                 return ESTATE_ERROR;
1030
1031                         TOKEN_NEW:
1032                                 return ESTATE_NEW;
1033
1034                         TOKEN_NEXT:
1035                                 i = cmd_next();
1036                                 if (i == ESTATE_NORMAL)
1037                                         continue;
1038                                 return i;
1039
1040                         TOKEN_PRINT:
1041                                 i = cmd_print();
1042                                 jump checkresult;
1043
1044                         TOKEN_QUIT:
1045                                 error("Quit");
1046                                 return ESTATE_QUIT;
1047
1048                         TOKEN_REPEAT:
1049                                 i = cmd_repeat();
1050                                 jump checkresult;
1051                                 
1052                         TOKEN_RUN:
1053                                 i = cmd_run();
1054                                 return i;
1055
1056                         TOKEN_SAVE:
1057                                 save endofstatement;
1058                                 error("Save failed");
1059                                 return ESTATE_ERROR;
1060
1061                         TOKEN_SCRIPT:
1062                                 i = cmd_script();
1063                                 jump checkresult;
1064
1065                         TOKEN_STOP:
1066                                 error("Stop");
1067                                 return ESTATE_ERROR;
1068
1069                         TOKEN_UNTIL:
1070                                 i = cmd_until();
1071                                 if (i ~= ESTATE_ERROR)
1072                                         return i;
1073                                 continue;
1074                                 jump checkresult;
1075
1076                         default:
1077                                 error("Unimplemented token");
1078                                 return ESTATE_ERROR;
1079
1080                         .checkresult;
1081                                 if (i == ESTATE_ERROR)
1082                                         return ESTATE_ERROR;
1083                                 break;
1084                 }
1085
1086         .endofstatement;
1087                 if (eos(cmd->0) == 0)
1088                 {
1089                         error_nomore();
1090                         return ESTATE_ERROR;
1091                 }
1092
1093                 if (cmd->0 == TOKEN__COLON)
1094                         cmd++;
1095         }
1096         
1097         return ESTATE_NORMAL;
1098 ];
1099