generated html version of scrip77.cHOME

#define true
true /*
if [ "$1" = 'simple' ]
then
cc $0 -Wall -Wextra -lm -fwrapv -o scrip7
else
echo "Compiling binaries and extracting doc and test..."
cc $0 -Wall -Wextra -lm -fwrapv -o scrip7 2>err
cc -DNOS7MAIN $0 -c -lm -fwrapv -o scrip7.o 2>>err
head err
sed -n '/B[E]GINHEADER/,/E[N]DHEADER/p' $0 >scrip7.h
cat >s7docs.txt <<END
Author: Oren Watson
Scrip77 hopefully getting stabler release 2015-08-22
You can extract and compile the full distribution simply by running this file
as a shell script like sh scrip77.c This produces the interpreter scrip7,
the library scrip7.o, and the documentation docs.txt. To include, include
scrip7.h. If your platform does not support weak symbols, you will also
need to define NOS7MAIN when including it.

Language Description:
A scrip77 program or script consists of statements and labels.
Labels are #text# between hashes. When a program is loaded,
its labels' locations are stored in variables named with the text.
Statements consist of a register letter, an optional offset, an operator,
and either a literal, or another register and optional offset.
There are 6 registers which store memory addresses, and whose notation
depends on the type of data they are being used to point to. The data types
in scrip7 are: 8 bit integers, 16 bit integers, 32 bit integers, 64 bit
integers, 32 bit floating point, 64 bit floating point, pointers, and the
"address" pseudo type which means accessing the address the register stores.
The notation for registers is in the following table:
int8 int16 int32 int64 float double pointer addr
  a    A     i     I     u     U      o      O
  b    B     j     J     v     V      p      P
  c    C     k     K     w     W      q      Q
  d    D     l     L     x     X      r      R
  e    E     m     M     y     Y      s      S
  f    F     n     N     z     Z      t      T
                   g           g      g      G
                   h           h      h      H
A special register called _ is supported for the first register in a statement.
It is zero when read, and does nothing when written to. g and h are relatively
normal registers, with VARIANT type adjusting between double, int64, and
pointer depending on the other operand.
The offsets are added to the address of the accessed data. An offset of
the form (1234 counts by bytes. An offset of the form )1234 counts by
the size of the addressed data type.
The literal syntax is as follows:
1234    Decimal integer.
%34af   Hexadecimal integer. Only lowercase letters are allowed.
	A space at the end is mandatory.
3%ff    Repeated hex. 3%ff is equivalent to %ffffffff .
12.34   Decimal floating point number.
12/34   Fractional floating point number.
1.23^4  Decimal floating point with decimal exponent.
"..."   Delimited string. escapes within string are:
        \@,\A thru \_ are used for character 0 to 31.
        also c escapes \n\t\v\a\b\e and \r can be used.
3"foo   Hollerith constant string. end " is not allowed or needed.
'a      Character constant. No ' after it.
The operators have a common semantics where usually only the first register's
data or address (hereafter called the destination) is modified, and the
second operand (hereafter called the source) is only read.
If the second operand is a literal, or the first operand is the _ register,
modifying it does nothing.
Command List:
END
grep "^	\+brase '.*': //\|^	\+//DOCS" $0 | sed \
	-e 's#.*brase '\''[\]\?#α#' -e 's#'\'': //#β #' -e 's#dest#α#' \
	-e 's#src#β#' -e 's#.*\//DOCS##' >>s7docs.txt
fi
exit 0
*/
//BEGINHEADER
#include "stdio.h"
#include "stdint.h"
extern int s7logflag,s7errflag,s7memsafe;
/*Declarations for non-static*/
void scrip7(char *code);
/*execute string*/
void scrip7f(FILE *code);
/*execute whole file as a series of programs.*/
int scrip7rc(FILE *code);
/*execute a program, ending with .\n, returns 0 if the program was empty.*/
void scrip7cli(FILE *code);
/*execute a set of programs, ending with an empty program.*/
struct va7 {int64_t c;double x;char *p;};
extern struct scrip7state{
	char *v[8];
	char *data;
	struct scrip7var *vars;
}globa7;
void se7var(char *name,struct va7 val);
struct va7 ge7var(char *name);
//ENDHEADER
char scrap[1000];
struct scrip7state globa7 = {{0,0,0,0,0,0,0,0},scrap,0};
int s7logflag=0;
int s7freeflag=0;
int s7errflag=1;

#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "inttypes.h"
#include "stddef.h"
#include "unistd.h"
#define ei else if
#define un(x) if(!(x))
#define wh while
#define loop for(;;)
#define brase break;case
#define brault break;default
#define sut struct
#define knz const
#define let(x,y) typeof(y) x = y

knz sut va7 nu77 = {0,0,0};
knz sut va7 one77 = {1,1,"one"};

sut scrip7var{sut scrip7var*tbl[32];sut va7 val;};
sut scrip7var *news7v(){
	return calloc(sizeof(sut scrip7var),0);
};


void se7var(char *n,sut va7 val){
	sut scrip7var**q=&(globa7.vars);
	loop{
		if(!*q)*q=news7v();
		if(!*n||*n=='#'){(*q)->val=val;return;}
		q=(*q)->tbl+*n%32;
		n++;
	}
}

sut va7 ge7var(char *n){
	sut scrip7var**q=&(globa7.vars);
	loop{
		if(!*q)*q=news7v();
		if(!*n){return (*q)->val;}
		q=(*q)->tbl+*n%32;
		n++;
	}
}

static char *s7getcmd(FILE *f){
	int n=80,l=0;
	char *s=NULL,*q;
	loop{
		s=realloc(s,n);
		q=fgets(s+l,n-l,f);
		if(!q)return s;
		l+=strlen(s+l);
		if(s[l-1]=='\n')
		if(s[l-2]=='.'){
			s[l-2]=0;
			return s;
		}
		if(l==n-1)n*=2;
	}
}

int undiv(double x,int64_t*np,int64_t*dp){
	double y;int i=0;
	int64_t p=0,q=1,r=1,s=0,n;
	do{i++;if(i>10)break;
	n=(int64_t)((p-x*q)/(x*s-r));
	p+=n*r;q+=n*s;y=(double)p/q;
	if(y==x){*np=p;*dp=q;return i;}
	n=(int64_t)((r-x*s)/(x*q-p));
	r+= n*p;s+=n*q;y=(double)r/s;
	}while(y!=x);
	*np=r;*dp=s;return i;
}

static void memsetl(char *r,char *s,int len,int num){
	memmove(r,s,len);
	int k=1;
	wh(k<num){
		memcpy(r+k*len,r,len*(k*2>num?num-k:k));
		k*=2;
	}
}

static char *s7getinput(int fn,char b){
	int n=80,l=0;
	char *s=malloc(n);
	wh(1){
		read(fn,s+l,1);
		if(s[l]==b)break;
		l++;
		if(l==n-1){
			n*=2;
			s=realloc(s,n);
		}
	}
	s[l]=0;
	return s;
}

#define TY_INT8 0
#define TY_INT16 1
#define TY_INT32 2
#define TY_INT64 3
#define TY_ADDR 4
#define TY_PTR 5
#define TY_FLOAT 6
#define TY_DOUBLE 7
#define TY_VARIANT 8
static char *tpnm[]={"int8","int16","int32","int64",
		"addr","void*","float","double","variant"};
