diff --git a/Makefile b/Makefile index 2cc498fd..9c985e58 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,14 @@ LFLAGS = all: dos33 asoft_detoken mkdos33fs make_b tokenize_asoft \ dos33_text2ascii integer_detoken char2hex pcx2hgr \ - asoft_presenter shape_table + asoft_presenter shape_table asoft_compact +asoft_compact: asoft_compact.o + $(CC) $(LFLAGS) -o asoft_compact asoft_compact.o + +asoft_compact.o: asoft_compact.c + $(CC) $(CFLAGS) -c asoft_compact.c asoft_detoken: asoft_detoken.o $(CC) $(LFLAGS) -o asoft_detoken asoft_detoken.o @@ -82,7 +87,8 @@ install: clean: rm -f *~ *.o asoft_detoken dos33 make_b mkdos33fs \ tokenize_asoft dos33_text2ascii integer_detoken \ - char2hex pcx2hgr asoft_presenter shape_table + char2hex pcx2hgr asoft_presenter shape_table \ + asoft_compact cd tests && make clean cd presenter_demo && make clean diff --git a/asoft_compact.c b/asoft_compact.c new file mode 100644 index 00000000..2d29a62d --- /dev/null +++ b/asoft_compact.c @@ -0,0 +1,406 @@ +/* asoft_compact */ +/* make applesoft code as compact as possible */ +/* + Renumber lines to be as short as possible */ +/* + Remove extraneous "LET" commands */ +/* + Transform "THEN GOTO" to "THEN" */ +/* + Make variables as short as possible */ +/* + Remove REM statements */ +/* + Combine lines right up to 255 char limit */ + +/* Example */ +/* demo.bas = 22,219 bytes */ +/* tokenized = 17,407 bytes */ +/* compacted = */ + +#include +#include /* strlen() */ +#include + +#include "version.h" + +#define LOW(_x) ((_x)&0xff) +#define HIGH(_x) (((_x)>>8)&0xff) + + + /* Starting at 0x80 */ +char applesoft_tokens[][8]={ +/* 80 */ "END","FOR","NEXT","DATA","INPUT","DEL","DIM","READ", +/* 88 */ "GR","TEXT","PR #","IN #","CALL","PLOT","HLIN","VLIN", +/* 90 */ "HGR2","HGR","HCOLOR=","HPLOT","DRAW","XDRAW","HTAB","HOME", +/* 98 */ "ROT=","SCALE=","SHLOAD","TRACE","NOTRACE","NORMAL","INVERSE","FLASH", +/* A0 */ "COLOR=","POP","VTAB ","HIMEM:","LOMEM:","ONERR","RESUME","RECALL", +/* A8 */ "STORE","SPEED=","LET","GOTO","RUN","IF","RESTORE","&", +/* B0 */ "GOSUB","RETURN","REM","STOP","ON","WAIT","LOAD","SAVE", +/* B8 */ "DEF FN","POKE","PRINT","CONT","LIST","CLEAR","GET","NEW", +/* C0 */ "TAB","TO","FN","SPC(","THEN","AT","NOT","STEP", +/* C8 */ "+","-","*","/","^","AND","OR",">", +/* D0 */ "=","<","SGN","INT","ABS","USR","FRE","SCRN (", +/* D8 */ "PDL","POS","SQR","RND","LOG","EXP","COS","SIN", +/* E0 */ "TAN","ATN","PEEK","LEN","STR$","VAL","ASC","CHR$", +/* E8 */ "LEFT$","RIGHT$","MID$","","","","","", +/* F0 */ "","","","","","","","", +/* F8 */ "","","","","","(","(","(" +}; + +#define TOKEN_END 0 +#define TOKEN_FOR 1 +#define TOKEN_NEXT 2 +#define TOKEN_DATA 3 +#define TOKEN_INPUT 4 +#define TOKEN_DEL 5 +#define TOKEN_DIM 6 +#define TOKEN_READ 7 +#define TOKEN_GR 8 +#define TOKEN_TEXT 9 +#define TOKEN_PR 10 +#define TOKEN_IN 11 +#define TOKEN_CALL 12 +#define TOKEN_PLOT 13 +#define TOKEN_HLIN 14 +#define TOKEN_VLIN 15 +#define TOKEN_HGR2 16 +#define TOKEN_HGR 17 +#define TOKEN_HCOLOR 18 +#define TOKEN_HPLOT 19 +#define TOKEN_DRAW 20 +#define TOKEN_XDRAW 21 +#define TOKEN_HTAB 22 +#define TOKEN_HOME 23 +#define TOKEN_ROT 24 +#define TOKEN_SCALE 25 +#define TOKEN_SHLOAD 26 +#define TOKEN_TRACE 27 +#define TOKEN_NOTRACE 28 +#define TOKEN_NORMAL 29 +#define TOKEN_INVERSE 30 +#define TOKEN_FLASH 31 +#define TOKEN_COLOR 32 +#define TOKEN_POP 33 +#define TOKEN_VTAB 34 +#define TOKEN_HIMEM 35 +#define TOKEN_LOMEM 36 +#define TOKEN_ONERR 37 +#define TOKEN_RESUME 38 +#define TOKEN_RECALL 39 +#define TOKEN_STORE 40 +#define TOKEN_SPEED 41 +#define TOKEN_LET 42 +#define TOKEN_GOTO 43 +#define TOKEN_RUN 44 +#define TOKEN_IF 45 +#define TOKEN_RESTORE 46 +#define TOKEN_AMP 47 +#define TOKEN_GOSUB 48 +#define TOKEN_RETURN 49 +#define TOKEN_REM 50 +#define TOKEN_STOP 51 +#define TOKEN_ON 52 +#define TOKEN_WAIT 53 +#define TOKEN_LOAD 54 +#define TOKEN_SAVE 55 +#define TOKEN_DEFFN 56 +#define TOKEN_POKE 57 +#define TOKEN_PRINT 58 +#define TOKEN_CONT 59 +#define TOKEN_LIST 60 +#define TOKEN_CLEAR 61 +#define TOKEN_GET 62 +#define TOKEN_NEW 63 +#define TOKEN_TAB 64 +#define TOKEN_TO 65 +#define TOKEN_FN 66 +#define TOKEN_SPC 67 +#define TOKEN_THEN 68 +#define TOKEN_AT 69 +#define TOKEN_NO 70 +#define TOKEN_STEP 71 +#if 0 +/* C8 */ "+","-","*","/","^","AND","OR",">", +/* D0 */ "=","<","SGN","INT","ABS","USR","FRE","SCRN (", +/* D8 */ "PDL","POS","SQR","RND","LOG","EXP","COS","SIN", +/* E0 */ "TAN","ATN","PEEK","LEN","STR$","VAL","ASC","CHR$", +/* E8 */ "LEFT$","RIGHT$","MID$","","","","","", +#endif + +static void color_red(void) { + fprintf(stderr,"%c[1;31;40m",27); +} + +static void color_green(void) { + fprintf(stderr,"%c[1;32;40m",27); +} + +static void color_cyan(void) { + fprintf(stderr,"%c[1;36;40m",27); +} + +static void color_yellow(void) { + fprintf(stderr,"%c[1;33;40m",27); +} + +static void color_normal(void) { + fprintf(stderr,"%c[0m",27); +} + +static int linenums[65536]; /* lazy */ +static int output[65536]; + + +static void print_int(int value, int *offset) { + + unsigned char buffer[16]; + int pointer=15; + int r,q; + + q=value; + + while(1) { + r=q%10; + q/=10; + + buffer[pointer]=r+'0'; + + if (q==0) break; + + pointer--; + } + + while(pointer<16) { + output[*offset]=buffer[pointer]; + pointer++; + (*offset)++; + } +} + +int main(int argc, char **argv) { + + int ch1; + int size1,size2; + int line1,line2; + int link1,link2,link; + int debug=1; + int token,last_token=0; + int line_no=0; + int i; + FILE *fff; + + int offset,link_offset,line_offset; + + if (argc<2) { + fprintf(stderr,"Usage: %s FILENAME -1 -2 -3 -4\n",argv[0]); + exit(1); + } + + fff=fopen(argv[1],"r"); + if (fff==NULL) { + fprintf(stderr,"Error opening %s\n",argv[1]); + exit(1); + } + + + /* read size, first two bytes */ + size1=fgetc(fff); + size2=fgetc(fff); + + if (debug) fprintf(stderr,"File size: %x %x\n",size1,size2); + + while(!feof(fff)) { + + /* link points to the next line */ + link1=fgetc(fff); + link2=fgetc(fff); + link=(link1<<8)|link2; + /* link==0 indicates EOF */ + if (link==0) goto the_end; + + /* line number is little endian 16-bit value */ + line1=fgetc(fff); + line2=fgetc(fff); + if (feof(fff)) goto the_end; + + color_red(); + fprintf(stderr,"%4d ",((line2)<<8)+line1); + color_normal(); + + /* repeat until EOL character (0) */ + while(1) { + + ch1=fgetc(fff); +after_read: + if (ch1==0) break; + + /* if > 0x80 it's a token */ + if (ch1>=0x80) { + color_green(); + fprintf(stderr,"%s",applesoft_tokens[ch1-0x80]); + color_normal(); + last_token=ch1&0x7f; + } + + + /* otherwise it is an ascii char */ + else { + if (ch1<0x20) { + color_cyan(); + fprintf(stderr,"%d",ch1); + color_normal(); + } + + if ((ch1>='0') && (ch1<='9')) { + if ((last_token==TOKEN_GOTO) || + (last_token==TOKEN_GOSUB) || + (last_token==TOKEN_THEN)) { + + line_no=ch1-'0'; + + while(1) { + ch1=fgetc(fff); + if ((ch1<'0') || (ch1>'9')) break; + line_no*=10; + line_no+=(ch1-'0'); + } + + color_yellow(); + fprintf(stderr,"%d",line_no); + color_normal(); + linenums[line_no]++; + goto after_read; + } + } + + + fputc(ch1,stderr); + } + + } + fprintf(stderr,"\n"); + } + the_end:; + + fprintf(stderr,"Used Line Numbers:\n"); + for(i=0;i<65536;i++) { + if(linenums[i]) fprintf(stderr,"\t%d\t%d\n",i,linenums[i]); + } + + rewind(fff); + + /*********************/ + /* Create new output */ + /*********************/ + + /* skip size bytes */ + offset=2; + size1=fgetc(fff); + size2=fgetc(fff); + + + while(!feof(fff)) { + + link_offset=offset; + + link1=fgetc(fff); + link2=fgetc(fff); + link=(link1<<8)|link2; + + output[offset]=link1; + output[offset+1]=link2; + + /* link==0 indicates end */ + if (link==0) break; + offset+=2; + + + /* line number is little endian 16-bit value */ + + line_offset=offset; + + line1=fgetc(fff); + line2=fgetc(fff); + + output[offset]=line1; + output[offset+1]=line2; + + offset+=2; + + if (feof(fff)) break; + + /* repeat until EOL character (0) */ + while(1) { + + ch1=fgetc(fff); +after_read2: + if (ch1==0) break; + + /* if > 0x80 it's a token */ + if (ch1>=0x80) { + + token=ch1&0x7f; + + if (token==TOKEN_LET) { + /* Skip superfluous LET */ + } + else if ((token==TOKEN_GOTO) && (last_token==TOKEN_THEN)) { + /* Skip superfluous GOTO if THEN GOTO */ + + } + else { + output[offset]=ch1; + offset++; + } + last_token=token; + } + + + /* otherwise it is an ascii char */ + else { + + if ((ch1>='0') && (ch1<='9')) { + if ((last_token==TOKEN_GOTO) || + (last_token==TOKEN_GOSUB) || + (last_token==TOKEN_THEN)) { + + line_no=ch1-'0'; + + while(1) { + ch1=fgetc(fff); + if ((ch1<'0') || (ch1>'9')) break; + line_no*=10; + line_no+=(ch1-'0'); + } + + print_int(line_no,&offset); + + goto after_read2; + } + } + + + output[offset]=ch1; + offset++; + } + + } + output[offset]=0; + offset++; + + output[link_offset]=LOW(offset+0x7ff); + output[link_offset+1]=HIGH(offset+0x7ff); + + } + + /* write out our program */ + + /* set last link field to $00 $00 which indicates EOF */ + output[offset]='\0'; + output[offset+1]='\0'; + offset+=2; + + /* Set filesize */ + /* -1 to match observed values */ + output[0]=LOW(offset-1); + output[1]=HIGH(offset-1); + /* output our file */ + for(i=0;i