Last active
May 5, 2022 04:52
-
-
Save sinsinpub/f5b472598c8eb54312613e528778d174 to your computer and use it in GitHub Desktop.
Print MSX-BASIC tokenized binary file to stdout in plain texts. Fixed messy indents, typos and bugs in original version. Tested with Turbo C++1/DJGPP GCC 7.3 and some BAS files of opensource Japanese homebrew games.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************\ | |
list v0.3 | |
This programm will convert a MSX-BASIC tokenized file into an ascii file. | |
syntax: list [inputfile] | |
To save converted texts, just pipe output with '> outputfile'. | |
Vincent van Dam | |
(vandam@ronix.ptf.hro.nl) | |
//Please notify me in case of modifications. | |
Original modified: 26/6/97 | |
Last modified by sin_sin on 2022-5-5 | |
\****************************************************************************/ | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
/* Uncomment this to escape double-byte GRAPH chars in \xXX form */ | |
/* #define ESCGRAPH 1 */ | |
/* MSX-BASIC tokens */ | |
const char *tokens_1[128] = { | |
"","END","FOR","NEXT","DATA","INPUT","DIM","READ","LET","GOTO","RUN","IF", | |
"RESTORE","GOSUB","RETURN","REM", /* 80-8F */ | |
"STOP","PRINT","CLEAR","LIST","NEW","ON","WAIT","DEF","POKE","CONT", | |
"CSAVE","CLOAD","OUT","LPRINT","LLIST","CLS", /* 90-9F */ | |
"WIDTH","ELSE","TRON","TROFF","SWAP","ERASE","ERROR","RESUME","DELETE", | |
"AUTO","RENUM","DEFSTR","DEFINT","DEFSNG","DEFDBL","LINE", /* A0-AF */ | |
"OPEN","FIELD","GET","PUT","CLOSE","LOAD","MERGE","FILES","LSET","RSET", | |
"SAVE","LFILES","CIRCLE","COLOR","DRAW","PAINT", /* B0-BF */ | |
"BEEP","PLAY","PSET","PRESET","SOUND","SCREEN","VPOKE","SPRITE","VDP", | |
"BASE","CALL","TIME","KEY","MAX","MOTOR","BLOAD", /* C0-CF */ | |
"BSAVE","DSKO$","SET","NAME","KILL","IPL","COPY","CMD","LOCATE","TO", | |
"THEN","TAB(","STEP","USR","FN","SPC(", /* D0-DF */ | |
"NOT","ERL","ERR","STRING$","USING","INSTR","'","VARPTR","CSRLIN","ATTR$", | |
"DSKI$","OFF","INKEY$","POINT",">","=", /* E0-EF */ | |
"<","+","-","*","/","^","AND","OR","XOR","EQV","IMP","MOD","\\","","", | |
"'doublebyte-token'" /* F0-FF */ | |
}; | |
/* double bytes tokens */ | |
const char *tokens_2[128] = { | |
"","LEFT$","RIGHT$","MID$","SGN","INT","ABS","SQR","RND","SIN","LOG", | |
"EXP","COS","TAN","ATN","FRE", /* 80-8F */ | |
"INP","POS","LEN","STR$","VAL","ASC","CHR$","PEEK","VPEEK","SPACE$", | |
"OCT$","HEX$","LPOS","BIN$","CINT","CSNG", /* 90-9F */ | |
"CDBL","FIX","STICK","STRIG","PDL","PAD","DSKF","FPOS","CVI","CVS","CVD", | |
"EOF","LOC","LOF","MKI$","MKS$", /* A0-AF */ | |
"MKD$","","","","","","","","","","","","","","","", /* B0-BF */ | |
"","","","","","","","","","","","","","","","", /* C0-CF */ | |
"","","","","","","","","","","","","","","","", /* D0-DF */ | |
"","","","","","","","","","","","","","","","", /* E0-EF */ | |
"","","","","","","","","","","","","","","","" /* F0-FF */ | |
}; | |
/* read a 2-byte word */ | |
unsigned int readword(FILE *fd) { | |
return getc(fd)+256*getc(fd); | |
} | |
/* print quote/remark/data char */ | |
int printchar(FILE *fd) { | |
unsigned char ch=getc(fd); | |
if (ch==0) return -1; | |
if (ch!=1) printf("%c",ch); | |
/* printable GRAPH char on MSX only */ | |
if (ch==1) | |
#ifdef ESCGRAPH | |
printf("\\x%X",getc(fd)); | |
#else | |
printf("%c",ch); | |
#endif | |
return 0; | |
} | |
/* get exponent of floating point number */ | |
int getexp(FILE *fd) { | |
int exp; | |
exp=getc(fd); | |
if (exp>127) { exp=exp-128; printf("-"); } | |
return exp-64; | |
} | |
/* print single/double precission float point */ | |
void printfloat(FILE *fd, int digits, char suffix) { | |
unsigned char lo,hi,str[21]; | |
int exp,i,j,flag,isint; | |
exp=getexp(fd); | |
lo=0; | |
memset(str,'0',20); | |
str[20]=0; | |
isint=0; | |
/* get digits */ | |
for (i=j=0; i<digits*2; i++) { | |
if (i%2==0) { | |
hi=getc(fd); | |
lo=hi&0x0f; hi=hi>>4; | |
str[j++]='0'+hi; | |
} else | |
str[j++]='0'+lo; | |
} | |
str[j]=0; | |
/* insert dot */ | |
if (exp<=-64) { | |
str[0]='0'; | |
str[1]='.'; | |
exp=0; | |
} else if (exp>digits*2 || exp<-1) { | |
for (i=(digits*2+2);i>1;i--) str[i]=str[i-1]; | |
str[1]='.'; | |
exp--; | |
} else if (exp<0) { | |
for (i=(digits*2+3);i>1;i--) str[i]=str[i-2]; | |
str[0]='.'; | |
str[1]='0'; | |
} else { | |
for (i=(digits*2+2);i>exp;i--) str[i]=str[i-1]; | |
str[exp]='.'; | |
} | |
/* delete extra zero's */ | |
for (i=flag=0; i<digits*2+2; i++) | |
if (str[i]=='0') { | |
if (flag==0) flag=i; | |
} else { | |
if (str[i]==0) break; else flag=0; | |
} | |
if (flag!=0) { | |
if (str[flag-1]=='.') { | |
str[flag-1]=0; | |
isint=1; | |
} else str[flag]=0; | |
} | |
printf("%s",str); | |
/* scientific notation */ | |
if (exp>digits*2 || exp<-1) { | |
printf("E%+02d",exp); | |
/* print literal suffix if not E-notation */ | |
} else if (isint || digits>3) { | |
printf("%c",suffix); | |
} | |
} | |
int main(int argc, char *argv[]) { | |
FILE *fd; | |
unsigned char ch; | |
unsigned char *token; | |
unsigned int linenumber; | |
unsigned int lineaddress; | |
int goon; | |
int quoted; | |
int datastr; | |
/* check argument */ | |
if (argc!=2) { | |
puts("Usage: LIST filename.BAS"); | |
return 1; | |
} | |
/* open file */ | |
if ((fd=fopen(argv[1],"rb"))==NULL) { | |
fprintf(stderr,"Cannot open file - %s\n",argv[1]); | |
exit(1); | |
} | |
/* read header and check if it is a BASIC program */ | |
ch=getc(fd); | |
if (ch!=0xff) { | |
fprintf(stderr,"File not a MSX-BASIC program - %s\n",argv[1]); | |
exit(1); | |
} | |
/* read line number and address */ | |
/* address tells where the next line begins, high 7th bit indicates 'loaded', always 1 */ | |
lineaddress=readword(fd); | |
while (lineaddress!=0) { | |
linenumber=readword(fd); | |
/* MSX-BASIC line number 0~65529 */ | |
printf("%u ",linenumber); | |
/* read a line of BASIC program */ | |
goon=1; | |
quoted=0; | |
datastr=0; | |
while(goon) { | |
ch=getc(fd); | |
if (ch==0) goon=0; | |
else if (ch==0x22) { /* double quotes " */ | |
printf("%c",ch); | |
quoted=1-quoted; | |
} else if (quoted==1) { /* keep output quoted chars */ | |
ungetc(ch,fd); | |
printchar(fd); | |
} else if (datastr==1) { /* keep output data until : */ | |
if (ch==0x3a) datastr=0; | |
ungetc(ch,fd); | |
printchar(fd); | |
} else if (ch>=0x80 && ch<0xff) { /* single byte token */ | |
token=(unsigned char *)tokens_1[ch-0x80]; | |
if (*token==0) | |
printf("'0x%x?'",ch); | |
else | |
printf("%s",token); | |
if (ch==0x84) datastr=1; /* DATA found */ | |
if (ch==0x8f) { /* REM found, output remaining */ | |
while (!printchar(fd)); | |
goon=0; | |
} | |
} else if (ch==0xff) { /* double bytes token */ | |
ch=getc(fd); | |
token=(unsigned char *)tokens_2[ch-0x80]; | |
if (*token==0) | |
printf("'0xff%x?'",ch); | |
else | |
printf("%s",token); | |
} else if (ch==0x3a) { /* colon : */ | |
ch=getc(fd); | |
if (ch==0xa1) | |
printf("ELSE"); | |
else if (ch==0x8f) { /* REM variant */ | |
ch=getc(fd); | |
if (ch==0xe6) { /* single quote mark */ | |
printf("'"); | |
while (!printchar(fd)); /* output remaining chars */ | |
goon=0; | |
} else if (ch==0) { /* unknown case */ | |
printf(":REM"); | |
while (!printchar(fd)); | |
goon=0; | |
} else { | |
printf("':0x%x?'",ch); | |
} | |
} else { | |
printf(":"); | |
ungetc(ch,fd); | |
} | |
} else if (ch==0x0b) /* octal number */ | |
printf("&O%o",readword(fd)); | |
else if (ch==0x0c) /* hexadecimal number */ | |
printf("&H%X",readword(fd)); | |
else if (ch==0x0d) /* line number: address */ | |
printf("'unsupport line ref'"); | |
else if (ch==0x0e) /* line number */ | |
printf("%u",readword(fd)); | |
else if (ch==0x0f) /* integer: byte */ | |
printf("%u",getc(fd)); | |
else if (ch==0x1c) /* integer: word */ | |
printf("%u",readword(fd)); | |
else if (ch==0x1d) { /* single precission float */ | |
printfloat(fd,3,'!'); | |
} else if (ch==0x1f) { /* double precission float */ | |
printfloat(fd,7,'#'); | |
} else if (ch>=0x11 && ch<=0x1a) | |
printf("%u",ch-0x11); | |
else /* literal ascii char, including &B number */ | |
printf("%c",ch); | |
} | |
printf("\n"); | |
lineaddress=readword(fd); | |
} | |
fclose(fd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment