view scrip7.c @ 5369:ffd6f9ff59f3

<oren> fetch https://raw.githubusercontent.com/orenwatson/scrip7/master/scrip7.c
author HackBot
date Thu, 21 May 2015 22:11:18 +0000
parents
children
line wrap: on
line source

#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 >docs.txt <<END
Author: Oren Watson
Scrip7 hopefully getting stabler release 2015-05-12
You can extract and compile the full distribution simply by running this
file as a shell script like sh scrip7.c This produces the interpreter scrip7,
the library scrip7.o, the documentation docs.txt.
To include, include this file. If your platform does not support weak symbols, 
you will also need to define NOS7MAIN when including it.
Changes in this new version:
Added a variable system to make things easier. the $ set instruction and
@ get instruction are used with string src as varaible name,
and dest as value. e.g. a='a a$3"foo a='f _.a a@3"foo _.a prints fa.

Language Description:
A scrip7 program or script consists of statements, jumps, and loop brackets.
Jump targets are written with #, Loops are written with {} and [] 
The {} brackets will jump  to the matching {} or [] bracket. [] brackets
are inert labels. The quickest way to see how these are supposed to be used, 
is to see the example code.
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" 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. 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 or code literal.
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 '^\( \|	\)*\(c\|br\)ase' scrip7.c | sed -e "s/.*ase '/α/; s/\\\\//; s/': \\/\\//β /; s/src/β/g; s/dest/α/g" >>docs.txt
echo "Running test:"
./scrip7 >out <<END
I=260I%170I+8I*9I/2I-5_pI {checks arithmetic}
I=7%7f I&6%e0 I|3%01 IX7%0f _xI {checks bit operations}
I=5I^5_pII=3I^4_pI {checks exponentiation}
u=43/8_xi {basic check for ieee float}
U=35478/256_xI {basic check for ieee double}
U=355/113_pU {check real number output}
I=1J>1[J+II+JIl1000}#_pI {check basic looping}
I=%5253545556575859{insert newline}b='
 [_.aa>1O!P(1}# {check character output, char literals, and byte order}
X=4.5325_pX_xXJ\X_pJJ>1_pJ 
{check float literals and output some more and undivide}
I=-99_pI {check negative integer literals}
J<2J:23J:17J:27J:67J:44
{Now a test of insertion sort}
[O=RQ=R[IlKQ=O#I>1O!P}#KzLL>1R!P}#
O=SP=SQ=SR=S
_pI_pI)1_pI)2_pI)3_pI)4 {verify sort result and register offsets}
_z0 {modifying void register and constants should do nothing}
END
if diff out - <<END
436
0f6f6f6f6e6e6e6e
3125
81
40ac0000
406152c000000000
3.141593
1597
YXWVUTSR
4.532500
1813/400
1813
400
-99
17
23
27
44
67
END
then
echo "Success"
else
echo "Failure"
fi
rm out
fi
exit 0
true */
//BEGINHEADER
#include "stdio.h"
#include "stdint.h"
extern int s7logflag,s7freeflag,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 let(x,y) typeof(y) x = y
#define new(T,y...) ({T *$$tmp=malloc(sizeof(T)); *$$tmp=(T){y}; $$tmp;})

sut scrip7var{sut scrip7var*tbl[32];sut va7 val;};