static int tpsz[]={1,2,4,8,1,sizeof(void*),sizeof(float),sizeof(double),8};
static int isint[]={1,1,1,1,0,0,0,0,0};
static int isreal[]={0,0,0,0,0,0,1,1,0};
static int isptr[]={0,0,0,0,1,1,0,0,0};
static int isnum[]={1,1,1,1,0,0,1,1,0};
#define VR_AIOU 0
#define VR_BJPV 1
#define VR_CKQW 2
#define VR_DLRX 3
#define VR_EMSY 4
#define VR_FNTZ 5
#define VR_G 6
#define VR_H 7
#define VR_LIT 8
#define VR_VOID 9
static char *vrnm[]={"aiou","bjpv","ckqw","dlrx","emsy","fntz",
		"g","h","constant","voidvar"};

#define Log(mesg,args...) \
{if(s7logflag)fprintf(stderr,"%ld:"mesg"\n",g-code,##args);}wh(0)

#define Die(mesg,args...) \
{if(s7errflag)fprintf(stderr,"%ld:"mesg"\n",g-code,##args);goto hell;}wh(0)

int isnu77(sut va7 v,int t){
	if(isint[t])return v.c==0;
	if(isptr[t])return v.p==0;
	if(isreal[t])return v.x==0;
	return 0;
}

static void gettype(char*g,int*d,int *dt){
	if(*g>='a'&&*g<='f')*d=*g-'a',*dt=TY_INT8;
	ei(*g>='A'&&*g<='F')*d=*g-'A',*dt=TY_INT16;
	ei(*g>='i'&&*g<='n')*d=*g-'i',*dt=TY_INT32;
	ei(*g>='I'&&*g<='N')*d=*g-'I',*dt=TY_INT64;
	ei(*g>='o'&&*g<='t')*d=*g-'o',*dt=TY_PTR;
	ei(*g>='O'&&*g<='T')*d=*g-'O',*dt=TY_ADDR;
	ei(*g>='u'&&*g<='z')*d=*g-'u',*dt=TY_FLOAT;
	ei(*g>='U'&&*g<='Z')*d=*g-'U',*dt=TY_DOUBLE;
	ei(*g=='G')*d=VR_G,*dt=TY_ADDR;
	ei(*g=='H')*d=VR_H,*dt=TY_ADDR;
	ei(*g=='g')*d=VR_G,*dt=TY_VARIANT;
	ei(*g=='h')*d=VR_H,*dt=TY_VARIANT;
	ei(*g=='_')*d=VR_VOID,*dt=-1;
}

static void setva7(int dt,char **dp, ptrdiff_t dx, const struct va7*v){
	if(dp==0)return;
	if(dt==TY_INT8)(*(int8_t*)(*dp+dx)) = v->c;
	ei(dt==TY_INT16)(*(int16_t*)(*dp+dx)) = v->c;
	ei(dt==TY_INT32)(*(int32_t*)(*dp+dx)) = v->c;
	ei(dt==TY_INT64)(*(int64_t*)(*dp+dx)) = v->c;
	ei(dt==TY_ADDR)(*dp) = v->p-dx;
	ei(dt==TY_PTR)(*(void**)(*dp+dx)) = v->p;
	ei(dt==TY_FLOAT)(*(float*)(*dp+dx)) = v->x;
	ei(dt==TY_DOUBLE)*(double*)(*dp+dx) = v->x;
}

static void getva7(int st,char **sp, ptrdiff_t sx, struct va7 *v){
	if(!sp){
		v->c=0;
		v->p=NULL;
		v->x=0.0;
		return;
	}
	if(st==TY_INT8)   v->c=*(int8_t*)(*sp+sx);
	if(st==TY_INT16)  v->c=*(int16_t*)(*sp+sx);
	if(st==TY_INT32)  v->c=*(int32_t*)(*sp+sx);
	if(st==TY_INT64||st==TY_VARIANT)  v->c=*(int64_t*)(*sp+sx);
	if(st==TY_ADDR)   v->p=(*sp+sx);
	if(st==TY_PTR||st==TY_VARIANT)    v->p=*(void**)(*sp+sx);
	if(st==TY_FLOAT)  v->x=*(float*)(*sp+sx);
	if(st==TY_DOUBLE||st==TY_VARIANT) v->x=*(double*)(*sp+sx);
	if(st<=TY_INT64){ v->p=(*sp+sx);v->x=v->c;}
	ei(st<=TY_PTR){   v->c=(int64_t)v->p;v->x=v->c;}
	ei(st<=TY_DOUBLE){v->c=v->x;v->p=(*sp+sx);}
}

static int64_t memlen(char *d,struct va7 *s,int t){
	int64_t n=0;
	struct va7 v;
	loop{
		char *q=d+tpsz[t]*n;
		getva7(t,&q,0,&v);
		if(t<TY_ADDR&&v.c==s->c)break;
		ei(t<TY_FLOAT&&t>=TY_ADDR&&v.p==s->p)break;
		ei(t<8&&t>=TY_FLOAT&&v.x==s->x)break;
		n++;
	}
	return n;
}

#define usg uintptr_t

static int64_t parsedec(char **gp){
	int64_t i=0;
	wh(**gp>='0'&&**gp<='9'){
		i=i*10+*(*gp)++-'0';
	}
	return i;
}

char bkslshtochr(char c){
	switch(c){
	case'@'...'_':return c-'@';
	case'a':return'\a';
	case'b':return'\b';
	case'd':return'\177';
	case'e':return'\033';
	case'f':return'\f';
	case'n':return'\n';
	case'r':return'\r';
	case't':return'\t';
	case'v':return'\v';
	default:return c;
	}
}

static void parsestr(char **gp,int *stp,struct va7 *sp){
	char *s=malloc(8);
	int z=8,i=0;
	char *g=*gp;
	loop{
		if(i==z)s=realloc(s,z*=2);
		g++;
		if(*g=='"')break;
		if(*g=='\\'){
			g++;
			s[i]=bkslshtochr(*g);
		}else{
			s[i]=*g;
		}
		i++;
	}
	s[i]=0;
	g++;
	*gp=g;
	*stp=TY_PTR;
	sp->p=s;
	sp->x=i;
	sp->c=i;
}

static void parsenum(char **gp,int *stp,struct va7 *sp){
	int64_t i=0,j;
	double x;
	static char *p=0;
	int sgn=1;
	char *g=*gp;
	if(*g>='0'&&*g<='9'){
		i=parsedec(&g);
	}else if(*g=='-'){
		sgn=-1;
		g++;
		i=parsedec(&g);
	}
	x=i;
	*stp=TY_INT64;
	if(*g=='.'){
		*stp=TY_DOUBLE;
		g++;
		j=0;
		while(*g>='0'&&*g<='9'){
			i=i*10+(*g++-'0')*sgn;
			j++;
		}
		i=x=(double)i/pow(10,j);
		if(*g=='^'){
			g++;
			j=parsedec(&g);
			x*=pow(10,j);
		}
	}ei(*g=='/'){
		*stp=TY_DOUBLE;
		g++;
		j=parsedec(&g);
		i=x=(double)i/j;
	}ei(*g=='%'){
		g++;
		j=0;
		int l=0;
		loop{
			int k=(*g+30)%39;
			if(k>=16)break;
			j=j*16+k;
			g++;l++;
		}
		int64_t t=j;
		wh(i>0){
			j=(j<<(l*4))+t;
			i--;
		}
		i=j;
		x=i;
	}ei(*g=='"'){
		p=(char*)realloc(p,i+1);
		p[i]=0;
		for(j=0;j<i;j++){
			p[j]=*++g;
		}
		g++;
		*stp=TY_ADDR;
	}else{
		x=i;
	}
	sp->p=p;
	sp->c=i;
	sp->x=x;
	*gp=g;
}

void scrip7(char *code){
	char **v=globa7.v;
	int i;
	for(i=0;i<8;i++)v[i]=globa7.data;
	char *g=code;
	int d,dt,s,st;
	char op;
	intptr_t dx,sx;
	struct va7 dv,sv;
	wh(*g){
		if(*g!='#'){g++;continue;}
		char *start=++g;
		while(*g&&*g!='#')g++;
		if(!*g)Die("zero char encountered in label");
		g++;
		dv.p=g;
		dv.c=g-start-1;
		dv.c=dv.c;
		se7var(start,dv);
	}
	g=code;
	wh(*g){
		if(*g>0&&*g<=' '){g++;continue;}
		if(*g=='#'){
			g++;
			while(*g!='#')g++;
			g++;
		}
		if(*g=='`'){Log("backtick is early exit");goto hell;}
		un((*g<='Z'&&*g>='A')||(*g<='z'&&*g>='a')||*g=='_')
			Die("bad dest name");
		gettype(g,&d,&dt);
		dx=0;
		sx=0;
		g++;
		wh(*g>0&&*g<=' ')g++;
		if(*g==0)Die("unexpected zero");
		if(*g=='('){
			g++;
			dx=parsedec(&g);
		}ei(*g==')'){
			g++;
			dx=parsedec(&g)*tpsz[dt];
		}
		if(*g==0)Die("unexpected zero");
		op=*g;
		g++;
		if(*g==0)Die("unexpected zero");
		if((*g<='z'&&*g>='a')||(*g<='Z'&&*g>='A')){
			gettype(g,&s,&st);
			g++;
			if(*g=='('){
				g++;
				sx=parsedec(&g);
			}ei(*g==')'){
				g++;
				sx=parsedec(&g)*tpsz[st];
			}
		}ei((*g<='9'&&*g>='0')||*g=='.'||*g=='-'||*g=='%'){
			s=8;
			parsenum(&g,&st,&sv);
		}ei(*g=='\''){
			s=8;
			st=TY_INT8;
			g++;
			sv.x=sv.c=*g;
			g++;
		}ei(*g=='"'){
			s=8;
			parsestr(&g,&st,&sv);
		}else Die("bad arg %c",*g);
		if(dt==-1)dt=st;
		Log("%s %"PRIuPTR" %s %c %s %"PRIuPTR" %s",
			vrnm[d],dx,tpnm[dt],op,vrnm[s],sx,tpnm[st]);
		char **sp=0;
		if(s<8){
			sp=v+s;
			getva7(st,sp,sx,&sv);
		}
		char **dp=(d<8)?&(v[d]):0;
		getva7(dt,dp,dx,&dv);
		if(dt==TY_VARIANT)dt=st;
		if(st==TY_VARIANT)st=dt;
		if(dt==TY_VARIANT)
			Die("Cannot use two variants in a command.");
		int skip=0;
		char *r;
		int dvn=d;
		int fdes;
		int64_t n,d;
		struct va7 nv;
		char pbuf[100];
		switch(op){
		brase '=': //set dest to src
			setva7(dt,dp,dx,&sv);
		brase 'z': //swap dest and src
			setva7(st,sp,sx,&dv);
			setva7(dt,dp,dx,&sv);
		brase 'p': //print src to stream given by dest. _ is stdout
			if(dvn!=VR_VOID&&!isint[dt])
				Die("dest must be a filedes, an integer.");
			if(dvn==VR_VOID)fdes=1;
			else fdes=dv.c;
			if(isint[st])sprintf(pbuf,"%"PRId64"\n",sv.c);
			ei(isptr[st]){write(fdes,sv.p,strlen(sv.p));break;}
			ei(isreal[st])sprintf(pbuf,"%f\n",sv.x);
			write(fdes,pbuf,strlen(pbuf));
		brase 'x': //print src in hex to stream given by dest, where
		//DOCS    _ is used as stdout or 1.
			if(dvn!=VR_VOID&&!isint[dt])
				Die("dest must be a fildes, as an integer.");
			if(dvn==VR_VOID)fdes=1;
			else fdes=dv.c;
			if(dt==TY_INT8)
				sprintf(pbuf,"%02"PRIx8"\n",(uint8_t)sv.c);
			ei(dt==TY_INT16)
				sprintf(pbuf,"%04"PRIx16"\n",(uint16_t)sv.c);
			ei(dt==TY_INT32)
				sprintf(pbuf,"%08"PRIx32"\n",(uint32_t)sv.c);
			ei(dt==TY_INT64)sprintf(pbuf,"%016"PRIx64"\n",sv.c);
			ei(dt<=TY_PTR)sprintf(pbuf,"%p\n",sv.p);
			else sprintf(pbuf,"%e\n",sv.x);
			write(fdes,pbuf,strlen(pbuf));
		brase 'r': //read in a line from stream given by src,
		//DOCS    and put value in dest according to dest's type
			if(!isint[st])
				Die("src must be a fildes, as an integer.");
			r=s7getinput(sv.c,'\n');
			if(dt<=TY_INT64)dv.c=strtol(r,0,0);
			ei(dt==TY_FLOAT||dt==TY_DOUBLE)dv.x=strtod(r,0);
			else dv.p = r;
			if(!isptr[dt])free(r);
			setva7(dt,dp,dx,&dv);
		brase 'S': //copy N objects from src to dest, if src is a ptr.
		//DOCS    (N being the register N of course) otherwise,
		//DOCS    set N objects in dest to the value of src.
			r=*dp;
			getva7(TY_INT64,&v[5],0,&nv);
			if(isptr[st]){
				memmove(r,*sp,nv.c*tpsz[dt]);
			}else{
				memsetl(r,*sp,tpsz[st],nv.c);
			}
		brase 'L': //get number of objects in dest until the value 
		//DOCS    of src is reached. set N to it.
			nv.c = memlen(*dp,&sv,dt);
			setva7(TY_INT64,v+5,0,&nv);
		brase '\\': //undivide src into two consecutive values in dest.
			if(!isnum[dt])
				Die("Undivide dest must be numeric type.");
			undiv(sv.x,&n,&d);
			dv.x=dv.c = n;
			setva7(dt,dp,dx,&dv);
			dv.x=dv.c = d;
			*dp = *dp + tpsz[dt];
			setva7(dt,dp,dx,&dv);
			*dp = *dp - tpsz[dt];
		brase 'R': //read N of dest's type into dest, from fd src.
			if(!isint[st])
				Die("src must be a fildes, as an integer.");
			getva7(TY_INT64,&v[5],0,&nv);
			read(sv.c,*dp,tpsz[dt]*nv.c);
		brase 'W': //write N of dest's type from dest, to fd src..
			if(!isint[st])
				Die("Source must be a fildes, as an integer.");
			getva7(TY_INT64,&v[5],0,&nv);
			write(sv.c,*dp,tpsz[dt]*nv.c);
		brase '.': //put src as char, to fd dest. _ is stdout.
			if(dvn!=VR_VOID&&!isint[dt])
				Die("dest must be a fildes, as an integer.");
			if(dvn==VR_VOID)fdes=1;
			else fdes = dv.c;
			write(fdes,&sv.c,1);
		brase ',': //get char into dest, from stream indicated by src.
			if(!isint[st])
				Die("src must be a fildes, as an integer.");
			{char c;
			read(sv.c,&c,1);
			dv.x=dv.c=c;}
			setva7(dt,dp,dx,&dv);
		brase '+': //add src to dest.
			dv.c+=sv.c;
			dv.x+=sv.x;
			dv.p+=sv.c;
			setva7(dt,dp,dx,&dv);
		brase '-': //subtract src from dest.
			dv.c-=sv.c;
			dv.x-=sv.x;
			dv.p-=sv.c;
			setva7(dt,dp,dx,&dv);
		brase '/': //divide dest by src
			if(sv.c)dv.c/=sv.c;
			dv.x/=sv.x;
			if(isptr[st]||isptr[dt])Die("Can't divide pointers.");
			setva7(dt,dp,dx,&dv);
		brase '%': //modulo dest by src
			dv.c%=sv.c;
			dv.x=fmod(dv.x,sv.x);
			if(isptr[st]||isptr[dt])Die("Can't modulo pointers.");
			setva7(dt,dp,dx,&dv);
		brase '*': //multiply dest by src
			dv.c*=sv.c;
			dv.x*=dv.x;
			if(isptr[st]||isptr[dt])
				Die("Can't multiply pointers.");
			setva7(dt,dp,dx,&dv);
		brase '|': //bitor src into dest
			dv.c|=sv.c;
			if(!isint[st]||!isint[dt])
				Die("Can only bitor integers.");
			setva7(dt,dp,dx,&dv);
		brase '&': //bitand src with dest
			dv.c&=sv.c;
			if(!isint[st]||!isint[dt])
				Die("Can only bitand integers.");
			setva7(dt,dp,dx,&dv);
		brase '^': //raise dest to src power
			dv.c=pow(dv.c,sv.x);
			dv.x=pow(dv.x,sv.x);
			if(isptr[st]||isptr[dt])
				Die("Can only exponent numbers.");
			setva7(dt,dp,dx,&dv);
		brase 'c': //multiply dest by cos src
			dv.c=dv.x=dv.x*cos(sv.x);
			if(isptr[st]||isptr[dt])
				Die("Can only cosine numbers.");
			setva7(dt,dp,dx,&dv);
		brase 's': //multiply dest by sin src
			dv.c=dv.x=dv.x*sin(sv.x);
			if(isptr[st]||isptr[dt])
				Die("Can only sine numbers.");
			setva7(dt,dp,dx,&dv);
		brase '_': //multiply dest by log src
			dv.c=dv.x=dv.x*log(sv.x);
			if(isptr[st]||isptr[dt])
				Die("Can only logarithm numbers.");
			setva7(dt,dp,dx,&dv);
		brase 't': //multiply dest by tan src
			dv.c=dv.x=dv.x*tan(sv.x);
			if(isptr[st]||isptr[dt])
				Die("Can only tangent numbers.");
			setva7(dt,dp,dx,&dv);
		brase 'a': //set dest to atan(dest/src)
			dv.c=dv.x=atan2(dv.x,sv.x);
			if(isptr[st]||isptr[dt])
				Die("Can only arctangent numbers.");
			setva7(dt,dp,dx,&dv);
		brase 'e': //multiply dest by e^src
			dv.c=dv.x=dv.x*exp(sv.x);
			if(isptr[st]||isptr[dt])
				Die("Can only exponent numbers.");
			setva7(dt,dp,dx,&dv);
		brase 'X': //xor dest with src
			dv.c^=sv.c;
			if(!isint[st]||!isint[dt])
				Die("Can only bitxor integers.");
			setva7(dt,dp,dx,&dv);
		brase 'M': //set dest to point to src newly allocated bytes
			if(isptr[st])
				Die("Non number malloc size.");
			*dp=malloc(sv.c*tpsz[dt]);
		brase 'N': //resize allocated memory at dest to src bytes.
			if(isptr[st])
				Die("Non number realloc size.");
			*dp=realloc(*dp,sv.c*tpsz[dt]);
		brase '>': //move dest src objects forward
			if(isptr[st])
				Die("Non number move size.");
			*dp=*dp+(sv.c*tpsz[dt]);
		brase ':': //set dest to src and move dest to next object
			setva7(dt,dp,dx,&sv);
			*dp=*dp+tpsz[dt];
		brase ';': // move to previous object and set dest to src
			*dp=*dp-tpsz[dt];
			setva7(dt,dp,dx,&sv);
		brase '<': //move dest src objects backward
			if(isptr[st])
				Die("Non number move size.");
			*dp=*dp-(sv.c*tpsz[dt]);
		brase 'F': //free memory at dest
			free(*dp);
			*dp=globa7.data;
		brase 'g': //set dest = 0 if dest <= src, else 1
			if(dt<=TY_INT64)skip=(dv.c<=sv.c);
			ei(dt<=TY_PTR)skip=(dv.p<=sv.p);
			else skip=(dv.x<=sv.x);
			if(skip)setva7(dt,dp,dx,&nu77);
			else setva7(dt,dp,dx,&one77);
		brase 'l': //set dest = 0 if dest > src, else 1
			if(dt<=TY_INT64)skip=(dv.c>sv.c);
			ei(dt<=TY_PTR)skip=(dv.p>sv.p);
			else skip=(dv.x>=sv.x);
			if(skip)setva7(dt,dp,dx,&nu77);
			else setva7(dt,dp,dx,&one77);
		brase '~': //set dest = 0 if dest == src, else 1
			if(dt<=TY_INT64)skip=(dv.c==sv.c);
			ei(dt<=TY_PTR)skip=(dv.p==sv.p);
			else skip=(dv.x==sv.x);
			if(skip)setva7(dt,dp,dx,&nu77);
			else setva7(dt,dp,dx,&one77);
		brase 'K': //save current place into dest
			if(dt==TY_PTR||dt==TY_ADDR)dv.p=g;
			else Die("Can only save label to a pointer.");
		brase '@': //get variable of name src into dest
			if(st==TY_ADDR)dv=ge7var(sv.p);
			else Die("Variable name must be string");
			setva7(dt,dp,dx,&sv);
		brase '$': //set variable of name src from dest
			if(st==TY_ADDR)se7var(sv.p,dv);
			else Die("Variable name must be string");
		brase 'j': //goto place saved in src
			if(st==TY_PTR||st==TY_ADDR)g=sv.p;
			else Die("Can only jump to a pointer.");
		brase 'J': //goto place saved in variable named src
			if(st==TY_PTR||st==TY_ADDR)g=ge7var(sv.p).p;
			else Die("Can only jump to a pointer.");
		brase 'i': //goto place saved in src if dest is not zero
			if(isnu77(dv,dt))break;
			if(st==TY_PTR||st==TY_ADDR)g=sv.p;
			else Die("Can only jump to a pointer.");
		brase 'I': //goto place in variable src if dest is not zero
			if(isnu77(dv,dt))break;
			if(st==TY_PTR||st==TY_ADDR)g=ge7var(sv.p).p;
			else Die("Can only jump to a pointer.");
		brase 'C': //call dest as a void(*)(char*) with src as arg.
			un(dt==TY_PTR||dt==TY_ADDR)
				Die("Can only call a pointer.");
			((void(*)(char*))dv.p)(sv.p);
		brault: Die("Bad Operator");
		}
	}
	hell:
	Log("end");
}

int scrip7rc(FILE *in){
	char *cmd=s7getcmd(in);
	if(*cmd==0){free(cmd);return 0;}
	scrip7(cmd);
	if(s7freeflag)free(cmd);
	return 1;
}


void scrip7f(FILE *f){
	wh(!feof(f))scrip7rc(f);
}

void scrip7cli(FILE *in){
	wh(!feof(in)&&scrip7rc(in));
}

#if !defined(NOS7MAIN)
__attribute__((weak)) int main(int argc,char **argv){
	int i=1,cli=1;
	wh(i<argc){
		FILE *f=fopen(argv[i],"r");
		if(!f){
			if(strchr(argv[i],'t'))s7logflag=1;
			if(strchr(argv[i],'c'))cli=1;
			if(strchr(argv[i],'d')){
				i++;
				if(i<argc)scrip7(argv[i]);
			}
			if(strchr(argv[i],'e')){
				cli=0;
				i++;
				if(i<argc)scrip7(argv[i]);
			}
			i++;
			continue;
		}
		cli=0;
		scrip7f(f);
		fclose(f);
		i++;
	}
	if(cli)scrip7cli(stdin);
	return 0;
}
#endif