summaryrefslogtreecommitdiff
path: root/apps/interpreters/bas/bas.c
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-10-27 07:53:12 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-10-27 07:53:12 -0600
commit4ef5633f361ab5302007045dcef945043d6d6225 (patch)
tree1806fe0ec9221c4e6c7439419e8b57bfe7865d29 /apps/interpreters/bas/bas.c
parentf2fe892334074612e4e3159c754b65d13bc348fc (diff)
downloadnuttx-4ef5633f361ab5302007045dcef945043d6d6225.tar.gz
nuttx-4ef5633f361ab5302007045dcef945043d6d6225.tar.bz2
nuttx-4ef5633f361ab5302007045dcef945043d6d6225.zip
Port of BAS 2.4 to NuttX by Alan Carvalho de Assis
Diffstat (limited to 'apps/interpreters/bas/bas.c')
-rw-r--r--apps/interpreters/bas/bas.c1736
1 files changed, 1736 insertions, 0 deletions
diff --git a/apps/interpreters/bas/bas.c b/apps/interpreters/bas/bas.c
new file mode 100644
index 000000000..eba40371f
--- /dev/null
+++ b/apps/interpreters/bas/bas.c
@@ -0,0 +1,1736 @@
+/* #includes */ /*{{{C}}}*//*{{{*/
+#include "config.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_GETTEXT
+#include <libintl.h>
+#define _(String) gettext(String)
+#else
+#define _(String) String
+#endif
+#include <limits.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "getopt.h"
+
+#include "auto.h"
+#include "bas.h"
+#include "error.h"
+#include "fs.h"
+#include "global.h"
+#include "program.h"
+#include "value.h"
+#include "var.h"
+
+#ifdef USE_DMALLOC
+#include "dmalloc.h"
+#endif
+/*}}}*/
+/* #defines */ /*{{{*/
+#define DIRECTMODE (pc.line==-1)
+#ifndef __GNUC__
+#define inline
+#endif
+/*}}}*/
+
+/* types */ /*{{{*/
+enum LabelType
+{
+ L_IF=1,
+ L_ELSE,
+ L_DO,
+ L_DOcondition,
+ L_FOR,
+ L_FOR_VAR,
+ L_FOR_LIMIT,
+ L_FOR_BODY,
+ L_REPEAT,
+ L_SELECTCASE,
+ L_WHILE,
+ L_FUNC
+};
+
+struct LabelStack
+{
+ enum LabelType type;
+ struct Pc patch;
+};
+/*}}}*/
+/* variables */ /*{{{*/
+static unsigned int labelStackPointer,labelStackCapacity;
+static struct LabelStack *labelStack;
+static struct Pc *lastdata;
+static struct Pc curdata;
+static struct Pc nextdata;
+static enum { DECLARE, COMPILE, INTERPRET } pass;
+static int stopped;
+static int optionbase;
+static struct Pc pc;
+static struct Auto stack;
+static struct Program program;
+static struct Global globals;
+static int run_restricted;
+
+int bas_argc;
+char *bas_argv0;
+char **bas_argv;
+int bas_end;
+/*}}}*/
+/* forward prototypes */ /*{{{*/
+static struct Value *statements(struct Value *value);
+static struct Value *compileProgram(struct Value *v, int clearGlobals);
+static struct Value *eval(struct Value *value, const char *desc);
+/*}}}*/
+
+static char *mytmpnam(void) /*{{{*/
+{
+ static char buf[_POSIX_PATH_MAX];
+ const char *tmpdir;
+ unsigned int i;
+ int fd=-1;
+
+ if ((tmpdir=getenv("TMPDIR"))==(char*)0) tmpdir="/tmp";
+ if ((strlen(tmpdir)+1+8+1)>=_POSIX_PATH_MAX) return (char*)0;
+ i=getpid();
+ 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;
+ if (fd==-1) return (char*)0;
+ close(fd);
+ return buf;
+}
+/*}}}*/
+static int cat(const char *filename) /*{{{*/
+{
+ int fd;
+ char buf[4096];
+ ssize_t l;
+ int err;
+
+ if ((fd=open(filename,O_RDONLY))==-1) return -1;
+ while ((l=read(fd,buf,sizeof(buf)))>0)
+ {
+ ssize_t off,w;
+
+ off=0;
+ while (off<l)
+ {
+ if ((w=write(1,buf+off,l-off))==-1)
+ {
+ err=errno;
+ close(fd);
+ errno=err;
+ return -1;
+ }
+ off+=w;
+ }
+ }
+ if (l==-1)
+ {
+ err=errno;
+ close(fd);
+ errno=err;
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+/*}}}*/
+static struct Value *lvalue(struct Value *value) /*{{{*/
+{
+ struct Symbol *sym;
+ struct Pc lvpc=pc;
+
+ sym=pc.token->u.identifier->sym;
+ assert(pass==DECLARE || sym->type==GLOBALVAR || sym->type==GLOBALARRAY || sym->type==LOCALVAR);
+ if ((pc.token+1)->type==T_OP)
+ {
+ struct Pc idxpc;
+ unsigned int dim,capacity;
+ int *idx;
+
+ pc.token+=2;
+ dim=0;
+ capacity=0;
+ idx=(int*)0;
+ while (1)
+ {
+ if (dim==capacity && pass==INTERPRET) /* enlarge idx */ /*{{{*/
+ {
+ int *more;
+
+ more=realloc(idx,sizeof(unsigned int)*(capacity?(capacity*=2):(capacity=3)));
+ if (!more)
+ {
+ if (capacity) free(idx);
+ return Value_new_ERROR(value,OUTOFMEMORY);
+ }
+ idx=more;
+ }
+ /*}}}*/
+ idxpc=pc;
+ if (eval(value,_("index"))->type==V_ERROR || VALUE_RETYPE(value,V_INTEGER)->type==V_ERROR)
+ {
+ if (capacity) free(idx);
+ pc=idxpc;
+ return value;
+ }
+ if (pass==INTERPRET)
+ {
+ idx[dim]=value->u.integer;
+ ++dim;
+ }
+ Value_destroy(value);
+ if (pc.token->type==T_COMMA) ++pc.token;
+ else break;
+ }
+ if (pc.token->type!=T_CP)
+ {
+ assert(pass!=INTERPRET);
+ return Value_new_ERROR(value,MISSINGCP);
+ }
+ else ++pc.token;
+ switch (pass)
+ {
+ case INTERPRET:
+ {
+ if ((value=Var_value(&(sym->u.var),dim,idx,value))->type==V_ERROR) pc=lvpc;
+ free(idx);
+ return value;
+ }
+ case DECLARE:
+ {
+ return Value_nullValue(V_INTEGER);
+ }
+ case COMPILE:
+ {
+ return Value_nullValue(sym->type==GLOBALARRAY ? sym->u.var.type : Auto_varType(&stack,sym));
+ }
+ default: assert(0);
+ }
+ return (struct Value*)0;
+ }
+ else
+ {
+ ++pc.token;
+ switch (pass)
+ {
+ case INTERPRET: return VAR_SCALAR_VALUE(sym->type==GLOBALVAR ? &(sym->u.var) : Auto_local(&stack,sym->u.local.offset));
+ case DECLARE: return Value_nullValue(V_INTEGER);
+ case COMPILE: return Value_nullValue(sym->type==GLOBALVAR? sym->u.var.type : Auto_varType(&stack,sym));
+ default: assert(0);
+ }
+ return (struct Value*)0;
+ }
+}
+/*}}}*/
+static struct Value *func(struct Value *value) /*{{{*/
+{
+ struct Identifier *ident;
+ struct Pc funcpc=pc;
+ int firstslot=-99;
+ int args=0;
+ struct Symbol *sym;
+
+ assert(pc.token->type==T_IDENTIFIER);
+ /*
+ Evaluating a function in direct mode may start a program, so it needs to
+ be compiled. If in direct mode, programs will be compiled after the
+ direct mode pass DECLARE, but errors are ignored at that point, because
+ the program may not be needed. If the program is fine, its symbols will
+ be available during the compile phase already. If not and we need it
+ at this point, compile it again to get the error and abort.
+ */
+ if (DIRECTMODE && !program.runnable && pass!=DECLARE)
+ {
+ if (compileProgram(value,0)->type==V_ERROR) return value;
+ Value_destroy(value);
+ }
+ ident=pc.token->u.identifier;
+ assert(pass==DECLARE || ident->sym->type==BUILTINFUNCTION || ident->sym->type==USERFUNCTION);
+ ++pc.token;
+ if (pass!=DECLARE)
+ {
+ firstslot=stack.stackPointer;
+ if (ident->sym->type==USERFUNCTION && ident->sym->u.sub.retType!=V_VOID)
+ {
+ struct Var *v=Auto_pushArg(&stack);
+ Var_new(v,ident->sym->u.sub.retType,0,(const unsigned int*)0,0);
+ }
+ }
+ if (pc.token->type==T_OP) /* push arguments to stack */ /*{{{*/
+ {
+ ++pc.token;
+ if (pc.token->type!=T_CP) while (1)
+ {
+ if (pass==DECLARE)
+ {
+ if (eval(value,_("actual parameter"))->type==V_ERROR) return value;
+ Value_destroy(value);
+ }
+ else
+ {
+ struct Var *v=Auto_pushArg(&stack);
+
+ Var_new_scalar(v);
+ if (eval(v->value,(const char*)0)->type==V_ERROR)
+ {
+ Value_clone(value,v->value);
+ while (stack.stackPointer>firstslot) Var_destroy(&stack.slot[--stack.stackPointer].var);
+ return value;
+ }
+ v->type=v->value->type;
+ }
+ ++args;
+ if (pc.token->type==T_COMMA) ++pc.token;
+ else break;
+ }
+ if (pc.token->type!=T_CP)
+ {
+ if (pass!=DECLARE)
+ {
+ while (stack.stackPointer>firstslot) Var_destroy(&stack.slot[--stack.stackPointer].var);
+ }
+ return Value_new_ERROR(value,MISSINGCP);
+ }
+ ++pc.token;
+ }
+ /*}}}*/
+ if (pass==DECLARE) Value_new_null(value,ident->defaultType);
+ else
+ {
+ int i;
+ int nomore;
+ int argerr;
+ int overloaded;
+
+ if (pass==INTERPRET && ident->sym->type==USERFUNCTION)
+ {
+ for (i=0; i<ident->sym->u.sub.u.def.localLength; ++i)
+ {
+ struct Var *v=Auto_pushArg(&stack);
+ Var_new(v,ident->sym->u.sub.u.def.localTypes[i],0,(const unsigned int*)0,0);
+ }
+ }
+ Auto_pushFuncRet(&stack,firstslot,&pc);
+
+ sym=ident->sym;
+ overloaded=(pass==COMPILE && sym->type==BUILTINFUNCTION && sym->u.sub.u.bltin.next);
+ do
+ {
+ nomore=(pass==COMPILE && !(sym->type==BUILTINFUNCTION && sym->u.sub.u.bltin.next));
+ argerr=0;
+ if (args<sym->u.sub.argLength) /*{{{*/
+ {
+ if (nomore) Value_new_ERROR(value,TOOFEW);
+ argerr=1;
+ }
+ /*}}}*/
+ else if (args>sym->u.sub.argLength) /*{{{*/
+ {
+ if (nomore) Value_new_ERROR(value,TOOMANY);
+ argerr=1;
+ }
+ /*}}}*/
+ else /*{{{*/
+ {
+ for (i=0; i<args; ++i)
+ {
+ struct Value *arg=Var_value(Auto_local(&stack,i),0,(int*)0,value);
+
+ assert(arg->type!=V_ERROR);
+ if (overloaded)
+ {
+ if (arg->type!=sym->u.sub.argTypes[i])
+ {
+ if (nomore) Value_new_ERROR(value,TYPEMISMATCH2,i+1);
+ argerr=1;
+ break;
+ }
+ }
+ else if (Value_retype(arg,sym->u.sub.argTypes[i])->type==V_ERROR)
+ {
+ if (nomore) Value_new_ERROR(value,TYPEMISMATCH3,arg->u.error.msg,i+1);
+ argerr=1;
+ break;
+ }
+ }
+ }
+ /*}}}*/
+ if (argerr)
+ {
+ if (nomore)
+ {
+ Auto_funcReturn(&stack,(struct Pc*)0);
+ pc=funcpc;
+ return value;
+ }
+ else sym=sym->u.sub.u.bltin.next;
+ }
+ } while (argerr);
+ ident->sym=sym;
+ if (sym->type==BUILTINFUNCTION)
+ {
+ if (pass==INTERPRET)
+ {
+ if (sym->u.sub.u.bltin.call(value,&stack)->type==V_ERROR) pc=funcpc;
+ }
+ else Value_new_null(value,sym->u.sub.retType);
+ }
+ else if (sym->type==USERFUNCTION)
+ {
+ if (pass==INTERPRET)
+ {
+ int r=1;
+
+ pc=sym->u.sub.u.def.scope.start;
+ if (pc.token->type==T_COLON) ++pc.token;
+ else Program_skipEOL(&program,&pc,STDCHANNEL,1);
+ do
+ {
+ if (statements(value)->type==V_ERROR)
+ {
+ if (strchr(value->u.error.msg,'\n')==(char*)0)
+ {
+ Auto_setError(&stack,Program_lineNumber(&program,&pc),&pc,value);
+ Program_PCtoError(&program,&pc,value);
+ }
+ if (stack.onerror.line!=-1)
+ {
+ stack.resumeable=1;
+ pc=stack.onerror;
+ }
+ else
+ {
+ Auto_frameToError(&stack,&program,value);
+ break;
+ }
+ }
+ else if (value->type!=V_NIL) break;
+ Value_destroy(value);
+ } while ((r=Program_skipEOL(&program,&pc,STDCHANNEL,1)));
+ if (!r) Value_new_VOID(value);
+ }
+ else Value_new_null(value,sym->u.sub.retType);
+ }
+ Auto_funcReturn(&stack,pass==INTERPRET && value->type!=V_ERROR ? &pc : (struct Pc*)0);
+ }
+ return value;
+}
+/*}}}*/
+
+#ifdef USE_LR0
+/* Grammar with LR(0) sets */ /*{{{*/
+/*
+Grammar:
+
+1 EV -> E
+2 E -> E op E
+3 E -> op E
+4 E -> ( E )
+5 E -> value
+
+i0:
+EV -> . E goto(0,E)=5
+E -> . E op E goto(0,E)=5
+E -> . op E +,- shift 2
+E -> . ( E ) ( shift 3
+E -> . value value shift 4
+
+i5:
+EV -> E . else accept
+E -> E . op E op shift 1
+
+i2:
+E -> op . E goto(2,E)=6
+E -> . E op E goto(2,E)=6
+E -> . op E +,- shift 2
+E -> . ( E ) ( shift 3
+E -> . value value shift 4
+
+i3:
+E -> ( . E ) goto(3,E)=7
+E -> . E op E goto(3,E)=7
+E -> . op E +,- shift 2
+E -> . ( E ) ( shift 3
+E -> . value value shift 4
+
+i4:
+E -> value . reduce 5
+
+i1:
+E -> E op . E goto(1,E)=8
+E -> . E op E goto(1,E)=8
+E -> . op E +,- shift 2
+E -> . ( E ) ( shift 3
+E -> . value value shift 4
+
+i6:
+E -> op E . reduce 3
+E -> E . op E op* shift 1 *=if stack[-2] contains op of unary lower priority
+
+i7:
+E -> ( E . ) ) shift 9
+E -> E . op E op shift 1
+
+i8:
+E -> E op E . reduce 2
+E -> E . op E op* shift 1 *=if stack[-2] contains op of lower priority or if
+ if it is of equal priority and right associative
+
+i9:
+E -> ( E ) . reduce 4
+
+*/
+/*}}}*/
+static struct Value *eval(struct Value *value, const char *desc) /*{{{*/
+{
+ /* variables */ /*{{{*/
+ static const int gotoState[10]={ 5,8,6,7,-1,-1,-1,-1,-1,-1 };
+ int capacity=10;
+ struct Pdastack
+ {
+ union
+ {
+ enum TokenType token;
+ struct Value value;
+ } u;
+ char state;
+ };
+ struct Pdastack *pdastack=malloc(capacity*sizeof(struct Pdastack));
+ struct Pdastack *sp=pdastack;
+ struct Pdastack *stackEnd=pdastack+capacity-1;
+ enum TokenType ip;
+ /*}}}*/
+
+ sp->state=0;
+ while (1)
+ {
+ if (sp==stackEnd)
+ {
+ pdastack=realloc(pdastack,(capacity+10)*sizeof(struct Pdastack));
+ sp=pdastack+capacity-1;
+ capacity+=10;
+ stackEnd=pdastack+capacity-1;
+ }
+ ip=pc.token->type;
+ switch (sp->state)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3: /*{{{*/ /* including 4 */
+ {
+ if (ip==T_IDENTIFIER) /*{{{*/
+ {
+ /* printf("state %d: shift 4\n",sp->state); */
+ /* printf("state 4: reduce E -> value\n"); */
+ ++sp;
+ sp->state=gotoState[(sp-1)->state];
+ if (pass==COMPILE)
+ {
+ if
+ (
+ ((pc.token+1)->type==T_OP || Auto_find(&stack,pc.token->u.identifier)==0)
+ && Global_find(&globals,pc.token->u.identifier,(pc.token+1)->type==T_OP)==0
+ )
+ {
+ Value_new_ERROR(value,UNDECLARED);
+ goto error;
+ }
+ }
+ if (pass!=DECLARE && (pc.token->u.identifier->sym->type==GLOBALVAR || pc.token->u.identifier->sym->type==GLOBALARRAY || pc.token->u.identifier->sym->type==LOCALVAR))
+ {
+ struct Value *l;
+
+ if ((l=lvalue(value))->type==V_ERROR) goto error;
+ Value_clone(&sp->u.value,l);
+ }
+ else
+ {
+ struct Pc var=pc;
+
+ func(&sp->u.value);
+ if (sp->u.value.type==V_VOID)
+ {
+ pc=var;
+ Value_new_ERROR(value,VOIDVALUE);
+ goto error;
+ }
+ }
+ }
+ /*}}}*/
+ else if (ip==T_INTEGER) /*{{{*/
+ {
+ /* printf("state %d: shift 4\n",sp->state); */
+ /* printf("state 4: reduce E -> value\n"); */
+ ++sp;
+ sp->state=gotoState[(sp-1)->state];
+ VALUE_NEW_INTEGER(&sp->u.value,pc.token->u.integer);
+ ++pc.token;
+ }
+ /*}}}*/
+ else if (ip==T_REAL) /*{{{*/
+ {
+ /* printf("state %d: shift 4\n",sp->state); */
+ /* printf("state 4: reduce E -> value\n"); */
+ ++sp;
+ sp->state=gotoState[(sp-1)->state];
+ VALUE_NEW_REAL(&sp->u.value,pc.token->u.real);
+ ++pc.token;
+ }
+ /*}}}*/
+ else if (TOKEN_ISUNARYOPERATOR(ip)) /*{{{*/
+ {
+ /* printf("state %d: shift 2\n",sp->state); */
+ ++sp;
+ sp->state=2;
+ sp->u.token=ip;
+ ++pc.token;
+ }
+ /*}}}*/
+ else if (ip==T_HEXINTEGER) /*{{{*/
+ {
+ /* printf("state %d: shift 4\n",sp->state); */
+ /* printf("state 4: reduce E -> value\n"); */
+ ++sp;
+ sp->state=gotoState[(sp-1)->state];
+ VALUE_NEW_INTEGER(&sp->u.value,pc.token->u.hexinteger);
+ ++pc.token;
+ }
+ /*}}}*/
+ else if (ip==T_OCTINTEGER) /*{{{*/
+ {
+ /* printf("state %d: shift 4\n",sp->state); */
+ /* printf("state 4: reduce E -> value\n"); */
+ ++sp;
+ sp->state=gotoState[(sp-1)->state];
+ VALUE_NEW_INTEGER(&sp->u.value,pc.token->u.octinteger);
+ ++pc.token;
+ }
+ /*}}}*/
+ else if (ip==T_OP) /*{{{*/
+ {
+ /* printf("state %d: shift 3\n",sp->state); */
+ ++sp;
+ sp->state=3;
+ sp->u.token=T_OP;
+ ++pc.token;
+ }
+ /*}}}*/
+ else if (ip==T_STRING) /*{{{*/
+ {
+ /* printf("state %d: shift 4\n",sp->state); */
+ /* printf("state 4: reduce E -> value\n"); */
+ ++sp;
+ sp->state=gotoState[(sp-1)->state];
+ Value_new_STRING(&sp->u.value);
+ String_destroy(&sp->u.value.u.string);
+ String_clone(&sp->u.value.u.string,pc.token->u.string);
+ ++pc.token;
+ }
+ /*}}}*/
+ else /*{{{*/
+ {
+ char state=sp->state;
+
+ if (state==0)
+ {
+ if (desc) Value_new_ERROR(value,MISSINGEXPR,desc);
+ else value=(struct Value*)0;
+ }
+ else Value_new_ERROR(value,MISSINGEXPR,_("operand"));
+ goto error;
+ }
+ /*}}}*/
+ break;
+ }
+ /*}}}*/
+ case 5: /*{{{*/
+ {
+ if (TOKEN_ISBINARYOPERATOR(ip))
+ {
+ /* printf("state %d: shift 1\n",sp->state); */
+ ++sp;
+ sp->state=1;
+ sp->u.token=ip;
+ ++pc.token;
+ break;
+ }
+ else
+ {
+ assert(sp==pdastack+1);
+ *value=sp->u.value;
+ free(pdastack);
+ return value;
+ }
+ break;
+ }
+ /*}}}*/
+ case 6: /*{{{*/
+ {
+ if (TOKEN_ISBINARYOPERATOR(ip) && TOKEN_UNARYPRIORITY((sp-1)->u.token)<TOKEN_BINARYPRIORITY(ip))
+ {
+ assert(TOKEN_ISUNARYOPERATOR((sp-1)->u.token));
+ /* printf("state %d: shift 1 (not reducing E -> op E)\n",sp->state); */
+ ++sp;
+ sp->state=1;
+ sp->u.token=ip;
+ ++pc.token;
+ }
+ else
+ {
+ enum TokenType op;
+
+ /* printf("reduce E -> op E\n"); */
+ --sp;
+ op=sp->u.token;
+ sp->u.value=(sp+1)->u.value;
+ switch (op)
+ {
+ case T_PLUS: break;
+ case T_MINUS: Value_uneg(&sp->u.value,pass==INTERPRET); break;
+ case T_NOT: Value_unot(&sp->u.value,pass==INTERPRET); break;
+ default: assert(0);
+ }
+ sp->state=gotoState[(sp-1)->state];
+ if (sp->u.value.type==V_ERROR)
+ {
+ *value=sp->u.value;
+ --sp;
+ goto error;
+ }
+ }
+ break;
+ }
+ /*}}}*/
+ case 7: /*{{{*/ /* including 9 */
+ {
+ if (TOKEN_ISBINARYOPERATOR(ip))
+ {
+ /* printf("state %d: shift 1\n"sp->state); */
+ ++sp;
+ sp->state=1;
+ sp->u.token=ip;
+ ++pc.token;
+ }
+ else if (ip==T_CP)
+ {
+ /* printf("state %d: shift 9\n",sp->state); */
+ /* printf("state 9: reduce E -> ( E )\n"); */
+ --sp;
+ sp->state=gotoState[(sp-1)->state];
+ sp->u.value=(sp+1)->u.value;
+ ++pc.token;
+ }
+ else
+ {
+ Value_new_ERROR(value,MISSINGCP);
+ goto error;
+ }
+ break;
+ }
+ /*}}}*/
+ case 8: /*{{{*/
+ {
+ int p1,p2;
+
+ if
+ (
+ TOKEN_ISBINARYOPERATOR(ip)
+ &&
+ (
+ ((p1=TOKEN_BINARYPRIORITY((sp-1)->u.token))<(p2=TOKEN_BINARYPRIORITY(ip)))
+ || (p1==p2 && TOKEN_ISRIGHTASSOCIATIVE((sp-1)->u.token))
+ )
+ )
+ {
+ /* printf("state %d: shift 1\n",sp->state); */
+ ++sp;
+ sp->state=1;
+ sp->u.token=ip;
+ ++pc.token;
+ }
+ else
+ {
+ /* printf("state %d: reduce E -> E op E\n",sp->state); */
+ if (Value_commonType[(sp-2)->u.value.type][sp->u.value.type]==V_ERROR)
+ {
+ Value_destroy(&sp->u.value);
+ sp-=2;
+ Value_destroy(&sp->u.value);
+ Value_new_ERROR(value,INVALIDOPERAND);
+ --sp;
+ goto error;
+ }
+ else switch ((sp-1)->u.token)
+ {
+ case T_LT: Value_lt(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_LE: Value_le(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_EQ: Value_eq(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_GE: Value_ge(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_GT: Value_gt(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_NE: Value_ne(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_PLUS: Value_add(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_MINUS: Value_sub(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_MULT: Value_mult(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_DIV: Value_div(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_IDIV: Value_idiv(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_MOD: Value_mod(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_POW: Value_pow(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_AND: Value_and(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_OR: Value_or(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_XOR: Value_xor(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_EQV: Value_eqv(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ case T_IMP: Value_imp(&(sp-2)->u.value,&sp->u.value,pass==INTERPRET); break;
+ default: assert(0);
+ }
+ Value_destroy(&sp->u.value);
+ sp-=2;
+ sp->state=gotoState[(sp-1)->state];
+ if (sp->u.value.type==V_ERROR)
+ {
+ *value=sp->u.value;
+ --sp;
+ goto error;
+ }
+ }
+ break;
+ }
+ /*}}}*/
+ }
+ }
+ error:
+ while (sp>pdastack)
+ {
+ switch (sp->state)
+ {
+ case 5:
+ case 6:
+ case 7:
+ case 8: Value_destroy(&sp->u.value);
+ }
+ --sp;
+ }
+ free(pdastack);
+ return value;
+}
+/*}}}*/
+#else
+static inline struct Value *binarydown(struct Value *value, struct Value *(level)(struct Value *value), const int prio) /*{{{*/
+{
+ enum TokenType op;
+ struct Pc oppc;
+
+ if (level(value)==(struct Value*)0) return (struct Value*)0;
+ if (value->type==V_ERROR) return value;
+ do
+ {
+ struct Value x;
+
+ op=pc.token->type;
+ if (!TOKEN_ISBINARYOPERATOR(op) || TOKEN_BINARYPRIORITY(op)!=prio) return value;
+ oppc=pc;
+ ++pc.token;
+ if (level(&x)==(struct Value*)0)
+ {
+ Value_destroy(value);
+ return Value_new_ERROR(value,MISSINGEXPR,_("binary operand"));
+ }
+ if (x.type==V_ERROR)
+ {
+ Value_destroy(value);
+ *value=x;
+ return value;
+ }
+ if (Value_commonType[value->type][x.type]==V_ERROR)
+ {
+ Value_destroy(value);
+ Value_destroy(&x);
+ return Value_new_ERROR(value,INVALIDOPERAND);
+ }
+ else switch (op)
+ {
+ case T_LT: Value_lt(value,&x,pass==INTERPRET); break;
+ case T_LE: Value_le(value,&x,pass==INTERPRET); break;
+ case T_EQ: Value_eq(value,&x,pass==INTERPRET); break;
+ case T_GE: Value_ge(value,&x,pass==INTERPRET); break;
+ case T_GT: Value_gt(value,&x,pass==INTERPRET); break;
+ case T_NE: Value_ne(value,&x,pass==INTERPRET); break;
+ case T_PLUS: Value_add(value,&x,pass==INTERPRET); break;
+ case T_MINUS: Value_sub(value,&x,pass==INTERPRET); break;
+ case T_MULT: Value_mult(value,&x,pass==INTERPRET); break;
+ case T_DIV: Value_div(value,&x,pass==INTERPRET); break;
+ case T_IDIV: Value_idiv(value,&x,pass==INTERPRET); break;
+ case T_MOD: Value_mod(value,&x,pass==INTERPRET); break;
+ case T_POW: Value_pow(value,&x,pass==INTERPRET); break;
+ case T_AND: Value_and(value,&x,pass==INTERPRET); break;
+ case T_OR: Value_or(value,&x,pass==INTERPRET); break;
+ case T_XOR: Value_xor(value,&x,pass==INTERPRET); break;
+ case T_EQV: Value_eqv(value,&x,pass==INTERPRET); break;
+ case T_IMP: Value_imp(value,&x,pass==INTERPRET); break;
+ default: assert(0);
+ }
+ Value_destroy(&x);
+ } while (value->type!=V_ERROR);
+ if (value->type==V_ERROR) pc=oppc;
+ return value;
+}
+/*}}}*/
+static inline struct Value *unarydown(struct Value *value, struct Value *(level)(struct Value *value), const int prio) /*{{{*/
+{
+ enum TokenType op;
+ struct Pc oppc;
+
+ op=pc.token->type;
+ if (!TOKEN_ISUNARYOPERATOR(op) || TOKEN_UNARYPRIORITY(op)!=prio) return level(value);
+ oppc=pc;
+ ++pc.token;
+ if (unarydown(value,level,prio)==(struct Value*)0) return Value_new_ERROR(value,MISSINGEXPR,_("unary operand"));
+ if (value->type==V_ERROR) return value;
+ switch (op)
+ {
+ case T_PLUS: Value_uplus(value,pass==INTERPRET); break;
+ case T_MINUS: Value_uneg(value,pass==INTERPRET); break;
+ case T_NOT: Value_unot(value,pass==INTERPRET); break;
+ default: assert(0);
+ }
+ if (value->type==V_ERROR) pc=oppc;
+ return value;
+}
+/*}}}*/
+static struct Value *eval8(struct Value *value) /*{{{*/
+{
+ switch (pc.token->type)
+ {
+ case T_IDENTIFIER: /*{{{*/
+ {
+ struct Pc var;
+ struct Value *l;
+
+ var=pc;
+ if (pass==COMPILE)
+ {
+ if
+ (
+ ((pc.token+1)->type==T_OP || Auto_find(&stack,pc.token->u.identifier)==0)
+ && Global_find(&globals,pc.token->u.identifier,(pc.token+1)->type==T_OP)==0
+ ) return Value_new_ERROR(value,UNDECLARED);
+ }
+ assert(pass==DECLARE || pc.token->u.identifier->sym);
+ if (pass!=DECLARE && (pc.token->u.identifier->sym->type==GLOBALVAR || pc.token->u.identifier->sym->type==GLOBALARRAY || pc.token->u.identifier->sym->type==LOCALVAR))
+ {
+ if ((l=lvalue(value))->type==V_ERROR) return value;
+ Value_clone(value,l);
+ }
+ else
+ {
+ func(value);
+ if (value->type==V_VOID)
+ {
+ Value_destroy(value);
+ pc=var;
+ return Value_new_ERROR(value,VOIDVALUE);
+ }
+ }
+ break;
+ }
+ /*}}}*/
+ case T_INTEGER: /*{{{*/
+ {
+ VALUE_NEW_INTEGER(value,pc.token->u.integer);
+ ++pc.token;
+ break;
+ }
+ /*}}}*/
+ case T_REAL: /*{{{*/
+ {
+ VALUE_NEW_REAL(value,pc.token->u.real);
+ ++pc.token;
+ break;
+ }
+ /*}}}*/
+ case T_STRING: /*{{{*/
+ {
+ Value_new_STRING(value);
+ String_destroy(&value->u.string);
+ String_clone(&value->u.string,pc.token->u.string);
+ ++pc.token;
+ break;
+ }
+ /*}}}*/
+ case T_HEXINTEGER: /*{{{*/
+ {
+ VALUE_NEW_INTEGER(value,pc.token->u.hexinteger);
+ ++pc.token;
+ break;
+ }
+ /*}}}*/
+ case T_OCTINTEGER: /*{{{*/
+ {
+ VALUE_NEW_INTEGER(value,pc.token->u.octinteger);
+ ++pc.token;
+ break;
+ }
+ /*}}}*/
+ case T_OP: /*{{{*/
+ {
+ ++pc.token;
+ if (eval(value,_("parenthetic"))->type==V_ERROR) return value;
+ if (pc.token->type!=T_CP)
+ {
+ Value_destroy(value);
+ return Value_new_ERROR(value,MISSINGCP);
+ }
+ ++pc.token;
+ break;
+ }
+ /*}}}*/
+ default: /*{{{*/
+ {
+ return (struct Value *)0;
+ }
+ /*}}}*/
+ }
+ return value;
+}
+/*}}}*/
+static struct Value *eval7(struct Value *value) /*{{{*/
+{
+ return binarydown(value,eval8,7);
+}
+/*}}}*/
+static struct Value *eval6(struct Value *value) /*{{{*/
+{
+ return unarydown(value,eval7,6);
+}
+/*}}}*/
+static struct Value *eval5(struct Value *value) /*{{{*/
+{
+ return binarydown(value,eval6,5);
+}
+/*}}}*/
+static struct Value *eval4(struct Value *value) /*{{{*/
+{
+ return binarydown(value,eval5,4);
+}
+/*}}}*/
+static struct Value *eval3(struct Value *value) /*{{{*/
+{
+ return binarydown(value,eval4,3);
+}
+/*}}}*/
+static struct Value *eval2(struct Value *value) /*{{{*/
+{
+ return unarydown(value,eval3,2);
+}
+/*}}}*/
+static struct Value *eval1(struct Value *value) /*{{{*/
+{
+ return binarydown(value,eval2,1);
+}
+/*}}}*/
+static struct Value *eval(struct Value *value, const char *desc) /*{{{*/
+{
+ /* avoid function calls for atomic expression */
+ switch (pc.token->type)
+ {
+ case T_STRING:
+ case T_REAL:
+ case T_INTEGER:
+ case T_HEXINTEGER:
+ case T_OCTINTEGER:
+ case T_IDENTIFIER: if (!TOKEN_ISBINARYOPERATOR((pc.token+1)->type) && (pc.token+1)->type!=T_OP) return eval7(value);
+ default: break;
+ }
+ if (binarydown(value,eval1,0)==(struct Value*)0)
+ {
+ if (desc) return Value_new_ERROR(value,MISSINGEXPR,desc);
+ else return (struct Value*)0;
+ }
+ else return value;
+}
+/*}}}*/
+#endif
+
+static void new(void) /*{{{*/
+{
+ Global_destroy(&globals);
+ Global_new(&globals);
+ Auto_destroy(&stack);
+ Auto_new(&stack);
+ Program_destroy(&program);
+ Program_new(&program);
+ FS_closefiles();
+ optionbase=0;
+}
+/*}}}*/
+static void pushLabel(enum LabelType type, struct Pc *patch) /*{{{*/
+{
+ if (labelStackPointer==labelStackCapacity)
+ {
+ struct LabelStack *more;
+
+ more=realloc(labelStack,sizeof(struct LabelStack)*(labelStackCapacity?(labelStackCapacity*=2):(32)));
+ labelStack=more;
+ }
+ labelStack[labelStackPointer].type=type;
+ labelStack[labelStackPointer].patch=*patch;
+ ++labelStackPointer;
+}
+/*}}}*/
+static struct Pc *popLabel(enum LabelType type) /*{{{*/
+{
+ if (labelStackPointer==0 || labelStack[labelStackPointer-1].type!=type) return (struct Pc*)0;
+ else return &labelStack[--labelStackPointer].patch;
+}
+/*}}}*/
+static struct Pc *findLabel(enum LabelType type) /*{{{*/
+{
+ int i;
+
+ for (i=labelStackPointer-1; i>=0; --i) if (labelStack[i].type==type) return &labelStack[i].patch;
+ return (struct Pc*)0;
+}
+/*}}}*/
+static void labelStackError(struct Value *v) /*{{{*/
+{
+ assert(labelStackPointer);
+ pc=labelStack[labelStackPointer-1].patch;
+ switch (labelStack[labelStackPointer-1].type)
+ {
+ case L_IF: Value_new_ERROR(v,STRAYIF); break;
+ case L_DO: Value_new_ERROR(v,STRAYDO); break;
+ case L_DOcondition: Value_new_ERROR(v,STRAYDOcondition); break;
+ case L_ELSE: Value_new_ERROR(v,STRAYELSE2); break;
+ case L_FOR_BODY:
+ {
+ Value_new_ERROR(v,STRAYFOR);
+ pc=*findLabel(L_FOR);
+ break;
+ }
+ case L_WHILE: Value_new_ERROR(v,STRAYWHILE); break;
+ case L_REPEAT: Value_new_ERROR(v,STRAYREPEAT); break;
+ case L_SELECTCASE: Value_new_ERROR(v,STRAYSELECTCASE); break;
+ case L_FUNC: Value_new_ERROR(v,STRAYFUNC); break;
+ default: assert(0);
+ }
+}
+/*}}}*/
+static const char *topLabelDescription(void) /*{{{*/
+{
+ if (labelStackPointer==0)
+ {
+ return _("program");
+ }
+ switch (labelStack[labelStackPointer-1].type)
+ {
+ case L_IF: return _("`if' branch");
+ case L_DO: return _("`do' loop");
+ case L_DOcondition: return _("`do while' or `do until' loop");
+ case L_ELSE: return _("`else' branch");
+ case L_FOR_BODY: return _("`for' loop");
+ case L_WHILE: return _("`while' loop");
+ case L_REPEAT: return _("`repeat' loop");
+ case L_SELECTCASE: return _("`select case' control structure");
+ case L_FUNC: return _("function or procedure");
+ default: assert(0);
+ }
+ /* NOTREACHED */
+ return (const char*)0;
+}
+/*}}}*/
+static struct Value *assign(struct Value *value) /*{{{*/
+{
+ struct Pc expr;
+
+ if (strcasecmp(pc.token->u.identifier->name,"mid$")==0) /* mid$(a$,n,m)=b$ */ /*{{{*/
+ {
+ long int n,m;
+ struct Value *l;
+
+ ++pc.token;
+ if (pc.token->type!=T_OP) return Value_new_ERROR(value,MISSINGOP);
+ ++pc.token;
+ if (pc.token->type!=T_IDENTIFIER) return Value_new_ERROR(value,MISSINGSTRIDENT);
+ if (pass==DECLARE)
+ {
+ if
+ (
+ ((pc.token+1)->type==T_OP || Auto_find(&stack,pc.token->u.identifier)==0)
+ && Global_variable(&globals,pc.token->u.identifier,pc.token->u.identifier->defaultType,(pc.token+1)->type==T_OP?GLOBALARRAY:GLOBALVAR,0)==0
+ )
+ {
+ return Value_new_ERROR(value,REDECLARATION);
+ }
+ }
+ if ((l=lvalue(value))->type==V_ERROR) return value;
+ if (pass==COMPILE && l->type!=V_STRING) return Value_new_ERROR(value,TYPEMISMATCH4);
+ if (pc.token->type!=T_COMMA) return Value_new_ERROR(value,MISSINGCOMMA);
+ ++pc.token;
+ if (eval(value,_("position"))->type==V_ERROR || Value_retype(value,V_INTEGER)->type==V_ERROR) return value;
+ n=value->u.integer;
+ Value_destroy(value);
+ if (pass==INTERPRET && n<1) return Value_new_ERROR(value,OUTOFRANGE,"position");
+ if (pc.token->type==T_COMMA)
+ {
+ ++pc.token;
+ if (eval(value,_("length"))->type==V_ERROR || Value_retype(value,V_INTEGER)->type==V_ERROR) return value;
+ m=value->u.integer;
+ if (pass==INTERPRET && m<0) return Value_new_ERROR(value,OUTOFRANGE,_("length"));
+ Value_destroy(value);
+ }
+ else m=-1;
+ if (pc.token->type!=T_CP) return Value_new_ERROR(value,MISSINGCP);
+ ++pc.token;
+ if (pc.token->type!=T_EQ) return Value_new_ERROR(value,MISSINGEQ);
+ ++pc.token;
+ if (eval(value,_("rhs"))->type==V_ERROR || Value_retype(value,V_STRING)->type==V_ERROR) return value;
+ if (pass==INTERPRET)
+ {
+ if (m==-1) m=value->u.string.length;
+ String_set(&l->u.string,n-1,&value->u.string,m);
+ }
+ }
+ /*}}}*/
+ else /*{{{*/
+ {
+ struct Value **l=(struct Value**)0;
+ int i, used=0, capacity=0;
+ struct Value retyped_value;
+
+ for (;;)
+ {
+ if (used==capacity)
+ {
+ struct Value **more;
+
+ capacity=capacity?2*capacity:2;
+ more=realloc(l,capacity*sizeof(*l));
+ l=more;
+ }
+
+ if (pass==DECLARE)
+ {
+ if
+ (
+ ((pc.token+1)->type==T_OP || Auto_find(&stack,pc.token->u.identifier)==0)
+ && Global_variable(&globals,pc.token->u.identifier,pc.token->u.identifier->defaultType,(pc.token+1)->type==T_OP?GLOBALARRAY:GLOBALVAR,0)==0
+ )
+ {
+ if (capacity) free(l);
+ return Value_new_ERROR(value,REDECLARATION);
+ }
+ }
+ if ((l[used]=lvalue(value))->type==V_ERROR) return value;
+ ++used;
+ if (pc.token->type==T_COMMA) ++pc.token;
+ else break;
+ }
+ if (pc.token->type!=T_EQ) return Value_new_ERROR(value,MISSINGEQ);
+ ++pc.token;
+ expr=pc;
+ if (eval(value,_("rhs"))->type==V_ERROR) return value;
+ for (i=0; i<used; ++i)
+ {
+ Value_clone(&retyped_value,value);
+ if (pass!=DECLARE && VALUE_RETYPE(&retyped_value,(l[i])->type)->type==V_ERROR)
+ {
+ pc=expr;
+ free(l);
+ Value_destroy(value);
+ *value=retyped_value;
+ return value;
+ }
+ if (pass==INTERPRET)
+ {
+ Value_destroy(l[i]);
+ *(l[i])=retyped_value;
+ }
+ }
+ free(l);
+ Value_destroy(value);
+ *value=retyped_value; /* for status only */
+ }
+ /*}}}*/
+ return value;
+}
+/*}}}*/
+static struct Value *compileProgram(struct Value *v, int clearGlobals) /*{{{*/
+{
+ struct Pc begin;
+
+ stack.resumeable=0;
+ if (clearGlobals)
+ {
+ Global_destroy(&globals);
+ Global_new(&globals);
+ }
+ else Global_clearFunctions(&globals);
+ if (Program_beginning(&program,&begin))
+ {
+ struct Pc savepc;
+ int savepass;
+
+ savepc=pc;
+ savepass=pass;
+ Program_norun(&program);
+ for (pass=DECLARE; pass!=INTERPRET; ++pass)
+ {
+ if (pass==DECLARE)
+ {
+ stack.begindata.line=-1;
+ lastdata=&stack.begindata;
+ }
+ optionbase=0;
+ FS_intr=0;
+ stopped=0;
+ program.runnable=1;
+ pc=begin;
+ while (1)
+ {
+ statements(v);
+ if (v->type==V_ERROR) break;
+ Value_destroy(v);
+ if (!Program_skipEOL(&program,&pc,0,0)) { Value_new_NIL(v); break; }
+ }
+ if (v->type!=V_ERROR && labelStackPointer>0)
+ {
+ Value_destroy(v);
+ labelStackError(v);
+ }
+ if (v->type==V_ERROR)
+ {
+ labelStackPointer=0;
+ Program_norun(&program);
+ if (stack.cur) Auto_funcEnd(&stack); /* Always correct? */
+ pass=savepass;
+ return v;
+ }
+ }
+ pc=begin;
+ if (Program_analyse(&program,&pc,v))
+ {
+ labelStackPointer=0;
+ Program_norun(&program);
+ if (stack.cur) Auto_funcEnd(&stack); /* Always correct? */
+ pass=savepass;
+ return v;
+ }
+ curdata=stack.begindata;
+ pc=savepc;
+ pass=savepass;
+ }
+ return Value_new_NIL(v);
+}
+/*}}}*/
+static void runline(struct Token *line) /*{{{*/
+{
+ struct Value value;
+
+ FS_flush(STDCHANNEL);
+ for (pass=DECLARE; pass!=INTERPRET; ++pass)
+ {
+ curdata.line=-1;
+ pc.line=-1;
+ pc.token=line;
+ optionbase=0;
+ FS_intr=0;
+ stopped=0;
+ statements(&value);
+ if (value.type!=V_ERROR && pc.token->type!=T_EOL)
+ {
+ Value_destroy(&value);
+ Value_new_ERROR(&value,SYNTAX);
+ }
+ if (value.type!=V_ERROR && labelStackPointer>0)
+ {
+ Value_destroy(&value);
+ labelStackError(&value);
+ }
+ if (value.type==V_ERROR)
+ {
+ struct String s;
+
+ Auto_setError(&stack,Program_lineNumber(&program,&pc),&pc,&value);
+ Program_PCtoError(&program,&pc,&value);
+ labelStackPointer=0;
+ FS_putChars(STDCHANNEL,_("Error: "));
+ String_new(&s);
+ Value_toString(&value,&s,' ',-1,0,0,0,0,-1,0,0);
+ Value_destroy(&value);
+ FS_putString(STDCHANNEL,&s);
+ String_destroy(&s);
+ return;
+ }
+ if (!program.runnable && pass==COMPILE)
+ {
+ Value_destroy(&value);
+ (void)compileProgram(&value,0);
+ }
+ }
+
+ pc.line=-1;
+ pc.token=line;
+ optionbase=0;
+ curdata=stack.begindata;
+ nextdata.line=-1;
+ Value_destroy(&value);
+ pass=INTERPRET;
+ FS_allowIntr(1);
+ do
+ {
+ assert(pass==INTERPRET);
+ statements(&value);
+ assert(pass==INTERPRET);
+ if (value.type==V_ERROR)
+ {
+ if (strchr(value.u.error.msg,'\n')==(char*)0)
+ {
+ Auto_setError(&stack,Program_lineNumber(&program,&pc),&pc,&value);
+ Program_PCtoError(&program,&pc,&value);
+ }
+ if (stack.onerror.line!=-1)
+ {
+ stack.resumeable=1;
+ pc=stack.onerror;
+ }
+ else
+ {
+ struct String s;
+
+ String_new(&s);
+ if (!stopped)
+ {
+ stopped=0;
+ FS_putChars(STDCHANNEL,_("Error: "));
+ }
+ Auto_frameToError(&stack,&program,&value);
+ Value_toString(&value,&s,' ',-1,0,0,0,0,-1,0,0);
+ while (Auto_gosubReturn(&stack,(struct Pc*)0));
+ FS_putString(STDCHANNEL,&s);
+ String_destroy(&s);
+ Value_destroy(&value);
+ break;
+ }
+ }
+ Value_destroy(&value);
+ } while (pc.token->type!=T_EOL || Program_skipEOL(&program,&pc,STDCHANNEL,1));
+ FS_allowIntr(0);
+}
+/*}}}*/
+static struct Value *evalGeometry(struct Value *value, unsigned int *dim, unsigned int geometry[]) /*{{{*/
+{
+ struct Pc exprpc=pc;
+
+ if (eval(value,_("dimension"))->type==V_ERROR || (pass!=DECLARE && Value_retype(value,V_INTEGER)->type==V_ERROR)) return value;
+ if (pass==INTERPRET && value->u.integer<optionbase)
+ {
+ Value_destroy(value);
+ pc=exprpc;
+ return Value_new_ERROR(value,OUTOFRANGE,_("dimension"));
+ }
+ geometry[0]=value->u.integer-optionbase+1;
+ Value_destroy(value);
+ if (pc.token->type==T_COMMA)
+ {
+ ++pc.token;
+ exprpc=pc;
+ if (eval(value,_("dimension"))->type==V_ERROR || (pass!=DECLARE && Value_retype(value,V_INTEGER)->type==V_ERROR)) return value;
+ if (pass==INTERPRET && value->u.integer<optionbase)
+ {
+ Value_destroy(value);
+ pc=exprpc;
+ return Value_new_ERROR(value,OUTOFRANGE,_("dimension"));
+ }
+ geometry[1]=value->u.integer-optionbase+1;
+ Value_destroy(value);
+ *dim=2;
+ }
+ else *dim=1;
+ if (pc.token->type==T_CP) ++pc.token;
+ else return Value_new_ERROR(value,MISSINGCP);
+ return (struct Value*)0;
+}
+/*}}}*/
+static struct Value *convert(struct Value *value, struct Value *l, struct Token *t) /*{{{*/
+{
+ switch (l->type)
+ {
+ case V_INTEGER:
+ {
+ char *datainput;
+ char *end;
+ long int v;
+ int overflow;
+
+ if (t->type!=T_DATAINPUT) return Value_new_ERROR(value,BADCONVERSION,_("integer"));
+ datainput=t->u.datainput;
+ v=Value_vali(datainput,&end,&overflow);
+ if (end==datainput || (*end!='\0' && *end!=' ' && *end!='\t')) return Value_new_ERROR(value,BADCONVERSION,_("integer"));
+ if (overflow) return Value_new_ERROR(value,OUTOFRANGE,_("converted value"));
+ Value_destroy(l);
+ VALUE_NEW_INTEGER(l,v);
+ break;
+ }
+ case V_REAL:
+ {
+ char *datainput;
+ char *end;
+ double v;
+ int overflow;
+
+ if (t->type!=T_DATAINPUT) return Value_new_ERROR(value,BADCONVERSION,_("real"));
+ datainput=t->u.datainput;
+ v=Value_vald(datainput,&end,&overflow);
+ if (end==datainput || (*end!='\0' && *end!=' ' && *end!='\t')) return Value_new_ERROR(value,BADCONVERSION,_("real"));
+ if (overflow) return Value_new_ERROR(value,OUTOFRANGE,_("converted value"));
+ Value_destroy(l);
+ VALUE_NEW_REAL(l,v);
+ break;
+ }
+ case V_STRING:
+ {
+ Value_destroy(l);
+ Value_new_STRING(l);
+ if (t->type==T_STRING) String_appendString(&l->u.string,t->u.string);
+ else String_appendChars(&l->u.string,t->u.datainput);
+ break;
+ }
+ default: assert(0);
+ }
+ return (struct Value*)0;
+}
+/*}}}*/
+static struct Value *dataread(struct Value *value, struct Value *l) /*{{{*/
+{
+ if (curdata.line==-1)
+ {
+ return Value_new_ERROR(value,ENDOFDATA);
+ }
+ if (curdata.token->type==T_DATA)
+ {
+ nextdata=curdata.token->u.nextdata;
+ ++curdata.token;
+ }
+ if (convert(value,l,curdata.token))
+ {
+ return value;
+ }
+ ++curdata.token;
+ if (curdata.token->type==T_COMMA) ++curdata.token;
+ else curdata=nextdata;
+ return (struct Value*)0;
+}
+/*}}}*/
+static struct Value more_statements;
+#include "statement.c"
+static struct Value *statements(struct Value *value) /*{{{*/
+{
+ more:
+ if (pc.token->statement)
+ {
+ struct Value *v;
+
+ if ((v=pc.token->statement(value)))
+ {
+ if (v==&more_statements) goto more;
+ else return value;
+ }
+ }
+ else return Value_new_ERROR(value,MISSINGSTATEMENT);
+
+ if (FS_intr)
+ {
+ stopped=1;
+ return Value_new_ERROR(value,BREAK);
+ }
+ else if (pc.token->type==T_COLON && (pc.token+1)->type==T_ELSE) ++pc.token;
+ else if ((pc.token->type==T_COLON && (pc.token+1)->type!=T_ELSE) || pc.token->type==T_QUOTE)
+ {
+ ++pc.token;
+ goto more;
+ }
+ else if ((pass==DECLARE || pass==COMPILE) && pc.token->type!=T_EOL && pc.token->type!=T_ELSE)
+ {
+ return Value_new_ERROR(value,MISSINGCOLON);
+ }
+ return Value_new_NIL(value);
+}
+/*}}}*/
+
+void bas_init(int backslash_colon, int restricted, int uppercase, int lpfd) /*{{{*/
+{
+#ifdef HAVE_GETTEXT
+ bindtextdomain("bas",LOCALEDIR);
+ textdomain("bas");
+#endif
+ stack.begindata.line=-1;
+ Token_init(backslash_colon,uppercase);
+ Global_new(&globals);
+ Auto_new(&stack);
+ Program_new(&program);
+ FS_opendev(STDCHANNEL,0,1);
+ FS_opendev(LPCHANNEL,-1,lpfd);
+ run_restricted=restricted;
+}
+/*}}}*/
+void bas_runFile(const char *runFile) /*{{{*/
+{
+ struct Value value;
+ int dev;
+
+ new();
+ if ((dev=FS_openin(runFile))==-1)
+ {
+ const char *errmsg=FS_errmsg;
+
+ FS_putChars(0,_("bas: Executing `"));
+ FS_putChars(0,runFile);
+ FS_putChars(0,_("' failed ("));
+ FS_putChars(0,errmsg);
+ FS_putChars(0,_(").\n"));
+ }
+ else if (Program_merge(&program,dev,&value))
+ {
+ struct String s;
+
+ FS_putChars(0,"bas: ");
+ String_new(&s);
+ Value_toString(&value,&s,' ',-1,0,0,0,0,-1,0,0);
+ FS_putString(0,&s);
+ String_destroy(&s);
+ FS_putChar(0,'\n');
+ Value_destroy(&value);
+ }
+ else
+ {
+ struct Token line[2];
+
+ Program_setname(&program,runFile);
+ line[0].type=T_RUN;
+ line[0].statement=stmt_RUN;
+ line[1].type=T_EOL;
+ line[1].statement=stmt_COLON_EOL;
+
+ FS_close(dev);
+ runline(line);
+ }
+}
+/*}}}*/
+void bas_runLine(const char *runLine) /*{{{*/
+{
+ struct Token *line;
+
+ line=Token_newCode(runLine);
+ runline(line+1);
+ Token_destroy(line);
+}
+/*}}}*/
+void bas_interpreter(void) /*{{{*/
+{
+ if (FS_istty(STDCHANNEL))
+ {
+ //FS_putChars(STDCHANNEL,"bas " VERSION "\n"); //acassis: fix it
+ FS_putChars(STDCHANNEL,"Copyright 1999-2014 Michael Haardt.\n");
+ FS_putChars(STDCHANNEL,_("This is free software with ABSOLUTELY NO WARRANTY.\n"));
+ }
+ new();
+ while (1)
+ {
+ struct Token *line;
+ struct String s;
+
+ FS_intr=0; stopped=0;
+ FS_allowIntr(1);
+ FS_nextline(STDCHANNEL);
+ if (FS_istty(STDCHANNEL)) FS_putChars(STDCHANNEL,"> ");
+ FS_flush(STDCHANNEL);
+ String_new(&s);
+ if (FS_appendToString(STDCHANNEL,&s,1)==-1)
+ {
+ if (FS_intr)
+ {
+ FS_putChars(STDCHANNEL,_("\nBreak\n"));
+ FS_flush(STDCHANNEL);
+ String_destroy(&s);
+ continue;
+ }
+ else
+ {
+ FS_putChars(STDCHANNEL,FS_errmsg);
+ FS_flush(STDCHANNEL);
+ String_destroy(&s);
+ break;
+ }
+ }
+ if (s.length==0)
+ {
+ String_destroy(&s);
+ break;
+ }
+ line=Token_newCode(s.character);
+ String_destroy(&s);
+ if (line->type!=T_EOL)
+ {
+ if (line->type==T_INTEGER && line->u.integer>0)
+ {
+ if (program.numbered)
+ {
+ if ((line+1)->type==T_EOL)
+ {
+ struct Pc where;
+
+ if (Program_goLine(&program,line->u.integer,&where)==(struct Pc*)0) FS_putChars(STDCHANNEL,(NOSUCHLINE));
+ else Program_delete(&program,&where,&where);
+ Token_destroy(line);
+ }
+ else Program_store(&program,line,line->u.integer);
+ }
+ else
+ {
+ FS_putChars(STDCHANNEL,_("Use `renum' to number program first"));
+ Token_destroy(line);
+ }
+ }
+ else if (line->type==T_UNNUMBERED)
+ {
+ runline(line+1);
+ Token_destroy(line);
+ if (FS_istty(STDCHANNEL) && bas_end>0)
+ {
+ FS_putChars(STDCHANNEL,_("END program\n"));
+ bas_end=0;
+ }
+ }
+ else
+ {
+ FS_putChars(STDCHANNEL,_("Invalid line\n"));
+ Token_destroy(line);
+ }
+ }
+ else Token_destroy(line);
+ }
+ FS_allowIntr(0);
+}
+/*}}}*/
+void bas_exit(void) /*{{{*/
+{
+ Auto_destroy(&stack);
+ Global_destroy(&globals);
+ Program_destroy(&program);
+ if (labelStack) free(labelStack);
+ FS_closefiles();
+ FS_close(LPCHANNEL);
+ FS_close(STDCHANNEL);
+}
+/*}}}*/