void se7var(char *n,sut va7 val){
	sut scrip7var**q=&(globa7.vars);
	loop{
		if(!*q)*q=new(sut scrip7var,{0},{0,0,0});
		if(!*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=new(sut scrip7var,{0},{0,0,0});
		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) {if(s7errflag)fprintf(stderr,"%ld:"mesg"\n",g-code);goto hell;}wh(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, 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 char *fwdjmptbl[256][2];
static uint8_t bakjmptbl[256];
static int pcache(char **s){
	if(**s=='{'){
		uint8_t k = ((usg)*s)%256;
		if(fwdjmptbl[k][0]==*s){
			*s = fwdjmptbl[k][1]+1;
			return 1;
		}else return 0;
	}
	if(**s=='}'){
		uint8_t k = bakjmptbl[((usg)*s)%256];
		if(fwdjmptbl[k][1]==*s){
			*s = fwdjmptbl[k][0]+1;
			return 1;
		}else return 0;
	}
	return 0;
}

static char *skipp(char *s){
	int l=0,nl=0;
	char *ss=s;
	if(*s=='['||*s==']')return s+1;
	un(*s=='{'||*s=='}')return s;
	if(pcache(&s))return s;
	do{
		if(*s=='['||*s=='{')nl=l+1;
		if(*s==']'||*s=='}')nl=l-1;
		if(nl==0){
			usg ssh = (usg)ss%256, sh = (usg)s%256;
			if(l>0){
				fwdjmptbl[ssh][0]=ss;
				fwdjmptbl[ssh][1]=s;
				bakjmptbl[sh]=ssh;
			}ei(l<0){
				fwdjmptbl[sh][0]=s;
				fwdjmptbl[sh][1]=ss;
				bakjmptbl[ssh]=sh;
			}
			return ++s;
		}
		l=nl;
		if(l<0)s--;
		if(l>0)s++;
	}wh(1);
}

static int64_t parsedec(char **gp){
	int64_t i=0;
	wh(**gp>='0'&&**gp<='9'){
		i=i*10+*(*gp)++-'0';
	}
	return 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){
		char*j=skipp(g);
		if(j!=g)Log("skipped parens");
		g=j;
		if(*g=='`'){Log("backtick is early exit");goto hell;}
		if((*g>0&&*g<=' ')||*g=='#'){g++;continue;}
		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;
			st=TY_ADDR;
			sv.p=g+1;
			sv.x=sv.c=0;
			g=skipp(g)+1;
		}else Die("bad arg");
		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 perform operation on two variants.");
		int skip=0;
		char *r;
		int dvn=d;
		int fdes;
		int64_t n,d;
		struct va7 nv;
		char pbuf[100];
		switch(op){
		case '=': //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 stream number, as an integer.");
			if(dvn==VR_VOID)fdes=1;
			else fdes=dv.c;
			if(isint[st])sprintf(pbuf,"%"PRId64"\n",sv.c);
			ei(isptr[st])sprintf(pbuf,"%p\n",sv.p);
			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. _ is stdout
			if(dvn!=VR_VOID&&!isint[dt])Die("dest must be a stream number, 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{
				int64_t n,d;
				undiv(sv.x,&n,&d);
				sprintf(pbuf,"%"PRId64"/%"PRId64"\n",n,d);
			}
			write(fdes,pbuf,strlen(pbuf));
		brase 'r': //read in a line from stream given by src and put value in dest
			if(!isint[st])Die("src must be a stream number, 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 an address. (N being the register N of course) otherwise, 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 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 result must be placed in 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 objects of dest's type into dest, from steem number src.
			if(!isint[st])Die("Source must be a stream number, as an integer.");
			getva7(TY_INT64,&v[5],0,&nv);
			read(sv.c,*dp,tpsz[dt]*nv.c);
		brase 'W': //write N objects of dest's type from dest, to stream number src..
			if(!isint[st])Die("Source must be a stream number, as an integer.");
			getva7(TY_INT64,&v[5],0,&nv);
			write(sv.c,*dp,tpsz[dt]*nv.c);
		brase '.': //put src as char, to stream indicated by dest. _ is stdout.
			if(dvn!=VR_VOID&&!isint[dt])Die("dest must be a stream number, 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 stream number, 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 '~': //skip to # if dest != src
			if(dt<=TY_INT64)skip=(dv.c!=sv.c);
			ei(dt<=TY_PTR)skip=(dv.p!=sv.p);
			else skip=(dv.x!=sv.x);
		brase 'g': //skip to # if dest <= src
			if(dt<=TY_INT64)skip=(dv.c<=sv.c);
			ei(dt<=TY_PTR)skip=(dv.p<=sv.p);
			else skip=(dv.x<=sv.x);
		brase 'l': //skip to # if dest > src
			if(dt<=TY_INT64)skip=(dv.c>sv.c);
			ei(dt<=TY_PTR)skip=(dv.p>sv.p);
			else skip=(dv.x>=sv.x);
		brase '!': //skip to # if dest == src
			if(dt<=TY_INT64)skip=(dv.c==sv.c);
			ei(dt<=TY_PTR)skip=(dv.p==sv.p);
			else skip=(dv.x==sv.x);
		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,&dv);
		brase '$': //set variable of name src from dest
			if(st==TY_ADDR)se7var(sv.p,dv);
			else Die("Variable name must be string");
		brase 'G': //goto place saved in src
			if(st==TY_PTR||st==TY_ADDR)g=sv.p;
			else Die("Can only jump to a pointer.");
		brase 'C': //call dest as a void(*)(char*) with src as parameter.
			un(dt==TY_PTR||dt==TY_ADDR)Die("Can only call a pointer.");
			((void(*)(char*))dv.p)(sv.p);
		brault: Die("Bad Operator");
		}
		if(skip){
			Log("condition false, skipping");
			wh(*g&&*g!='#')g++;
			if(*g)g++;
		}
	}
	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=argc,cli=1;
	wh(i>1){
		i--;
		FILE *f=fopen(argv[i],"r");
		if(!f){
			if(strchr(argv[i],'d'))s7logflag=1;
			if(strchr(argv[i],'f'))s7freeflag=1;
			if(strchr(argv[i],'c'))cli=1;
			continue;
		}
		cli=0;
		scrip7f(f);
		fclose(f);
	}
	if(cli)scrip7cli(stdin);
	return 0;
}
#endif