2012-05-18 21:27:33 +00:00
|
|
|
/* asoft_compact */
|
2016-03-11 19:54:20 +00:00
|
|
|
/* 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 */
|
2012-05-18 21:27:33 +00:00
|
|
|
|
|
|
|
/* Example */
|
|
|
|
/* demo.bas = 22,219 bytes */
|
|
|
|
/* tokenized = 17,407 bytes */
|
2016-03-11 19:54:20 +00:00
|
|
|
/* compacted = */
|
2012-05-18 21:27:33 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
2016-03-11 19:54:20 +00:00
|
|
|
#include <string.h> /* strlen() */
|
2012-05-18 21:27:33 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "version.h"
|
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
#define LOW(_x) ((_x)&0xff)
|
2012-05-18 21:27:33 +00:00
|
|
|
#define HIGH(_x) (((_x)>>8)&0xff)
|
|
|
|
|
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/* Starting at 0x80 */
|
|
|
|
char applesoft_tokens[][8]={
|
2012-05-18 21:27:33 +00:00
|
|
|
/* 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 */ "","","","","","(","(","("
|
|
|
|
};
|
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
#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
|
2012-05-18 21:27:33 +00:00
|
|
|
#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) {
|
2016-03-11 19:54:20 +00:00
|
|
|
fprintf(stderr,"%c[1;31;40m",27);
|
2012-05-18 21:27:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void color_green(void) {
|
2016-03-11 19:54:20 +00:00
|
|
|
fprintf(stderr,"%c[1;32;40m",27);
|
2012-05-18 21:27:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void color_cyan(void) {
|
2016-03-11 19:54:20 +00:00
|
|
|
fprintf(stderr,"%c[1;36;40m",27);
|
2012-05-18 21:27:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void color_yellow(void) {
|
2016-03-11 19:54:20 +00:00
|
|
|
fprintf(stderr,"%c[1;33;40m",27);
|
2012-05-18 21:27:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void color_normal(void) {
|
2016-03-11 19:54:20 +00:00
|
|
|
fprintf(stderr,"%c[0m",27);
|
2012-05-18 21:27:33 +00:00
|
|
|
}
|
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
static int linenums[65536]; /* lazy */
|
2012-05-18 21:27:33 +00:00
|
|
|
static int output[65536];
|
|
|
|
|
|
|
|
|
|
|
|
static void print_int(int value, int *offset) {
|
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
unsigned char buffer[16];
|
|
|
|
int pointer=15;
|
|
|
|
int r,q;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
q=value;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
while(1) {
|
|
|
|
r=q%10;
|
|
|
|
q/=10;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
buffer[pointer]=r+'0';
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
if (q==0) break;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
pointer--;
|
|
|
|
}
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
while(pointer<16) {
|
|
|
|
output[*offset]=buffer[pointer];
|
|
|
|
pointer++;
|
|
|
|
(*offset)++;
|
|
|
|
}
|
2012-05-18 21:27:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
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);
|
2012-05-18 21:27:33 +00:00
|
|
|
color_normal();
|
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/* repeat until EOL character (0) */
|
|
|
|
while(1) {
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
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:;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
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]);
|
|
|
|
}
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
rewind(fff);
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/*********************/
|
|
|
|
/* Create new output */
|
|
|
|
/*********************/
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/* skip size bytes */
|
|
|
|
offset=2;
|
|
|
|
size1=fgetc(fff);
|
|
|
|
size2=fgetc(fff);
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
while(!feof(fff)) {
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
link_offset=offset;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
link1=fgetc(fff);
|
|
|
|
link2=fgetc(fff);
|
|
|
|
link=(link1<<8)|link2;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
output[offset]=link1;
|
|
|
|
output[offset+1]=link2;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/* link==0 indicates end */
|
|
|
|
if (link==0) break;
|
|
|
|
offset+=2;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/* line number is little endian 16-bit value */
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
// line_offset=offset;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
line1=fgetc(fff);
|
|
|
|
line2=fgetc(fff);
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
output[offset]=line1;
|
|
|
|
output[offset+1]=line2;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
offset+=2;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
if (feof(fff)) break;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/* repeat until EOL character (0) */
|
|
|
|
while(1) {
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
ch1=fgetc(fff);
|
2012-05-18 21:27:33 +00:00
|
|
|
after_read2:
|
2016-03-11 19:54:20 +00:00
|
|
|
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++;
|
|
|
|
}
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
}
|
|
|
|
output[offset]=0;
|
|
|
|
offset++;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
output[link_offset]=LOW(offset+0x7ff);
|
|
|
|
output[link_offset+1]=HIGH(offset+0x7ff);
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
}
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/* write out our program */
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/* set last link field to $00 $00 which indicates EOF */
|
|
|
|
output[offset]='\0';
|
|
|
|
output[offset+1]='\0';
|
|
|
|
offset+=2;
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
/* Set filesize */
|
|
|
|
/* -1 to match observed values */
|
|
|
|
output[0]=LOW(offset-1);
|
|
|
|
output[1]=HIGH(offset-1);
|
|
|
|
/* output our file */
|
|
|
|
for(i=0;i<offset;i++) putchar(output[i]);
|
2012-05-18 21:27:33 +00:00
|
|
|
|
2016-03-11 19:54:20 +00:00
|
|
|
return 0;
|
2012-05-18 21:27:33 +00:00
|
|
|
}
|