Skip to content

Instantly share code, notes, and snippets.

@sinsinpub
Last active May 5, 2022 04:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sinsinpub/f5b472598c8eb54312613e528778d174 to your computer and use it in GitHub Desktop.
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.
/****************************************************************************\
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