"Fossies" - the Fresh Open Source Software Archive

Member "bas-2.6/bas.c" (2 Jul 2019, 34819 Bytes) of package /linux/privat/bas-2.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "bas.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.5_vs_2.6.

    1 /* #includes */ /*{{{C}}}*//*{{{*/
    2 #include "config.h"
    3 
    4 #include <sys/stat.h>
    5 #include <sys/types.h>
    6 #include <sys/wait.h>
    7 #include <assert.h>
    8 #include <ctype.h>
    9 #include <errno.h>
   10 #include <fcntl.h>
   11 #ifdef HAVE_GETTEXT
   12 #include <libintl.h>
   13 #define _(String) gettext(String)
   14 #else
   15 #define _(String) String
   16 #endif
   17 #include <limits.h>
   18 #include <math.h>
   19 #include <string.h>
   20 #include <stdlib.h>
   21 #include <stdio.h>
   22 #include <time.h>
   23 #include <unistd.h>
   24 
   25 #include "getopt.h"
   26 
   27 #include "auto.h"
   28 #include "bas.h"
   29 #include "error.h"
   30 #include "fs.h"
   31 #include "global.h"
   32 #include "program.h"
   33 #include "value.h"
   34 #include "var.h"
   35 
   36 #ifdef USE_DMALLOC
   37 #include "dmalloc.h"
   38 #endif
   39 /*}}}*/
   40 /* #defines */ /*{{{*/
   41 #define DIRECTMODE (pc.line==-1)
   42 #ifndef __GNUC__
   43 #define inline
   44 #endif
   45 /*}}}*/
   46 
   47 /* types */ /*{{{*/
   48 enum LabelType
   49 {
   50   L_IF=1,
   51   L_ELSE,
   52   L_DO,
   53   L_DOcondition,
   54   L_FOR,
   55   L_FOR_VAR,
   56   L_FOR_LIMIT,
   57   L_FOR_BODY,
   58   L_REPEAT,
   59   L_SELECTCASE,
   60   L_WHILE,
   61   L_FUNC
   62 };
   63 
   64 struct LabelStack
   65 {
   66   enum LabelType type;
   67   struct Pc patch;
   68 };
   69 /*}}}*/
   70 /* variables */ /*{{{*/
   71 static unsigned int labelStackPointer,labelStackCapacity;
   72 static struct LabelStack *labelStack;
   73 static struct Pc *lastdata;
   74 static struct Pc curdata;
   75 static struct Pc nextdata;
   76 static enum { DECLARE, COMPILE, INTERPRET } pass;
   77 static int stopped;
   78 static long int optionbase;
   79 static struct Pc pc;
   80 static struct Auto stack;
   81 static struct Program program;
   82 static struct Global globals;
   83 static int run_restricted;
   84 
   85 int bas_argc;
   86 char *bas_argv0;
   87 char **bas_argv;
   88 int bas_end;
   89 /*}}}*/
   90 /* forward prototypes */ /*{{{*/
   91 static struct Value *statements(struct Value *value);
   92 static struct Value *compileProgram(struct Value *v, int clearGlobals);
   93 static struct Value *eval(struct Value *value, const char *desc);
   94 /*}}}*/
   95 
   96 static char *mytmpnam(void) /*{{{*/
   97 {
   98   static char buf[_POSIX_PATH_MAX];
   99   const char *tmpdir;  
  100   unsigned int i;
  101   int fd=-1;
  102 
  103   if ((tmpdir=getenv("TMPDIR"))==(char*)0) tmpdir="/tmp";
  104   if ((strlen(tmpdir)+1+8+1)>=_POSIX_PATH_MAX) return (char*)0;
  105   i=getpid();
  106   while (i<0xffffffff && (snprintf(buf,sizeof(buf),"%s/%08x",tmpdir,i),(fd=open(buf,O_RDWR|O_CREAT|O_EXCL,0600)))==-1 && errno==EEXIST) ++i;
  107   if (fd==-1) return (char*)0;
  108   close(fd);
  109   return buf;
  110 }
  111 /*}}}*/
  112 static int cat(const char *filename) /*{{{*/
  113 {
  114   int fd;
  115   char buf[4096];
  116   ssize_t l;
  117   int err;
  118 
  119   if ((fd=open(filename,O_RDONLY))==-1) return -1;
  120   while ((l=read(fd,buf,sizeof(buf)))>0)
  121   {
  122     ssize_t off,w;
  123 
  124     off=0;
  125     while (off<l)
  126     {
  127       if ((w=write(1,buf+off,l-off))==-1)
  128       {
  129         err=errno;
  130         close(fd);
  131         errno=err;
  132         return -1;
  133       }
  134       off+=w;
  135     }
  136   }
  137   if (l==-1)
  138   {
  139     err=errno;
  140     close(fd);
  141     errno=err;
  142     return -1;
  143   }
  144   close(fd);
  145   return 0;
  146 }
  147 /*}}}*/
  148 static struct Value *lvalue(struct Value *value) /*{{{*/
  149 {
  150   struct Symbol *sym;
  151   struct Pc lvpc=pc;
  152 
  153   sym=pc.token->u.identifier->sym;
  154   assert(pass==DECLARE || sym->type==GLOBALVAR || sym->type==GLOBALARRAY || sym->type==LOCALVAR);
  155   if ((pc.token+1)->type==T_OP)
  156   {
  157     struct Pc idxpc;
  158     unsigned int dim,capacity;
  159     int *idx;
  160 
  161     pc.token+=2;
  162     dim=0;
  163     capacity=0;
  164     idx=(int*)0;
  165     while (1)
  166     {
  167       if (dim==capacity && pass==INTERPRET) /* enlarge idx */ /*{{{*/
  168       {
  169         int *more;
  170 
  171         more=realloc(idx,sizeof(unsigned int)*(capacity?(capacity*=2):(capacity=3)));
  172         if (!more)
  173         {
  174           if (capacity) free(idx);
  175           return Value_new_ERROR(value,OUTOFMEMORY);
  176         }
  177         idx=more;
  178       }
  179       /*}}}*/
  180       idxpc=pc;
  181       if (eval(value,_("index"))->type==V_ERROR || VALUE_RETYPE(value,V_INTEGER)->type==V_ERROR)
  182       {
  183         if (capacity) free(idx);
  184         pc=idxpc;
  185         return value;
  186       }
  187       if (pass==INTERPRET)
  188       {
  189         idx[dim]=value->u.integer;
  190         ++dim;
  191       }
  192       Value_destroy(value);
  193       if (pc.token->type==T_COMMA) ++pc.token;
  194       else break;
  195     }
  196     if (pc.token->type!=T_CP)
  197     {
  198       assert(pass!=INTERPRET);
  199       return Value_new_ERROR(value,MISSINGCP);
  200     }
  201     else ++pc.token;
  202     switch (pass)
  203     {
  204       case INTERPRET:
  205       {
  206         if ((value=Var_value(&(sym->u.var),dim,idx,value))->type==V_ERROR) pc=lvpc;
  207         free(idx);
  208         return value;
  209       }
  210       case DECLARE:
  211       {
  212         return Value_nullValue(V_INTEGER);
  213       }
  214       case COMPILE:
  215       {
  216         return Value_nullValue(sym->type==GLOBALARRAY ? sym->u.var.type : Auto_varType(&stack,sym));
  217       }
  218       default: assert(0);
  219     }
  220     return (struct Value*)0;
  221   }
  222   else
  223   {
  224     ++pc.token;
  225     switch (pass)
  226     {
  227       case INTERPRET: return VAR_SCALAR_VALUE(sym->type==GLOBALVAR ? &(sym->u.var) : Auto_local(&stack,sym->u.local.offset));
  228       case DECLARE: return Value_nullValue(V_INTEGER);
  229       case COMPILE: return Value_nullValue(sym->type==GLOBALVAR? sym->u.var.type : Auto_varType(&stack,sym));
  230       default: assert(0);
  231     }
  232     return (struct Value*)0;
  233   }
  234 }
  235 /*}}}*/
  236 static struct Value *func(struct Value *value) /*{{{*/
  237 {
  238   struct Identifier *ident;
  239   struct Pc funcpc=pc;
  240   int firstslot=-99;
  241   int args=0;
  242   struct Symbol *sym;
  243 
  244   assert(pc.token->type==T_IDENTIFIER);
  245   /*
  246   Evaluating a function in direct mode may start a program, so it needs to
  247   be compiled.  If in direct mode, programs will be compiled after the
  248   direct mode pass DECLARE, but errors are ignored at that point, because
  249   the program may not be needed.  If the program is fine, its symbols will
  250   be available during the compile phase already.  If not and we need it
  251   at this point, compile it again to get the error and abort.
  252   */
  253   if (DIRECTMODE && !program.runnable && pass!=DECLARE)
  254   {
  255     if (compileProgram(value,0)->type==V_ERROR) return value;
  256     Value_destroy(value);
  257   }
  258   ident=pc.token->u.identifier;
  259   assert(pass==DECLARE || ident->sym->type==BUILTINFUNCTION || ident->sym->type==USERFUNCTION);
  260   ++pc.token;
  261   if (pass!=DECLARE)
  262   {
  263     firstslot=stack.stackPointer;
  264     if (ident->sym->type==USERFUNCTION && ident->sym->u.sub.retType!=V_VOID)
  265     {
  266       struct Var *v=Auto_pushArg(&stack);
  267       Var_new(v,ident->sym->u.sub.retType,0,(const unsigned int*)0,0);
  268     }
  269   }
  270   if (pc.token->type==T_OP) /* push arguments to stack */ /*{{{*/
  271   {
  272     ++pc.token;
  273     if (pc.token->type!=T_CP) while (1)
  274     {
  275       if (pass==DECLARE)
  276       {
  277         if (eval(value,_("actual parameter"))->type==V_ERROR) return value;
  278         Value_destroy(value);
  279       }
  280       else
  281       {
  282         struct Var *v=Auto_pushArg(&stack);
  283 
  284         Var_new_scalar(v);
  285         if (eval(v->value,(const char*)0)->type==V_ERROR)
  286         {
  287           Value_clone(value,v->value);
  288           while (stack.stackPointer>firstslot) Var_destroy(&stack.slot[--stack.stackPointer].var);
  289           return value;
  290         }
  291         v->type=v->value->type;
  292       }
  293       ++args;
  294       if (pc.token->type==T_COMMA) ++pc.token;
  295       else break;
  296     }
  297     if (pc.token->type!=T_CP)
  298     {
  299       if (pass!=DECLARE)
  300       {
  301         while (stack.stackPointer>firstslot) Var_destroy(&stack.slot[--stack.stackPointer].var);
  302       }
  303       return Value_new_ERROR(value,MISSINGCP);
  304     }
  305     ++pc.token;
  306   }
  307   /*}}}*/
  308   if (pass==DECLARE) Value_new_null(value,ident->defaultType);
  309   else
  310   {
  311     int i;
  312     int nomore;
  313     int argerr;
  314     int overloaded;
  315 
  316     if (pass==INTERPRET && ident->sym->type==USERFUNCTION)
  317     {
  318       for (i=0; i<ident->sym->u.sub.u.def.localLength; ++i)
  319       {
  320         struct Var *v=Auto_pushArg(&stack);
  321         Var_new(v,ident->sym->u.sub.u.def.localTypes[i],0,(const unsigned int*)0,0);
  322       }
  323     }
  324     Auto_pushFuncRet(&stack,firstslot,&pc);
  325 
  326     sym=ident->sym;
  327     overloaded=(pass==COMPILE && sym->type==BUILTINFUNCTION && sym->u.sub.u.bltin.next);
  328     do
  329     {
  330       nomore=(pass==COMPILE && !(sym->type==BUILTINFUNCTION && sym->u.sub.u.bltin.next));
  331       argerr=0;
  332       if (args<sym->u.sub.argLength) /*{{{*/
  333       {
  334         if (nomore) Value_new_ERROR(value,TOOFEW);
  335         argerr=1;
  336       }
  337       /*}}}*/
  338       else if (args>sym->u.sub.argLength) /*{{{*/
  339       {
  340         if (nomore) Value_new_ERROR(value,TOOMANY);
  341         argerr=1;
  342       }
  343       /*}}}*/
  344       else /*{{{*/
  345       {
  346         for (i=0; i<args; ++i)
  347         {
  348           struct Value *arg=Var_value(Auto_local(&stack,i),0,(int*)0,value);
  349 
  350           assert(arg->type!=V_ERROR);
  351           if (overloaded)
  352           {
  353             if (arg->type!=sym->u.sub.argTypes[i])
  354             {
  355               if (nomore) Value_new_ERROR(value,TYPEMISMATCH2,i+1);
  356               argerr=1;
  357               break;
  358             }
  359           }
  360           else if (Value_retype(arg,sym->u.sub.argTypes[i])->type==V_ERROR)
  361           {
  362             if (nomore) Value_new_ERROR(value,TYPEMISMATCH3,arg->u.error.msg,i+1);
  363             argerr=1;
  364             break;
  365           }
  366         }
  367       }
  368       /*}}}*/
  369       if (argerr)
  370       {
  371         if (nomore)
  372         {
  373           Auto_funcReturn(&stack,(struct Pc*)0);
  374           pc=funcpc;
  375           return value;
  376         }
  377         else sym=sym->u.sub.u.bltin.next;
  378       }
  379     } while (argerr);
  380     ident->sym=sym;
  381     if (sym->type==BUILTINFUNCTION)
  382     {
  383       if (pass==INTERPRET)
  384       {
  385         if (sym->u.sub.u.bltin.call(value,&stack)->type==V_ERROR) pc=funcpc;
  386       }
  387       else Value_new_null(value,sym->u.sub.retType);
  388     }
  389     else if (sym->type==USERFUNCTION)
  390     {
  391       if (pass==INTERPRET)
  392       {
  393         int r=1;
  394 
  395         pc=sym->u.sub.u.def.scope.start;
  396         if (pc.token->type==T_COLON) ++pc.token;
  397         else Program_skipEOL(&program,&pc,STDCHANNEL,1);
  398         do
  399         {
  400           if (statements(value)->type==V_ERROR)
  401           {
  402             if (strchr(value->u.error.msg,'\n')==(char*)0)
  403             {
  404               Auto_setError(&stack,Program_lineNumber(&program,&pc),&pc,value);
  405               Program_PCtoError(&program,&pc,value);
  406             }
  407             if (stack.onerror.line!=-1)
  408             {
  409               stack.resumeable=1;
  410               pc=stack.onerror;
  411             }
  412             else
  413             {
  414               Auto_frameToError(&stack,&program,value);
  415               break;
  416             }
  417           }
  418           else if (value->type!=V_NIL) break;
  419           Value_destroy(value);
  420         } while ((r=Program_skipEOL(&program,&pc,STDCHANNEL,1)));
  421         if (!r) Value_new_VOID(value);
  422       }
  423       else Value_new_null(value,sym->u.sub.retType);
  424     }
  425     Auto_funcReturn(&stack,pass==INTERPRET && value->type!=V_ERROR ? &pc : (struct Pc*)0);
  426   }
  427   return value;
  428 }
  429 /*}}}*/
  430 
  431 static inline struct Value *binarydown(struct Value *value, struct Value *(level)(struct Value *value), const int prio) /*{{{*/
  432 {
  433   enum TokenType op;
  434   struct Pc oppc;
  435 
  436   if (level(value)==(struct Value*)0) return (struct Value*)0;
  437   if (value->type==V_ERROR) return value;
  438   do
  439   {
  440     struct Value x;
  441 
  442     op=pc.token->type;
  443     if (!TOKEN_ISBINARYOPERATOR(op) || TOKEN_BINARYPRIORITY(op)!=prio) return value;
  444     oppc=pc;
  445     ++pc.token;
  446     if (level(&x)==(struct Value*)0)
  447     {
  448       Value_destroy(value);
  449       return Value_new_ERROR(value,MISSINGEXPR,_("binary operand"));
  450     }
  451     if (x.type==V_ERROR)
  452     {
  453       Value_destroy(value);
  454       *value=x;
  455       return value;
  456     }
  457     if (Value_commonType[value->type][x.type]==V_ERROR)
  458     {
  459       Value_destroy(value);
  460       Value_destroy(&x);
  461       return Value_new_ERROR(value,INVALIDOPERAND);
  462     }
  463     else switch (op)
  464     {
  465       case T_LT:    Value_lt(value,&x,pass==INTERPRET);   break;
  466       case T_LE:    Value_le(value,&x,pass==INTERPRET);   break;
  467       case T_EQ:    Value_eq(value,&x,pass==INTERPRET);   break;
  468       case T_GE:    Value_ge(value,&x,pass==INTERPRET);   break;
  469       case T_GT:    Value_gt(value,&x,pass==INTERPRET);   break;
  470       case T_NE:    Value_ne(value,&x,pass==INTERPRET);   break;
  471       case T_PLUS:  Value_add(value,&x,pass==INTERPRET);  break;
  472       case T_MINUS: Value_sub(value,&x,pass==INTERPRET);  break;
  473       case T_MULT:  Value_mult(value,&x,pass==INTERPRET); break;
  474       case T_DIV:   Value_div(value,&x,pass==INTERPRET);  break;
  475       case T_IDIV:  Value_idiv(value,&x,pass==INTERPRET); break;
  476       case T_MOD:   Value_mod(value,&x,pass==INTERPRET);  break;
  477       case T_POW:   Value_pow(value,&x,pass==INTERPRET);  break;
  478       case T_AND:   Value_and(value,&x,pass==INTERPRET);  break;
  479       case T_OR:    Value_or(value,&x,pass==INTERPRET);   break;
  480       case T_XOR:   Value_xor(value,&x,pass==INTERPRET);  break;
  481       case T_EQV:   Value_eqv(value,&x,pass==INTERPRET);  break;
  482       case T_IMP:   Value_imp(value,&x,pass==INTERPRET);  break;
  483       default:      assert(0);
  484     }
  485     Value_destroy(&x);
  486   } while (value->type!=V_ERROR);
  487   if (value->type==V_ERROR) pc=oppc;
  488   return value;
  489 }
  490 /*}}}*/
  491 static inline struct Value *unarydown(struct Value *value, struct Value *(level)(struct Value *value), const int prio) /*{{{*/
  492 {
  493   enum TokenType op;
  494   struct Pc oppc;
  495 
  496   op=pc.token->type;
  497   if (!TOKEN_ISUNARYOPERATOR(op) || TOKEN_UNARYPRIORITY(op)!=prio) return level(value);
  498   oppc=pc;
  499   ++pc.token;
  500   if (unarydown(value,level,prio)==(struct Value*)0) return Value_new_ERROR(value,MISSINGEXPR,_("unary operand"));
  501   if (value->type==V_ERROR) return value;
  502   switch (op)
  503   {
  504     case T_PLUS:  Value_uplus(value,pass==INTERPRET); break;
  505     case T_MINUS: Value_uneg(value,pass==INTERPRET);  break;
  506     case T_NOT:   Value_unot(value,pass==INTERPRET);  break;
  507     default:      assert(0);
  508   }
  509   if (value->type==V_ERROR) pc=oppc;
  510   return value;
  511 }
  512 /*}}}*/
  513 static struct Value *eval8(struct Value *value) /*{{{*/
  514 {
  515   switch (pc.token->type)
  516   {
  517     case T_IDENTIFIER: /*{{{*/
  518     {
  519       struct Pc var;
  520       struct Value *l;
  521 
  522       var=pc;
  523       if (pass==COMPILE)
  524       {
  525         if
  526         (
  527           ((pc.token+1)->type==T_OP || Auto_find(&stack,pc.token->u.identifier)==0)
  528           && Global_find(&globals,pc.token->u.identifier,(pc.token+1)->type==T_OP)==0
  529         ) return Value_new_ERROR(value,UNDECLARED);
  530       }
  531       assert(pass==DECLARE || pc.token->u.identifier->sym);
  532       if (pass!=DECLARE && (pc.token->u.identifier->sym->type==GLOBALVAR || pc.token->u.identifier->sym->type==GLOBALARRAY || pc.token->u.identifier->sym->type==LOCALVAR))
  533       {
  534         if ((l=lvalue(value))->type==V_ERROR) return value;
  535         Value_clone(value,l);
  536       }
  537       else
  538       {
  539         func(value);
  540         if (value->type==V_VOID)
  541         {
  542           Value_destroy(value);
  543           pc=var;
  544           return Value_new_ERROR(value,VOIDVALUE);
  545         }
  546       }
  547       break;
  548     }
  549     /*}}}*/
  550     case T_INTEGER: /*{{{*/
  551     {
  552       VALUE_NEW_INTEGER(value,pc.token->u.integer);
  553       ++pc.token;
  554       break;
  555     }
  556     /*}}}*/
  557     case T_REAL: /*{{{*/
  558     {
  559       VALUE_NEW_REAL(value,pc.token->u.real);
  560       ++pc.token;
  561       break;
  562     }
  563     /*}}}*/
  564     case T_STRING: /*{{{*/
  565     {
  566       Value_new_STRING(value);
  567       String_destroy(&value->u.string);
  568       String_clone(&value->u.string,pc.token->u.string);
  569       ++pc.token;
  570       break;
  571     }
  572     /*}}}*/
  573     case T_HEXINTEGER: /*{{{*/
  574     {
  575       VALUE_NEW_INTEGER(value,pc.token->u.hexinteger);
  576       ++pc.token;
  577       break;
  578     }
  579     /*}}}*/
  580     case T_OCTINTEGER: /*{{{*/
  581     {
  582       VALUE_NEW_INTEGER(value,pc.token->u.octinteger);
  583       ++pc.token;
  584       break;
  585     }
  586     /*}}}*/
  587     case T_OP: /*{{{*/
  588     {
  589       ++pc.token;
  590       if (eval(value,_("parenthetic"))->type==V_ERROR) return value;
  591       if (pc.token->type!=T_CP)
  592       {
  593         Value_destroy(value);
  594         return Value_new_ERROR(value,MISSINGCP);
  595       }
  596       ++pc.token;
  597       break;
  598     }
  599     /*}}}*/
  600     default: /*{{{*/
  601     {
  602       if (TOKEN_ISUNARYOPERATOR(pc.token->type)) return unarydown(value,eval8,6);
  603       else return (struct Value *)0;
  604     }
  605     /*}}}*/
  606   }
  607   return value;
  608 }
  609 /*}}}*/
  610 static struct Value *eval7(struct Value *value) /*{{{*/
  611 {
  612   return binarydown(value,eval8,7);
  613 }
  614 /*}}}*/
  615 static struct Value *eval6(struct Value *value) /*{{{*/
  616 {
  617   return unarydown(value,eval7,6);
  618 }
  619 /*}}}*/
  620 static struct Value *eval5(struct Value *value) /*{{{*/
  621 {
  622   return binarydown(value,eval6,5);
  623 }
  624 /*}}}*/
  625 static struct Value *eval4(struct Value *value) /*{{{*/
  626 {
  627   return binarydown(value,eval5,4);
  628 }
  629 /*}}}*/
  630 static struct Value *eval3(struct Value *value) /*{{{*/
  631 {
  632   return binarydown(value,eval4,3);
  633 }
  634 /*}}}*/
  635 static struct Value *eval2(struct Value *value) /*{{{*/
  636 {
  637   return unarydown(value,eval3,2);
  638 }
  639 /*}}}*/
  640 static struct Value *eval1(struct Value *value) /*{{{*/
  641 {
  642   return binarydown(value,eval2,1);
  643 }
  644 /*}}}*/
  645 static struct Value *eval(struct Value *value, const char *desc) /*{{{*/
  646 {
  647   /* avoid function calls for atomic expression */
  648   switch (pc.token->type)
  649   {
  650     case T_STRING:
  651     case T_REAL:
  652     case T_INTEGER:
  653     case T_HEXINTEGER:
  654     case T_OCTINTEGER:
  655     case T_IDENTIFIER: if (!TOKEN_ISBINARYOPERATOR((pc.token+1)->type) && (pc.token+1)->type!=T_OP) return eval7(value);
  656     default: break;
  657   }
  658   if (binarydown(value,eval1,0)==(struct Value*)0)
  659   {
  660     if (desc) return Value_new_ERROR(value,MISSINGEXPR,desc);
  661     else return (struct Value*)0; 
  662   }
  663   else return value;
  664 }
  665 /*}}}*/
  666 
  667 static void new(void) /*{{{*/
  668 {
  669   Global_destroy(&globals);
  670   Global_new(&globals);
  671   Auto_destroy(&stack);
  672   Auto_new(&stack);
  673   Program_destroy(&program);
  674   Program_new(&program);
  675   FS_closefiles();
  676   optionbase=0;
  677 }
  678 /*}}}*/
  679 static void pushLabel(enum LabelType type, struct Pc *patch) /*{{{*/
  680 {
  681   if (labelStackPointer==labelStackCapacity)
  682   {
  683     struct LabelStack *more;
  684 
  685     more=realloc(labelStack,sizeof(struct LabelStack)*(labelStackCapacity?(labelStackCapacity*=2):(labelStackCapacity=32)));
  686     labelStack=more;
  687   }
  688   assert(labelStackPointer<labelStackCapacity);
  689   labelStack[labelStackPointer].type=type;
  690   labelStack[labelStackPointer].patch=*patch;
  691   ++labelStackPointer;
  692 }
  693 /*}}}*/
  694 static struct Pc *popLabel(enum LabelType type) /*{{{*/
  695 {
  696   if (labelStackPointer==0 || labelStack[labelStackPointer-1].type!=type) return (struct Pc*)0;
  697   else return &labelStack[--labelStackPointer].patch;
  698 }
  699 /*}}}*/
  700 static struct Pc *findLabel(enum LabelType type) /*{{{*/
  701 {
  702   int i;
  703 
  704   for (i=labelStackPointer-1; i>=0; --i) if (labelStack[i].type==type) return &labelStack[i].patch;
  705   return (struct Pc*)0;
  706 }
  707 /*}}}*/
  708 static void labelStackError(struct Value *v) /*{{{*/
  709 {
  710   assert(labelStackPointer);
  711   pc=labelStack[labelStackPointer-1].patch;
  712   switch (labelStack[labelStackPointer-1].type)
  713   {
  714     case L_IF: Value_new_ERROR(v,STRAYIF); break;
  715     case L_DO: Value_new_ERROR(v,STRAYDO); break;
  716     case L_DOcondition: Value_new_ERROR(v,STRAYDOcondition); break;
  717     case L_ELSE: Value_new_ERROR(v,STRAYELSE2); break;
  718     case L_FOR_BODY:
  719     {
  720       Value_new_ERROR(v,STRAYFOR);
  721       pc=*findLabel(L_FOR);
  722       break;
  723     }
  724     case L_WHILE: Value_new_ERROR(v,STRAYWHILE); break;
  725     case L_REPEAT: Value_new_ERROR(v,STRAYREPEAT); break;
  726     case L_SELECTCASE: Value_new_ERROR(v,STRAYSELECTCASE); break;
  727     case L_FUNC: Value_new_ERROR(v,STRAYFUNC); break;
  728     default: assert(0);
  729   }
  730 }
  731 /*}}}*/
  732 static const char *topLabelDescription(void) /*{{{*/
  733 {
  734   if (labelStackPointer==0)
  735   {
  736     return _("program");
  737   }
  738   switch (labelStack[labelStackPointer-1].type)
  739   {
  740     case L_IF: return _("`if' branch");
  741     case L_DO: return _("`do' loop");
  742     case L_DOcondition: return _("`do while' or `do until' loop");
  743     case L_ELSE: return _("`else' branch");
  744     case L_FOR_BODY: return _("`for' loop");
  745     case L_WHILE: return _("`while' loop");
  746     case L_REPEAT: return _("`repeat' loop");
  747     case L_SELECTCASE: return _("`select case' control structure");
  748     case L_FUNC: return _("function or procedure");
  749     default: assert(0);
  750   }
  751   /* NOTREACHED */
  752   return (const char*)0;
  753 }
  754 /*}}}*/
  755 static struct Value *assign(struct Value *value) /*{{{*/
  756 {
  757   struct Pc expr;
  758 
  759   assert(pc.token->type==T_IDENTIFIER);
  760   if (strcasecmp(pc.token->u.identifier->name,"mid$")==0) /* mid$(a$,n,m)=b$ */ /*{{{*/
  761   {
  762     long int n,m;
  763     struct Value *l;
  764 
  765     ++pc.token;
  766     if (pc.token->type!=T_OP) return Value_new_ERROR(value,MISSINGOP);
  767     ++pc.token;
  768     if (pc.token->type!=T_IDENTIFIER) return Value_new_ERROR(value,MISSINGSTRIDENT);
  769     if (pass==DECLARE)
  770     {
  771       if
  772       (
  773         ((pc.token+1)->type==T_OP || Auto_find(&stack,pc.token->u.identifier)==0)
  774         && Global_variable(&globals,pc.token->u.identifier,pc.token->u.identifier->defaultType,(pc.token+1)->type==T_OP?GLOBALARRAY:GLOBALVAR,0)==0
  775       )
  776       {
  777         return Value_new_ERROR(value,REDECLARATION);
  778       }
  779     }
  780     if ((l=lvalue(value))->type==V_ERROR) return value;
  781     if (pass==COMPILE && l->type!=V_STRING) return Value_new_ERROR(value,TYPEMISMATCH4);
  782     if (pc.token->type!=T_COMMA) return Value_new_ERROR(value,MISSINGCOMMA);
  783     ++pc.token;
  784     if (eval(value,_("position"))->type==V_ERROR || Value_retype(value,V_INTEGER)->type==V_ERROR) return value;
  785     n=value->u.integer;
  786     Value_destroy(value);
  787     if (pass==INTERPRET && n<1) return Value_new_ERROR(value,OUTOFRANGE,"position");
  788     if (pc.token->type==T_COMMA)
  789     {
  790       ++pc.token;
  791       if (eval(value,_("length"))->type==V_ERROR || Value_retype(value,V_INTEGER)->type==V_ERROR) return value;
  792       m=value->u.integer;
  793       if (pass==INTERPRET && m<0) return Value_new_ERROR(value,OUTOFRANGE,_("length"));
  794       Value_destroy(value);
  795     }
  796     else m=-1;
  797     if (pc.token->type!=T_CP) return Value_new_ERROR(value,MISSINGCP);
  798     ++pc.token;
  799     if (pc.token->type!=T_EQ) return Value_new_ERROR(value,MISSINGEQ);
  800     ++pc.token;
  801     if (eval(value,_("rhs"))->type==V_ERROR || Value_retype(value,V_STRING)->type==V_ERROR) return value;
  802     if (pass==INTERPRET)
  803     {
  804       if (m==-1) m=value->u.string.length;
  805       String_set(&l->u.string,n-1,&value->u.string,m);
  806     }
  807   }
  808   /*}}}*/
  809   else /*{{{*/
  810   {
  811     struct Value **l=(struct Value**)0;
  812     int i, used=0, capacity=0;
  813     struct Value retyped_value;
  814 
  815     for (;;)
  816     {
  817       if (pc.token->type!=T_IDENTIFIER) return Value_new_ERROR(value,MISSINGVARIDENT);
  818 
  819       if (used==capacity)
  820       {
  821         struct Value **more;
  822       
  823         capacity=capacity?2*capacity:2;
  824         more=realloc(l,capacity*sizeof(*l));
  825         l=more;
  826       }
  827 
  828       if (pass==DECLARE)
  829       {
  830         if
  831         (
  832           ((pc.token+1)->type==T_OP || Auto_find(&stack,pc.token->u.identifier)==0)
  833           && Global_variable(&globals,pc.token->u.identifier,pc.token->u.identifier->defaultType,(pc.token+1)->type==T_OP?GLOBALARRAY:GLOBALVAR,0)==0
  834         )
  835         {
  836           if (capacity) free(l);
  837           return Value_new_ERROR(value,REDECLARATION);
  838         }
  839       }
  840       if ((l[used]=lvalue(value))->type==V_ERROR) return value;
  841       ++used;
  842       if (pc.token->type==T_COMMA) ++pc.token;
  843       else break;
  844     }
  845     if (pc.token->type!=T_EQ) return Value_new_ERROR(value,MISSINGEQ);
  846     ++pc.token;
  847     expr=pc;
  848     if (eval(value,_("rhs"))->type==V_ERROR) return value;
  849     for (i=0; i<used; ++i)
  850     {
  851       Value_clone(&retyped_value,value);
  852       if (pass!=DECLARE && VALUE_RETYPE(&retyped_value,(l[i])->type)->type==V_ERROR)
  853       {
  854         pc=expr;
  855         free(l);
  856         Value_destroy(value);
  857         *value=retyped_value;
  858         return value;
  859       }
  860       if (pass==INTERPRET)
  861       {
  862         Value_destroy(l[i]);
  863         *(l[i])=retyped_value;
  864       }
  865     }
  866     free(l);
  867     Value_destroy(value);
  868     *value=retyped_value; /* for status only */
  869   }
  870   /*}}}*/
  871   return value;
  872 }
  873 /*}}}*/
  874 static struct Value *compileProgram(struct Value *v, int clearGlobals) /*{{{*/
  875 {
  876   struct Pc begin;
  877 
  878   stack.resumeable=0;
  879   if (clearGlobals)
  880   {
  881     Global_destroy(&globals);
  882     Global_new(&globals);
  883   }
  884   else Global_clearFunctions(&globals);
  885   if (Program_beginning(&program,&begin))
  886   {
  887     struct Pc savepc;
  888     int savepass;
  889 
  890     savepc=pc;
  891     savepass=pass;
  892     Program_norun(&program);
  893     for (pass=DECLARE; pass!=INTERPRET; ++pass)
  894     {
  895       if (pass==DECLARE)
  896       {
  897         stack.begindata.line=-1;
  898         lastdata=&stack.begindata;
  899       }
  900       optionbase=0;
  901       FS_intr=0;
  902       stopped=0;
  903       program.runnable=1;
  904       pc=begin;
  905       while (1)
  906       {
  907         statements(v);
  908         if (v->type==V_ERROR) break;
  909         Value_destroy(v);
  910         if (!Program_skipEOL(&program,&pc,0,0)) { Value_new_NIL(v); break; }
  911       }
  912       if (v->type!=V_ERROR && labelStackPointer>0)
  913       {
  914         Value_destroy(v);
  915         labelStackError(v);
  916       }
  917       if (v->type==V_ERROR)
  918       {
  919         labelStackPointer=0;
  920         Program_norun(&program);
  921         if (stack.cur) Auto_funcEnd(&stack); /* Always correct? */
  922         pass=savepass;
  923         return v;
  924       }
  925     }
  926     pc=begin;
  927     if (Program_analyse(&program,&pc,v))
  928     {
  929       labelStackPointer=0;
  930       Program_norun(&program);
  931       if (stack.cur) Auto_funcEnd(&stack); /* Always correct? */
  932       pass=savepass;
  933       return v;
  934     }
  935     curdata=stack.begindata;
  936     pc=savepc;
  937     pass=savepass;
  938   }
  939   return Value_new_NIL(v);
  940 }
  941 /*}}}*/
  942 static void runline(struct Token *line) /*{{{*/
  943 {
  944   struct Value value;
  945 
  946   FS_flush(STDCHANNEL);
  947   for (pass=DECLARE; pass!=INTERPRET; ++pass)
  948   {
  949     curdata.line=-1;
  950     pc.line=-1;
  951     pc.token=line;
  952     optionbase=0;
  953     FS_intr=0;
  954     stopped=0;
  955     statements(&value);
  956     if (value.type!=V_ERROR && pc.token->type!=T_EOL)
  957     {
  958       Value_destroy(&value);
  959       Value_new_ERROR(&value,SYNTAX);
  960     }
  961     if (value.type!=V_ERROR && labelStackPointer>0)
  962     {
  963       Value_destroy(&value);
  964       labelStackError(&value);
  965     }
  966     if (value.type==V_ERROR)
  967     {
  968       struct String s;
  969 
  970       Auto_setError(&stack,Program_lineNumber(&program,&pc),&pc,&value);
  971       Program_PCtoError(&program,&pc,&value);
  972       labelStackPointer=0;
  973       FS_putChars(STDCHANNEL,_("Error: "));
  974       String_new(&s);
  975       Value_toString(&value,&s,' ',-1,0,0,0,0,-1,0,0);
  976       Value_destroy(&value);
  977       FS_putString(STDCHANNEL,&s);
  978       String_destroy(&s);
  979       return;
  980     }
  981     if (!program.runnable && pass==COMPILE)
  982     {
  983       Value_destroy(&value);
  984       (void)compileProgram(&value,0);
  985     }
  986   }
  987 
  988   pc.line=-1;
  989   pc.token=line;
  990   optionbase=0;
  991   curdata=stack.begindata;
  992   nextdata.line=-1;
  993   Value_destroy(&value);
  994   pass=INTERPRET;
  995   FS_allowIntr(1);
  996   do
  997   {
  998     assert(pass==INTERPRET);
  999     statements(&value);
 1000     assert(pass==INTERPRET);
 1001     if (value.type==V_ERROR)
 1002     {
 1003       if (strchr(value.u.error.msg,'\n')==(char*)0)
 1004       {
 1005         Auto_setError(&stack,Program_lineNumber(&program,&pc),&pc,&value);
 1006         Program_PCtoError(&program,&pc,&value);
 1007       }
 1008       if (stack.onerror.line!=-1)
 1009       {
 1010         stack.resumeable=1;
 1011         pc=stack.onerror;
 1012       }
 1013       else
 1014       {
 1015         struct String s;
 1016 
 1017         String_new(&s);
 1018         if (!stopped)
 1019         {
 1020           stopped=0;
 1021           FS_putChars(STDCHANNEL,_("Error: "));
 1022         }
 1023         Auto_frameToError(&stack,&program,&value);
 1024         Value_toString(&value,&s,' ',-1,0,0,0,0,-1,0,0);
 1025         while (Auto_gosubReturn(&stack,(struct Pc*)0));
 1026         FS_putString(STDCHANNEL,&s);
 1027         String_destroy(&s);
 1028         Value_destroy(&value);
 1029         break;
 1030       }
 1031     }
 1032     Value_destroy(&value);
 1033   } while (pc.token->type!=T_EOL || Program_skipEOL(&program,&pc,STDCHANNEL,1));
 1034   FS_allowIntr(0);
 1035 }
 1036 /*}}}*/
 1037 static struct Value *evalGeometry(struct Value *value, unsigned int *dim, unsigned int geometry[]) /*{{{*/
 1038 {
 1039   struct Pc exprpc=pc;
 1040 
 1041   if (eval(value,_("dimension"))->type==V_ERROR || (pass!=DECLARE && Value_retype(value,V_INTEGER)->type==V_ERROR)) return value;
 1042   if (pass==INTERPRET && value->u.integer<optionbase)
 1043   {
 1044     Value_destroy(value);
 1045     pc=exprpc;
 1046     return Value_new_ERROR(value,OUTOFRANGE,_("dimension"));
 1047   }
 1048   geometry[0]=value->u.integer-optionbase+1;
 1049   Value_destroy(value);
 1050   if (pc.token->type==T_COMMA)
 1051   {
 1052     ++pc.token;
 1053     exprpc=pc;
 1054     if (eval(value,_("dimension"))->type==V_ERROR || (pass!=DECLARE && Value_retype(value,V_INTEGER)->type==V_ERROR)) return value;
 1055     if (pass==INTERPRET && value->u.integer<optionbase)
 1056     {
 1057       Value_destroy(value);
 1058       pc=exprpc;
 1059       return Value_new_ERROR(value,OUTOFRANGE,_("dimension"));
 1060     }
 1061     geometry[1]=value->u.integer-optionbase+1;
 1062     Value_destroy(value);
 1063     *dim=2;
 1064   }
 1065   else *dim=1;
 1066   if (pc.token->type==T_CP) ++pc.token;
 1067   else return Value_new_ERROR(value,MISSINGCP);
 1068   return (struct Value*)0;
 1069 }
 1070 /*}}}*/
 1071 static struct Value *convert(struct Value *value, struct Value *l, struct Token *t) /*{{{*/
 1072 {
 1073   switch (l->type)
 1074   {
 1075     case V_INTEGER:
 1076     {
 1077       char *datainput;
 1078       char *end;
 1079       long int v;
 1080       int overflow;
 1081 
 1082       if (t->type!=T_DATAINPUT) return Value_new_ERROR(value,BADCONVERSION,_("integer"));
 1083       datainput=t->u.datainput;
 1084       v=Value_vali(datainput,&end,&overflow);
 1085       if (end==datainput || (*end!='\0' && *end!=' ' && *end!='\t')) return Value_new_ERROR(value,BADCONVERSION,_("integer"));
 1086       if (overflow) return Value_new_ERROR(value,OUTOFRANGE,_("converted value"));
 1087       Value_destroy(l);
 1088       VALUE_NEW_INTEGER(l,v);
 1089       break;
 1090     }
 1091     case V_REAL:
 1092     {
 1093       char *datainput;
 1094       char *end;
 1095       double v;
 1096       int overflow;
 1097 
 1098       if (t->type!=T_DATAINPUT) return Value_new_ERROR(value,BADCONVERSION,_("real"));
 1099       datainput=t->u.datainput;
 1100       v=Value_vald(datainput,&end,&overflow);
 1101       if (end==datainput || (*end!='\0' && *end!=' ' && *end!='\t')) return Value_new_ERROR(value,BADCONVERSION,_("real"));
 1102       if (overflow) return Value_new_ERROR(value,OUTOFRANGE,_("converted value"));
 1103       Value_destroy(l);
 1104       VALUE_NEW_REAL(l,v);
 1105       break;
 1106     }
 1107     case V_STRING:
 1108     {
 1109       Value_destroy(l);
 1110       Value_new_STRING(l);
 1111       if (t->type==T_STRING) String_appendString(&l->u.string,t->u.string);
 1112       else String_appendChars(&l->u.string,t->u.datainput);
 1113       break;
 1114     }
 1115     default: assert(0);
 1116   }
 1117   return (struct Value*)0;
 1118 }
 1119 /*}}}*/
 1120 static struct Value *dataread(struct Value *value, struct Value *l) /*{{{*/
 1121 {
 1122   if (curdata.line==-1)
 1123   {
 1124     return Value_new_ERROR(value,ENDOFDATA);
 1125   }
 1126   if (curdata.token->type==T_DATA)
 1127   {
 1128     nextdata=curdata.token->u.nextdata;
 1129     ++curdata.token;
 1130   }
 1131   if (convert(value,l,curdata.token))
 1132   {
 1133     return value;
 1134   }
 1135   ++curdata.token;
 1136   if (curdata.token->type==T_COMMA) ++curdata.token;
 1137   else curdata=nextdata;
 1138   return (struct Value*)0;
 1139 }
 1140 /*}}}*/
 1141 static struct Value more_statements;
 1142 #include "statement.c"
 1143 static struct Value *statements(struct Value *value) /*{{{*/
 1144 {
 1145   more:
 1146   if (pc.token->statement)
 1147   {
 1148     struct Value *v;
 1149 
 1150     if ((v=pc.token->statement(value)))
 1151     {
 1152       if (v==&more_statements) goto more;
 1153       else return value;
 1154     }
 1155   }
 1156   else return Value_new_ERROR(value,MISSINGSTATEMENT);
 1157 
 1158   if (FS_intr)
 1159   {
 1160     stopped=1;
 1161     return Value_new_ERROR(value,BREAK);
 1162   }
 1163   else if (pc.token->type==T_COLON && (pc.token+1)->type==T_ELSE) ++pc.token;
 1164   else if ((pc.token->type==T_COLON && (pc.token+1)->type!=T_ELSE) || pc.token->type==T_QUOTE)
 1165   {
 1166     ++pc.token;
 1167     goto more;
 1168   }
 1169   else if ((pass==DECLARE || pass==COMPILE) && pc.token->type!=T_EOL && pc.token->type!=T_ELSE)
 1170   {
 1171     return Value_new_ERROR(value,MISSINGCOLON);
 1172   }
 1173   return Value_new_NIL(value);
 1174 }
 1175 /*}}}*/
 1176 
 1177 void bas_init(int backslash_colon, int restricted, int uppercase, int lpfd) /*{{{*/
 1178 {
 1179 #ifdef HAVE_GETTEXT
 1180   bindtextdomain("bas",LOCALEDIR);
 1181   textdomain("bas");
 1182 #endif
 1183   stack.begindata.line=-1;
 1184   Token_init(backslash_colon,uppercase);
 1185   Global_new(&globals);
 1186   Auto_new(&stack);
 1187   Program_new(&program);
 1188   FS_opendev(STDCHANNEL,0,1);
 1189   FS_opendev(LPCHANNEL,-1,lpfd);
 1190   run_restricted=restricted;
 1191 }
 1192 /*}}}*/
 1193 void bas_runFile(const char *runFile) /*{{{*/
 1194 {
 1195   struct Value value;
 1196   int dev;
 1197 
 1198   new();
 1199   if ((dev=FS_openin(runFile))==-1)
 1200   {
 1201     const char *errmsg=FS_errmsg;
 1202 
 1203     FS_putChars(0,_("bas: Executing `"));
 1204     FS_putChars(0,runFile);
 1205     FS_putChars(0,_("' failed ("));
 1206     FS_putChars(0,errmsg);
 1207     FS_putChars(0,_(").\n"));
 1208   }
 1209   else if (Program_merge(&program,dev,&value))
 1210   {
 1211     struct String s;
 1212 
 1213     FS_putChars(0,"bas: ");
 1214     String_new(&s);
 1215     Value_toString(&value,&s,' ',-1,0,0,0,0,-1,0,0);
 1216     FS_putString(0,&s);
 1217     String_destroy(&s);
 1218     FS_putChar(0,'\n');
 1219     Value_destroy(&value);
 1220   }
 1221   else
 1222   {
 1223     struct Token line[2];
 1224 
 1225     Program_setname(&program,runFile);
 1226     line[0].type=T_RUN;
 1227     line[0].statement=stmt_RUN;
 1228     line[1].type=T_EOL;
 1229     line[1].statement=stmt_COLON_EOL;
 1230 
 1231     FS_close(dev);
 1232     runline(line);
 1233   }
 1234 }
 1235 /*}}}*/
 1236 void bas_runLine(const char *runLine) /*{{{*/
 1237 {
 1238   struct Token *line;
 1239 
 1240   line=Token_newCode(runLine);
 1241   runline(line+1);
 1242   Token_destroy(line);
 1243 }
 1244 /*}}}*/
 1245 void bas_interpreter(void) /*{{{*/
 1246 {
 1247   if (FS_istty(STDCHANNEL))
 1248   {
 1249     FS_putChars(STDCHANNEL,"bas " VERSION "\n");
 1250     FS_putChars(STDCHANNEL,"Copyright 1999-2014 Michael Haardt.\n");
 1251     FS_putChars(STDCHANNEL,_("This is free software with ABSOLUTELY NO WARRANTY.\n"));
 1252   }
 1253   new();
 1254   while (1)
 1255   {
 1256     struct Token *line;
 1257     struct String s;
 1258 
 1259     FS_intr=0; stopped=0;
 1260     FS_allowIntr(1);
 1261     FS_nextline(STDCHANNEL);
 1262     if (FS_istty(STDCHANNEL)) FS_putChars(STDCHANNEL,"> ");
 1263     FS_flush(STDCHANNEL);
 1264     String_new(&s);
 1265     if (FS_appendToString(STDCHANNEL,&s,1)==-1)
 1266     {
 1267       if (FS_intr)
 1268       {
 1269         FS_putChars(STDCHANNEL,_("\nBreak\n"));
 1270         FS_flush(STDCHANNEL);
 1271         String_destroy(&s);
 1272         continue;
 1273       }
 1274       else
 1275       {
 1276         FS_putChars(STDCHANNEL,FS_errmsg);
 1277         FS_flush(STDCHANNEL);
 1278         String_destroy(&s);
 1279         break;
 1280       }
 1281     }
 1282     if (s.length==0)
 1283     {
 1284       String_destroy(&s);
 1285       break;
 1286     }
 1287     line=Token_newCode(s.character);
 1288     String_destroy(&s);
 1289     if (line->type!=T_EOL)
 1290     {
 1291       if (line->type==T_INTEGER && line->u.integer>0)
 1292       {
 1293         if (program.numbered)
 1294         {
 1295           if ((line+1)->type==T_EOL)
 1296           {
 1297             struct Pc where;
 1298 
 1299             if (Program_goLine(&program,line->u.integer,&where)==(struct Pc*)0) FS_putChars(STDCHANNEL,NOSUCHLINE_MSG);
 1300             else Program_delete(&program,&where,&where);
 1301             Token_destroy(line);
 1302           }
 1303           else Program_store(&program,line,line->u.integer);
 1304         }
 1305         else
 1306         {
 1307           FS_putChars(STDCHANNEL,_("Use `renum' to number program first"));
 1308           Token_destroy(line);
 1309         }
 1310       }
 1311       else if (line->type==T_UNNUMBERED)
 1312       {
 1313         runline(line+1);
 1314         Token_destroy(line);
 1315         if (FS_istty(STDCHANNEL) && bas_end>0)
 1316         {
 1317           FS_putChars(STDCHANNEL,_("END program\n"));
 1318           bas_end=0;
 1319         }
 1320       }
 1321       else
 1322       {
 1323         FS_putChars(STDCHANNEL,_("Invalid line\n"));
 1324         Token_destroy(line);
 1325       }
 1326     }
 1327     else Token_destroy(line);
 1328   }
 1329   FS_allowIntr(0);
 1330 }
 1331 /*}}}*/
 1332 void bas_exit(void) /*{{{*/
 1333 {
 1334   Auto_destroy(&stack);
 1335   Global_destroy(&globals);
 1336   Program_destroy(&program);
 1337   if (labelStack) free(labelStack);
 1338   FS_closefiles();
 1339   FS_close(LPCHANNEL);
 1340   FS_close(STDCHANNEL);
 1341 }
 1342 /*}}}*/