diff options
| author | Tom Smeding <tom.smeding@gmail.com> | 2016-08-13 18:12:30 +0200 | 
|---|---|---|
| committer | Tom Smeding <tom.smeding@gmail.com> | 2016-08-13 18:12:38 +0200 | 
| commit | ce00424be3963c97ef43d52e87a2da380559536c (patch) | |
| tree | 32724710628f17b21cc64eebc21870fca24a0a39 | |
Initial
| -rw-r--r-- | .gitignore | 4 | ||||
| -rw-r--r-- | Makefile | 17 | ||||
| -rw-r--r-- | bfinter.c | 385 | 
3 files changed, 406 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc06708 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +bfinter +*.o +*.dSYM +*.bf diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fa4031c --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +CC = gcc +CFLAGS = -Wall -Wextra -O2 -std=c11 -fwrapv + +BIN = bfinter + +.PHONY: all clean remake + +all: $(BIN) + +clean: +	rm -f $(BIN) + +remake: clean all + + +$(BIN): $(wildcard *.c *.h) +	$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ diff --git a/bfinter.c b/bfinter.c new file mode 100644 index 0000000..cf4a102 --- /dev/null +++ b/bfinter.c @@ -0,0 +1,385 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> + +typedef unsigned char byte; + +int roundup2power(int n){ +	if(n&(n-1)){ +		n&=n-1; +		while(n&(n-1))n&=n-1; +		n<<=1; +	} +	return n; +} + +typedef struct Tape{ +	byte *buf; +	int sz; +	int maxidx; +} Tape; + +Tape* tape_make(int sz){ +	Tape *tape=malloc(sizeof(Tape)); +	assert(tape); +	tape->buf=calloc(sz,1); +	assert(tape->buf); +	tape->sz=sz; +	tape->maxidx=0; +	return tape; +} + +void tape_set(Tape *tape,int idx,byte val){ +	/*static int max=-1,min=0x7fffffff; +	if(idx>max){ +		max=idx; +		printf("max=%d\n",idx); +	} +	if(idx<min){ +		min=idx; +		printf("min=%d\n",idx); +	}*/ +	if(idx>tape->maxidx)tape->maxidx=idx; +	assert(idx>=0); +	if(idx>=tape->sz){ +		int newsz=roundup2power(idx+1); +		fprintf(stderr,"newsz=%d\n",newsz); +		byte *newbuf=realloc(tape->buf,newsz); +		assert(newbuf); +		memset(newbuf+tape->sz,0,newsz-tape->sz); +		tape->buf=newbuf; +		tape->sz=newsz; +	} +	tape->buf[idx]=(val%256+256)%256; +} + +byte tape_get(const Tape *tape,int idx){ +	if(idx<0||idx>=tape->sz)return 0; +	return tape->buf[idx]; +} + +void tape_print(const Tape *tape){ +	for(int i=0;i<=tape->maxidx;i++){ +		printf("%3d ",tape->buf[i]); +	} +	putchar('\n'); +} + + +typedef struct Jumpmap{ +	int *tg; //targets +} Jumpmap; + +void jm_fill(Jumpmap *jm,const char *source,int len){ +	int *stack,stacksz=16,stackp=0; +	stack=malloc(stacksz*sizeof(int)); +	assert(stack); + +	for(int i=0;i<len;i++){ +		if(source[i]=='['){ +			if(stackp==stacksz-1){ +				stacksz*=2; +				int *newstack=realloc(stack,stacksz*sizeof(int)); +				assert(newstack); +				stack=newstack; +			} +			stack[stackp++]=i; +		} else if(source[i]==']'){ +			assert(stackp>0); +			stackp--; +			jm->tg[i]=stack[stackp]; +			jm->tg[stack[stackp]]=i; +		} +	} +} + +Jumpmap* jm_make(const char *source,int len){ +	Jumpmap *jm=malloc(sizeof(Jumpmap)); +	assert(jm); +	jm->tg=malloc(len*sizeof(int)); +	assert(jm->tg); +	jm_fill(jm,source,len); +	return jm; +} + +void jm_destroy(Jumpmap *jm){ +	free(jm->tg); +	free(jm); +} + +int jm_get(const Jumpmap *jm,int idx){ +	return jm->tg[idx]; +} + + +int readfile(FILE *f,char **bufp){ +	int bufsz=256,cursor=0; +	char *buf=malloc(bufsz); +	assert(buf); +	 +	while(true){ +		int nr=fread(buf+cursor,1,bufsz-cursor-1,f); +		cursor+=nr; +		if(ferror(f)){ +			perror("fread"); +			exit(1); +		} +		if(feof(f))break; +		if(cursor>=bufsz-1){ +			bufsz*=2; +			char *newbuf=realloc(buf,bufsz); +			assert(newbuf); +			buf=newbuf; +		} +	} +	*bufp=buf; +	return cursor; +} + + +void interpret(const char *source,const int sourcelen,const Jumpmap *jm){ +	Tape *tape=tape_make(1024); +	for(int ip=0,mp=0;ip<sourcelen;ip++){ +		switch(source[ip]){ +			case '+': tape_set(tape,mp,tape_get(tape,mp)+1); break; +			case '-': tape_set(tape,mp,tape_get(tape,mp)-1); break; +			case '>': mp++; break; +			case '<': mp--; break; +			case '.': putchar(tape_get(tape,mp)); fflush(stdout); break; +			case ',': tape_set(tape,mp,(byte)getchar()); break; +			case '[': if(!tape_get(tape,mp))ip=jm_get(jm,ip); break; +			case ']': if(tape_get(tape,mp))ip=jm_get(jm,ip); break; +			case '#': tape_print(tape); break; + +			case '0': tape_set(tape,mp,0); break; +			case '^': ip++; tape_set(tape,mp,tape_get(tape,mp)+(byte)source[ip]); break; +			case '@': ip++; mp+=(char)source[ip]; break; +			case 'T':{ +				ip++; +				int nplaces=(byte)source[ip++]; +				int cond=tape_get(tape,mp); +				if(cond==0){ +					ip+=2*nplaces-1; +					break; +				} +				int locs[nplaces],incrs[nplaces]; +				//fprintf(stderr,"TRANS(=%d,%d){",tape_get(tape,mp),nplaces); +				for(int l=0;l<nplaces;l++){ +					locs[l]=(char)source[ip++]; +					incrs[l]=(unsigned char)source[ip++]; +					//fprintf(stderr,"%d+=%d,",locs[l],incrs[l]); +				} +				ip--; +				//fprintf(stderr,"}\n"); +				tape_set(tape,mp,0); +				if(cond)for(int l=0;l<nplaces;l++){ +					tape_set(tape,mp+locs[l],tape_get(tape,mp+locs[l])+incrs[l]*cond); +				} +				break; +			} +		} +	} +} + +void cleanup(char *source,int *sourcelen){ +	int i,j; +	const int len=*sourcelen; +	for(i=0,j=0;i<len;i++){ +		if(strchr("+-><.,[]#",source[i])!=NULL){ +			if(j<i)source[j]=source[i]; +			j++; +		} +	} +	if(j<*sourcelen)source[j]=0; +	*sourcelen=j; +} + +void optimise(char *source,int *sourcelen){ +	int i,j; +	const int len=*sourcelen; +	int plus=0,shift=0; +	for(i=0,j=0;i<len;i++){ +		if(plus&&source[i]!='+'&&source[i]!='-'){ +			//fprintf(stderr,"plus: %d\n",plus); +			if(plus==-1)source[j++]='-'; +			else if(plus==1)source[j++]='+'; +			else { +				source[j++]='^'; +				source[j++]=(plus%256+256)%256; +			} +			plus=0; +		} + +		if(shift&&source[i]!='>'&&source[i]!='<'){ +			//fprintf(stderr,"shift: %d\n",shift); +			if(shift==-1)source[j++]='<'; +			else if(shift==1)source[j++]='>'; +			else { +				//fprintf(stderr,"shift=%d\n",shift); +				while(shift>127){ +					source[j++]='@'; +					source[j++]=127; +					shift-=127; +				} +				if(shift==1){ +					source[j++]='>'; +					shift=0; +				} +				if(shift>0){ +					source[j++]='@'; +					source[j++]=shift; +					shift=0; +				} +				while(shift<-128){ +					source[j++]='@'; +					source[j++]=-128; +					shift+=128; +				} +				if(shift==-1){ +					source[j++]='<'; +					shift=0; +				} +				if(shift<0){ +					source[j++]='@'; +					source[j++]=shift; +					shift=0; +				} +			} +			shift=0; +		} + +		if(source[i]=='+'||source[i]=='-'){ +			plus+=2*(source[i]=='+')-1; +			continue; +		} + +		if(source[i]=='>'||source[i]=='<'){ +			shift+=2*(source[i]=='>')-1; +			continue; +		} + +		if(i<=len-3&&memcmp(source+i,"[-]",3)==0){ +			//fprintf(stderr,"zero\n"); +			source[j++]='0'; +			i+=2; +			continue; +		} +		if(source[i]=='['){ +			int k; +			for(k=i+1;k<len;k++){ +				if(source[k]==']')break; +				if(strchr("><+-",source[k])==NULL){ +					k=-1; +					break; +				} +			} +			if(k==-1){ +				if(j<i)source[j]=source[i]; +				j++; +				continue; +			} +			int endidx=k; + +			//fprintf(stderr,"transferloop: index=%d\n",i); +			int nplaces=0; +			for(k=i+1;source[k]!=']';k++){ +				nplaces+=source[k]=='+'||source[k]=='-'; +			} +			int locs[nplaces],incrs[nplaces]; +			nplaces=0; +			int position=0,l; +			for(k=i+1;source[k]!=']';k++){ +				if(source[k]=='>'||source[k]=='<'){ +					position+=2*(source[k]=='>')-1; +					if(position>127||position<-128){ +						k=-1; +						break; +					} +				} else { +					for(l=0;l<nplaces;l++)if(locs[l]==position)break; +					if(l==nplaces){ +						nplaces++; +						locs[l]=position; +						incrs[l]=0; +					} +					incrs[l]=((incrs[l]+2*(source[k]=='+')-1)%256+256)%256; +				} +			} +			//fprintf(stderr,"TL: original: "); +			//fwrite(source+i,1,endidx-i+1,stderr); +			//fputc('\n',stderr); +			//fprintf(stderr,"TL: "); for(l=0;l<nplaces;l++)fprintf(stderr,"%d+=%d ",locs[l],incrs[l]); fputc('\n',stderr); +			if(k==-1||nplaces<=1||nplaces>256||position!=0){ +				//fprintf(stderr,"TL: nplaces=%d invalid, or position=%d invalid or not zero\n",nplaces,position); +				if(j<i)source[j]=source[i]; +				j++; +				continue; +			} + +			for(l=0;l<nplaces;l++){ +				if(locs[l]==0)break; +			} +			if(l==nplaces||incrs[l]!=255){ +				//fprintf(stderr,"TL: increment on condition cell not -1\n"); +				if(j<i)source[j]=source[i]; +				j++; +				continue; +			} + +			source[j++]='T'; +			source[j++]=(unsigned char)(nplaces-1); +			for(l=0;l<nplaces;l++){ +				if(locs[l]==0)continue; +				source[j++]=(char)locs[l]; +				source[j++]=(unsigned char)incrs[l]; +			} +			i=endidx; +			continue; +		} + +		//fprintf(stderr,"copy '%c'\n",source[i]); +		if(j<i)source[j]=source[i]; +		j++; +	} +	*sourcelen=j; +} + + +int main(int argc,char **argv){ +	char *source; +	int sourcelen; + +	if(argc==1||strcmp(argv[1],"-")==0){ +		sourcelen=readfile(stdin,&source); +	} else { +		FILE *f=fopen(argv[1],"rb"); +		if(!f){ +			perror("fopen"); +			return 1; +		} +		sourcelen=readfile(f,&source); +		fclose(f); +	} + +	//cleanup() necessary to remove the special optimiser +	//chars that might be present in the original source +	cleanup(source,&sourcelen); +	optimise(source,&sourcelen); //may be omitted if desired + +#if 0 +	fwrite(source,1,sourcelen,stdout); +	fflush(stdout); +	return 0; +#endif + +	Jumpmap *jm=jm_make(source,sourcelen); + +	interpret(source,sourcelen,jm); +	 +	jm_destroy(jm); +	free(source); +}  | 
