/* 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; 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