Convertir un fichier Basic en Texte

Voici un petit utilitaire pour convertir un fichier basic en texte.

Vous trouverez la liste de tokens ici : https://www.bento8.fr/?p=54

package fr.bento8.to8.basic;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * @author Benoît Rousseau
 * @version 1.0
 *
 */
public class BasicConverter {

	byte[] basBytes;
	int fileSize;

	public static byte[][] keywords = {
			{0x45 ,0x4e ,0x44},	//	0x80	END
			{0x46 ,0x4f ,0x52},	//	0x81	FOR
			{0x4e ,0x45 ,0x58 ,0x54},	//	0x82	NEXT
			{0x44 ,0x41 ,0x54 ,0x41},	//	0x83	DATA
			{0x44 ,0x49 ,0x4d},	//	0x84	DIM
			{0x52 ,0x45 ,0x41 ,0x44},	//	0x85	READ
			{0x4c ,0x45 ,0x54},	//	0x86	LET
			{0x47 ,0x4f},	//	0x87	GO
			{0x52 ,0x55 ,0x4e},	//	0x88	RUN
			{0x49 ,0x46},	//	0x89	IF
			{0x52 ,0x45 ,0x53 ,0x54 ,0x4f ,0x52 ,0x45},	//	0x8A	RESTORE
			{0x52 ,0x45 ,0x54 ,0x55 ,0x52 ,0x4e},	//	0x8B	RETURN
			{0x52 ,0x45 ,0x4d},	//	0x8C	REM
			{0x27},	//	0x8D	'
			{0x53 ,0x54 ,0x4f ,0x50},	//	0x8E	STOP
			{0x45 ,0x4c ,0x53 ,0x45},	//	0x8F	ELSE
			{0x54 ,0x52 ,0x4f ,0x4e},	//	0x90	TRON
			{0x54 ,0x52 ,0x4f ,0x46 ,0x46},	//	0x91	TROFF
			{0x44 ,0x45 ,0x46 ,0x53 ,0x54 ,0x52},	//	0x92	DEFSTR
			{0x44 ,0x45 ,0x46 ,0x49 ,0x4e ,0x54},	//	0x93	DEFINT
			{0x44 ,0x45 ,0x46 ,0x53 ,0x4e ,0x47},	//	0x94	DEFSNG
			{0x44 ,0x45 ,0x46 ,0x44 ,0x42 ,0x4c},	//	0x95	DEFDBL
			{0x4f ,0x4e},	//	0x96	ON
			{0x57 ,0x41 ,0x49 ,0x54},	//	0x97	WAIT
			{0x45 ,0x52 ,0x52 ,0x4f ,0x52},	//	0x98	ERROR
			{0x52 ,0x45 ,0x53 ,0x55 ,0x4d ,0x45},	//	0x99	RESUME
			{0x41 ,0x55 ,0x54 ,0x4f},	//	0x9A	AUTO
			{0x44 ,0x45 ,0x4c ,0x45 ,0x54 ,0x45},	//	0x9B	DELETE
			{0x4c ,0x4f ,0x43 ,0x41 ,0x54 ,0x45},	//	0x9C	LOCATE
			{0x43 ,0x4c ,0x53},	//	0x9D	CLS
			{0x43 ,0x4f ,0x4e ,0x53 ,0x4f ,0x4c ,0x45},	//	0x9E	CONSOLE
			{0x50 ,0x53 ,0x45 ,0x54},	//	0x9F	PSET
			{0x4d ,0x4f ,0x54 ,0x4f ,0x52},	//	0xA0	MOTOR
			{0x53 ,0x4b ,0x49 ,0x50 ,0x46},	//	0xA1	SKIPF
			{0x45 ,0x58 ,0x45 ,0x43},	//	0xA2	EXEC
			{0x42 ,0x45 ,0x45 ,0x50},	//	0xA3	BEEP
			{0x43 ,0x4f ,0x4c ,0x4f ,0x52},	//	0xA4	COLOR
			{0x4c ,0x49 ,0x4e ,0x45},	//	0xA5	LINE
			{0x42 ,0x4f ,0x58},	//	0xA6	BOX
			{0x55 ,0x4e ,0x4d ,0x41 ,0x53 ,0x4b},	//	0xA7	UNMASK
			{0x41 ,0x54 ,0x54 ,0x52 ,0x42},	//	0xA8	ATTRB
			{0x44 ,0x45 ,0x46},	//	0xA9	DEF
			{0x50 ,0x4f ,0x4b ,0x45},	//	0xAA	POKE
			{0x50 ,0x52 ,0x49 ,0x4e ,0x54},	//	0xAB	PRINT
			{0x43 ,0x4f ,0x4e ,0x54},	//	0xAC	CONT
			{0x4c ,0x49 ,0x53 ,0x54},	//	0xAD	LIST
			{0x43 ,0x4c ,0x45 ,0x41 ,0x52},	//	0xAE	CLEAR
			{0x49 ,0x4e ,0x54 ,0x45 ,0x52 ,0x56 ,0x41 ,0x4c},	//	0xAF	INTERVAL
			{0x4b ,0x45 ,0x59},	//	0xB0	KEY
			{0x4e ,0x45 ,0x57},	//	0xB1	NEW
			{0x53 ,0x41 ,0x56 ,0x45},	//	0xB2	SAVE
			{0x4c ,0x4f ,0x41 ,0x44},	//	0xB3	LOAD
			{0x4d ,0x45 ,0x52 ,0x47 ,0x45},	//	0xB4	MERGE
			{0x4f ,0x50 ,0x45 ,0x4e},	//	0xB5	OPEN
			{0x43 ,0x4c ,0x4f ,0x53 ,0x45},	//	0xB6	CLOSE
			{0x49 ,0x4e ,0x50 ,0x45 ,0x4e},	//	0xB7	INPEN
			{0x50 ,0x45 ,0x4e},	//	0xB8	PEN
			{0x50 ,0x4c ,0x41 ,0x59},	//	0xB9	PLAY
			{0x54 ,0x41 ,0x42 ,0x28},	//	0xBA	TAB(
			{0x54 ,0x4f},	//	0xBB	TO
			{0x53 ,0x55 ,0x42},	//	0xBC	SUB
			{0x46 ,0x4e},	//	0xBD	FN
			{0x53 ,0x50 ,0x43 ,0x28},	//	0xBE	SPC(
			{0x55 ,0x53 ,0x49 ,0x4e ,0x47},	//	0xBF	USING
			{0x55 ,0x53 ,0x52},	//	0xC0	USR
			{0x45 ,0x52 ,0x4c},	//	0xC1	ERL
			{0x45 ,0x52 ,0x52},	//	0xC2	ERR
			{0x4f ,0x46 ,0x46},	//	0xC3	OFF
			{0x54 ,0x48 ,0x45 ,0x4e},	//	0xC4	THEN
			{0x4e ,0x4f ,0x54},	//	0xC5	NOT
			{0x53 ,0x54 ,0x45 ,0x50},	//	0xC6	STEP
			{0x2b},	//	0xC7	+
			{0x2d},	//	0xC8	-
			{0x2a},	//	0xC9	*
			{0x2f},	//	0xCA	/
			{0x5e},	//	0xCB	^
			{0x41 ,0x4e ,0x44},	//	0xCC	AND
			{0x4f ,0x52},	//	0xCD	OR
			{0x58 ,0x4f ,0x52},	//	0xCE	XOR
			{0x45 ,0x51 ,0x56},	//	0xCF	EQV
			{0x49 ,0x4d ,0x50},	//	0xD0	IMP
			{0x4d ,0x4f ,0x44},	//	0xD1	MOD
			{0x40},	//	0xD2	@
			{0x3e},	//	0xD3	>
			{0x3d},	//	0xD4	=
			{0x3c},	//	0xD5	<
			{0x44 ,0x53 ,0x4b ,0x49 ,0x4e ,0x49},	//	0xD6	DSKINI
			{0x44 ,0x53 ,0x4b ,0x4f ,0x24},	//	0xD7	DSKO$
			{0x4b ,0x49 ,0x4c ,0x4c},	//	0xD8	KILL
			{0x4e ,0x41 ,0x4d ,0x45},	//	0xD9	NAME
			{0x46 ,0x49 ,0x45 ,0x4c ,0x44},	//	0xDA	FIELD
			{0x4c ,0x53 ,0x45 ,0x54},	//	0xDB	LSET
			{0x52 ,0x53 ,0x45 ,0x54},	//	0xDC	RSET
			{0x50 ,0x55 ,0x54},	//	0xDD	PUT
			{0x47 ,0x45 ,0x54},	//	0xDE	GET
			{0x56 ,0x45 ,0x52 ,0x49 ,0x46 ,0x59},	//	0xDF	VERIFY
			{0x44 ,0x45 ,0x56 ,0x49 ,0x43 ,0x45},	//	0xE0	DEVICE
			{0x44 ,0x49 ,0x52},	//	0xE1	DIR
			{0x46 ,0x49 ,0x4c ,0x45 ,0x53},	//	0xE2	FILES
			{0x57 ,0x52 ,0x49 ,0x54 ,0x45},	//	0xE3	WRITE
			{0x55 ,0x4e ,0x4c ,0x4f ,0x41 ,0x44},	//	0xE4	UNLOAD
			{0x42 ,0x41 ,0x43 ,0x4b ,0x55 ,0x50},	//	0xE5	BACKUP
			{0x43 ,0x4f ,0x50 ,0x59},	//	0xE6	COPY
			{0x43 ,0x49 ,0x52 ,0x43 ,0x4c ,0x45},	//	0xE7	CIRCLE
			{0x50 ,0x41 ,0x49 ,0x4e ,0x54},	//	0xE8	PAINT
			{0x52 ,0x45 ,0x53 ,0x45 ,0x54},	//	0xE9	RESET
			{0x52 ,0x45 ,0x4e ,0x55 ,0x4d},	//	0xEA	RENUM
			{0x53 ,0x57 ,0x41 ,0x50},	//	0xEB	SWAP
			{0x2a},	//	0xEC	*
			{0x57 ,0x49 ,0x4e ,0x44 ,0x4f ,0x57},	//	0xED	WINDOW
			{0x50 ,0x41 ,0x54 ,0x54 ,0x45 ,0x52 ,0x4e},	//	0xEE	PATTERN
			{0x44 ,0x4f},	//	0xEF	DO
			{0x4c ,0x4f ,0x4f ,0x50},	//	0xF0	LOOP
			{0x45 ,0x58 ,0x49 ,0x54},	//	0xF1	EXIT
			{0x49 ,0x4e ,0x4d ,0x4f ,0x55 ,0x53 ,0x45},	//	0xF2	INMOUSE
			{0x4d ,0x4f ,0x55 ,0x53 ,0x45},	//	0xF3	MOUSE
			{0x43 ,0x48 ,0x41 ,0x49 ,0x4e},	//	0xF4	CHAIN
			{0x43 ,0x4f ,0x4d ,0x4d ,0x4f ,0x4e},	//	0xF5	COMMON
			{0x53 ,0x45 ,0x41 ,0x52 ,0x43 ,0x48},	//	0xF6	SEARCH
			{0x46 ,0x57 ,0x44},	//	0xF7	FWD
			{0x54 ,0x55 ,0x52 ,0x54 ,0x4c ,0x45}	//	0xF8	TURTLE
	};

	public static byte[][] functions = {
			{0x53 ,0x47 ,0x4e},	//	0xFF	0x80	SGN
			{0x49 ,0x4e ,0x54},	//	0xFF	0x81	INT
			{0x41 ,0x42 ,0x53},	//	0xFF	0x82	ABS
			{0x46 ,0x52 ,0x45},	//	0xFF	0x83	FRE
			{0x53 ,0x51 ,0x52},	//	0xFF	0x84	SQR
			{0x4c ,0x4f ,0x47},	//	0xFF	0x85	LOG
			{0x45 ,0x58 ,0x50},	//	0xFF	0x86	EXP
			{0x43 ,0x4f ,0x53},	//	0xFF	0x87	COS
			{0x53 ,0x49 ,0x4e},	//	0xFF	0x88	SIN
			{0x54 ,0x41 ,0x4e},	//	0xFF	0x89	TAN
			{0x50 ,0x45 ,0x45 ,0x4b},	//	0xFF	0x8A	PEEK
			{0x4c ,0x45 ,0x4e},	//	0xFF	0x8B	LEN
			{0x53 ,0x54 ,0x52 ,0x24},	//	0xFF	0x8C	STR$
			{0x56 ,0x41 ,0x4c},	//	0xFF	0x8D	VAL
			{0x41 ,0x53 ,0x43},	//	0xFF	0x8E	ASC
			{0x43 ,0x48 ,0x52 ,0x24},	//	0xFF	0x8F	CHR$
			{0x45 ,0x4f ,0x46},	//	0xFF	0x90	EOF
			{0x43 ,0x49 ,0x4e ,0x54},	//	0xFF	0x91	CINT
			{0x43 ,0x53 ,0x4e ,0x47},	//	0xFF	0x92	CSNG
			{0x43 ,0x44 ,0x42 ,0x4c},	//	0xFF	0x93	CDBL
			{0x46 ,0x49 ,0x58},	//	0xFF	0x94	FIX
			{0x48 ,0x45 ,0x58 ,0x24},	//	0xFF	0x95	HEX$
			{0x4f ,0x43 ,0x54 ,0x24},	//	0xFF	0x96	OCT$
			{0x53 ,0x54 ,0x49 ,0x43 ,0x4b},	//	0xFF	0x97	STICK
			{0x53 ,0x54 ,0x52 ,0x49 ,0x47},	//	0xFF	0x98	STRIG
			{0x47 ,0x52 ,0x24},	//	0xFF	0x99	GR$
			{0x4c ,0x45 ,0x46 ,0x54 ,0x24},	//	0xFF	0x9A	LEFT$
			{0x52 ,0x49 ,0x47 ,0x48 ,0x54 ,0x24},	//	0xFF	0x9B	RIGHT$
			{0x4d ,0x49 ,0x44 ,0x24},	//	0xFF	0x9C	MID$
			{0x49 ,0x4e ,0x53 ,0x54 ,0x52},	//	0xFF	0x9D	INSTR
			{0x56 ,0x41 ,0x52 ,0x50 ,0x54 ,0x52},	//	0xFF	0x9E	VARPTR
			{0x52 ,0x4e ,0x44},	//	0xFF	0x9F	RND
			{0x49 ,0x4e ,0x4b ,0x45 ,0x59 ,0x24},	//	0xFF	0xA0	INKEY$
			{0x49 ,0x4e ,0x50 ,0x55 ,0x54},	//	0xFF	0xA1	INPUT
			{0x43 ,0x53 ,0x52 ,0x4c ,0x49 ,0x4e},	//	0xFF	0xA2	CSRLIN
			{0x50 ,0x4f ,0x49 ,0x4e ,0x54},	//	0xFF	0xA3	POINT
			{0x53 ,0x43 ,0x52 ,0x45 ,0x45 ,0x4e},	//	0xFF	0xA4	SCREEN
			{0x50 ,0x4f ,0x53},	//	0xFF	0xA5	POS
			{0x50 ,0x54 ,0x52 ,0x49 ,0x47},	//	0xFF	0xA6	PTRIG
			{0x44 ,0x53 ,0x4b ,0x46},	//	0xFF	0xA7	DSKF
			{0x43 ,0x56 ,0x49},	//	0xFF	0xA8	CVI
			{0x43 ,0x56 ,0x53},	//	0xFF	0xA9	CVS
			{0x43 ,0x56 ,0x44},	//	0xFF	0xAA	CVD
			{0x4d ,0x4b ,0x49 ,0x24},	//	0xFF	0xAB	MKI$
			{0x4d ,0x4b ,0x53 ,0x24},	//	0xFF	0xAC	MKS$
			{0x4d ,0x4b ,0x44 ,0x24},	//	0xFF	0xAD	MKD$
			{0x4c ,0x4f ,0x43},	//	0xFF	0xAE	LOC
			{0x4c ,0x4f ,0x46},	//	0xFF	0xAF	LOF
			{0x53 ,0x50 ,0x41 ,0x43 ,0x45 ,0x24},	//	0xFF	0xB0	SPACE$
			{0x53 ,0x54 ,0x52 ,0x49 ,0x4e ,0x47 ,0x24},	//	0xFF	0xB1	STRING$
			{0x44 ,0x53 ,0x4b ,0x49 ,0x24},	//	0xFF	0xB2	DSKI$
			{0x46 ,0x4b ,0x45 ,0x59 ,0x24},	//	0xFF	0xB3	FKEY$
			{0x4d ,0x49 ,0x4e ,0x28},	//	0xFF	0xB4	MIN(
			{0x4d ,0x41 ,0x58 ,0x28},	//	0xFF	0xB5	MAX(
			{0x41 ,0x54 ,0x4e},	//	0xFF	0xB6	ATN
			{0x43 ,0x52 ,0x55 ,0x4e ,0x43 ,0x48 ,0x24},	//	0xFF	0xB7	CRUNCH$
			{0x4d ,0x54 ,0x52 ,0x49 ,0x47},	//	0xFF	0xB8	MTRIG
			{0x45 ,0x56 ,0x41 ,0x4c},	//	0xFF	0xB9	EVAL
			{0x50 ,0x41 ,0x4c ,0x45 ,0x54 ,0x54 ,0x45},	//	0xFF	0xBA	PALETTE
			{0x42 ,0x41 ,0x4e ,0x4b},	//	0xFF	0xBB	BANK
			{0x48 ,0x45 ,0x41 ,0x44},	//	0xFF	0xBC	HEAD
			{0x52 ,0x4f ,0x54},	//	0xFF	0xBD	ROT
			{0x53 ,0x48 ,0x4f ,0x57},	//	0xFF	0xBE	SHOW
			{0x5a ,0x4f ,0x4f ,0x4d},	//	0xFF	0xBF	ZOOM
			{0x54 ,0x52 ,0x41 ,0x43 ,0x45}	//	0xFF	0xC0	TRACE
	};

	public BasicConverter() {
	}

	public void load(String fileName) {
		try {
			basBytes = Files.readAllBytes(Paths.get(fileName));										// Lecture de l'en-tête du fichier .bas

			byte fileType = basBytes[0];
			if (fileType != (byte) 0xff) {															// Octet 0   : 0xff (Type du fichier)
				throw new IllegalStateException("Type de fichier non reconnu: Le premier octet "+
						fileType+" n'est pas 0xff");
			}

			fileSize = basBytes[1] << 8 & 0xff00 | basBytes[2] & 0xff;								// Octet 1-2 : Longueur du fichier
			System.out.println("Taille du fichier "+fileName+": "+fileSize+" octets.");

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public byte[] convertToAscii() {

		if (basBytes == null) {
			return null;
		}

		byte[] txtBytes = new byte[basBytes.length*8];												// On réserve de l'espace supplémentaire pour le remplacement des codes par les mots clés
		int i=3, j=0, k, l;																			// La première ligne commence a l'index 3
		int linelength, lineNumber;
		String lineNumberStr;

		while (i<basBytes.length-2) {																// Lecture ligne à ligne du fichier basic (on ne lit pas les deux octets 0x0000 en fin de fichier)
			linelength = basBytes[i++] << 8 & 0xFF00 | basBytes[i++] & 0xFF;						// La longueur de la ligne comprend line length et line number
			lineNumber = basBytes[i++] << 8 & 0xFF00 | basBytes[i++] & 0xFF;
			lineNumberStr = String.valueOf(lineNumber);
			System.out.println("Lecture ligne: "+lineNumberStr+" longueur: "+linelength);

			for (l = 0; l < lineNumberStr.length(); l++) {											// ajout du numéro de ligne
				txtBytes[j++] = (byte) lineNumberStr.charAt(l);
			}
			txtBytes[j++] = (byte) 0x20;															// ajout d'un espace
			
			while (basBytes[i] != (byte) 0x00) { 													// une fin de ligne se termine par la valeur 0x00			
				if (basBytes[i] == (byte) 0x16) { 													// caractères accentués
					if (basBytes[i+1] == (byte) 0x41) { 											// - accent grave
						if (basBytes[i+2] == (byte) 0x61) {txtBytes[j++] = (byte) 0xe0; i+=2;} 		// à
						else if (basBytes[i+2] == (byte) 0x65) {txtBytes[j++] = (byte) 0xe8; i+=2;} // è
						else if (basBytes[i+2] == (byte) 0x75) {txtBytes[j++] = (byte) 0xf9; i+=2;} // ù
					} else if (basBytes[i+1] == (byte) 0x42) { 										// - accent aigu
						if (basBytes[i+2] == (byte) 0x65) {txtBytes[j++] = (byte) 0xe9; i+=2;} 		// é
					} else if (basBytes[i+1] == (byte) 0x43) { 										// - accent circonflexe
						if (basBytes[i+2] == (byte) 0x61) {txtBytes[j++] = (byte) 0xe2; i+=2;}		// â
						else if (basBytes[i+2] == (byte) 0x65) {txtBytes[j++] = (byte) 0xea; i+=2;} // ê
						else if (basBytes[i+2] == (byte) 0x69) {txtBytes[j++] = (byte) 0xee; i+=2;} // î
						else if (basBytes[i+2] == (byte) 0x6f) {txtBytes[j++] = (byte) 0xf4; i+=2;} // ô
						else if (basBytes[i+2] == (byte) 0x75) {txtBytes[j++] = (byte) 0xfb; i+=2;} // û
					} else if (basBytes[i+1] == (byte) 0x48) { 										// - tréma
						if (basBytes[i+2] == (byte) 0x65) {txtBytes[j++] = (byte) 0xeb; i+=2;}		// ë
						else if (basBytes[i+2] == (byte) 0x69) {txtBytes[j++] = (byte) 0xef; i+=2;} // ï
						else if (basBytes[i+2] == (byte) 0x6f) {txtBytes[j++] = (byte) 0xf6; i+=2;} // ö
						else if (basBytes[i+2] == (byte) 0x75) {txtBytes[j++] = (byte) 0xfc; i+=2;} // ü
					} else if (basBytes[i+1] == (byte) 0x4b) { 										// - cédille
						if (basBytes[i+2] == (byte) 0x63) {txtBytes[j++] = (byte) 0xe7; i+=2;} 		// ç
					}
					else {
						System.out.println("Caractère accentué "+
								String.format("0x%02X", basBytes[i])+" "+
								String.format("0x%02X", basBytes[i+1])+" "+
								String.format("0x%02X", basBytes[i+2])+
								" non reconnu.");
						i+=3;}
				} else if (basBytes[i] == (byte) 0xff) {											// Gestion des fonctions Basic
					i++;																			// on se positione après la balise 0xff
					if (basBytes[i] <= (byte) 0xc0 && functions[basBytes[i]+128].length > 0) { 		// test de la valeur la plus haute du tableau de correspondance et vérification de la présence d'une valeur
						for (k = 0; k < functions[basBytes[i]+128].length; k++) { 					// +128 positionne la valeur 0x80 à l'index 0 du tableau
							txtBytes[j++] = functions[basBytes[i]+128][k];							// écriture lettre à lettre du nom de fonction
						}
					} else {
						System.out.println("Fonction 0xFF "+
								String.format("0x%02X", basBytes[i])+
								" non reconnue.");
						txtBytes[j++] = basBytes[i];
					}
				} else if (basBytes[i] < (byte) 0xff) { 											// Gestion des mots clés Basic
					if (basBytes[i] <= (byte) 0xf8 && keywords[basBytes[i]+128].length > 0) { 		// test de la valeur la plus haute du tableau de correspondance et vérification de la présence d'une valeur
						for (k = 0; k < keywords[basBytes[i]+128].length; k++) {					// +128 positionne la valeur 0x80 à l'index 0 du tableau
							txtBytes[j++] = keywords[basBytes[i]+128][k];							// écriture lettre à lettre du nom de mot clé
						}
					} else {
						System.out.println("Mot clé "+
								String.format("0x%02X", basBytes[i])+
								" non reconnu.");
						txtBytes[j++] = basBytes[i];
					}
				} else {
					txtBytes[j++] = basBytes[i];													// Caractère sans transcodage
				}
				i++;
			}
			i++;
			txtBytes[j++] = (byte) 0x0d;															// Ajout d'un retour à la ligne
			txtBytes[j++] = (byte) 0x0a;
		}
		System.out.println("Conversion terminée.");
		return txtBytes;
	}	
}
package fr.bento8.to8.samples;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import fr.bento8.to8.basic.BasicConverter;

/**
 * @author Benoît Rousseau
 * @version 1.0
 *
 */
public class BasToTxt
{

	/**
	 * Effectue la conversion d'un fichier BASIC (.BAS) TO8 Thomson en fichier Texte
	 * 
	 * @param args nom du fichier .BAS a convertir
	 */
	public static void main(String[] args)
	{
		try {
			
			String basFileName = args[0];
			
			BasicConverter bc = new BasicConverter();
			bc.load(basFileName);
			byte[] txtBytes = bc.convertToAscii();

			Path outputFile = Paths.get(basFileName.substring(0, basFileName.lastIndexOf('.'))+".txt");
			Files.deleteIfExists(outputFile);
			Files.createFile(outputFile);
			Files.write(outputFile, txtBytes);
			System.out.println("Ecriture du fichier "+outputFile.getFileName()+" terminée.");

		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e);
		}
	}
}

Liste des tokens BASIC 512 du TO8

Vous trouverez des informations très utiles sur le format d’encodage des fichiers Basic sur Thomson à cette page : http://pulkomandy.tk/wiki/doku.php?id=documentations:basic_internals

J’avais besoin de m’assurer de bien lister l’ensemble des tokens du BASIC512 sur TO8. J’ai donc écrit un programme .BAS avec un éditeur hexadécimal en entrant chaque valeur de token (un par ligne). J’ai ensuite utilisé LIST pour afficher les valeurs correspondantes. Voici ce que j’ai obtenu :

TokenKeywordPrefixTokenFunction
0x80END0xFF0x80SGN
0x81FOR0xFF0x81INT
0x82NEXT0xFF0x82ABS
0x83DATA0xFF0x83FRE
0x84DIM0xFF0x84SQR
0x85READ0xFF0x85LOG
0x86LET0xFF0x86EXP
0x87GO0xFF0x87COS
0x88RUN0xFF0x88SIN
0x89IF0xFF0x89TAN
0x8ARESTORE0xFF0x8APEEK
0x8BRETURN0xFF0x8BLEN
0x8CREM0xFF0x8CSTR$
0x8D0xFF0x8DVAL
0x8ESTOP0xFF0x8EASC
0x8FELSE0xFF0x8FCHR$
0x90TRON0xFF0x90EOF
0x91TROFF0xFF0x91CINT
0x92DEFSTR0xFF0x92CSNG
0x93DEFINT0xFF0x93CDBL
0x94DEFSNG0xFF0x94FIX
0x95DEFDBL0xFF0x95HEX$
0x96ON0xFF0x96OCT$
0x97WAIT0xFF0x97STICK
0x98ERROR0xFF0x98STRIG
0x99RESUME0xFF0x99GR$
0x9AAUTO0xFF0x9ALEFT$
0x9BDELETE0xFF0x9BRIGHT$
0x9CLOCATE0xFF0x9CMID$
0x9DCLS0xFF0x9DINSTR
0x9ECONSOLE0xFF0x9EVARPTR
0x9FPSET0xFF0x9FRND
0xA0MOTOR0xFF0xA0INKEY$
0xA1SKIPF0xFF0xA1INPUT
0xA2EXEC0xFF0xA2CSRLIN
0xA3BEEP0xFF0xA3POINT
0xA4COLOR0xFF0xA4SCREEN
0xA5LINE0xFF0xA5POS
0xA6BOX0xFF0xA6PTRIG
0xA7UNMASK0xFF0xA7DSKF
0xA8ATTRB0xFF0xA8CVI
0xA9DEF0xFF0xA9CVS
0xAAPOKE0xFF0xAACVD
0xABPRINT0xFF0xABMKI$
0xACCONT0xFF0xACMKS$
0xADLIST0xFF0xADMKD$
0xAECLEAR0xFF0xAELOC
0xAFINTERVAL0xFF0xAFLOF
0xB0KEY0xFF0xB0SPACE$
0xB1NEW0xFF0xB1STRING$
0xB2SAVE0xFF0xB2DSKI$
0xB3LOAD0xFF0xB3FKEY$
0xB4MERGE0xFF0xB4MIN(
0xB5OPEN0xFF0xB5MAX(
0xB6CLOSE0xFF0xB6ATN
0xB7INPEN0xFF0xB7CRUNCH$
0xB8PEN0xFF0xB8MTRIG
0xB9PLAY0xFF0xB9EVAL
0xBATAB(0xFF0xBAPALETTE
0xBBTO0xFF0xBBBANK
0xBCSUB0xFF0xBCHEAD
0xBDFN0xFF0xBDROT
0xBESPC(0xFF0xBESHOW
0xBFUSING0xFF0xBFZOOM
0xC0USR0xFF0xC0TRACE
0xC1ERL   
0xC2ERR   
0xC3OFF   
0xC4THEN   
0xC5NOT   
0xC6STEP   
0xC7+   
0xC8   
0xC9*   
0xCA/   
0xCB^   
0xCCAND   
0xCDOR   
0xCEXOR   
0xCFEQV   
0xD0IMP   
0xD1MOD   
0xD2@   
0xD3>   
0xD4=   
0xD5<   
0xD6DSKINI   
0xD7DSKO$   
0xD8KILL   
0xD9NAME   
0xDAFIELD   
0xDBLSET   
0xDCRSET   
0xDDPUT   
0xDEGET   
0xDFVERIFY   
0xE0DEVICE   
0xE1DIR   
0xE2FILES   
0xE3WRITE   
0xE4UNLOAD   
0xE5BACKUP   
0xE6COPY   
0xE7CIRCLE   
0xE8PAINT   
0xE9RESET   
0xEARENUM   
0xEBSWAP   
0xEC*   
0xEDWINDOW   
0xEEPATTERN   
0xEFDO   
0xF0LOOP   
0xF1EXIT   
0xF2INMOUSE   
0xF3MOUSE   
0xF4CHAIN   
0xF5COMMON   
0xF6SEARCH   
0xF7FWD   
0xF8TURTLE   

Je vous propose également un convertisseur basic vers texte : https://www.bento8.fr/?p=56

Solution du jeu : Mission très spéciale

Je vous propose la solution du jeu « Mission très spéciale » édité par Free Game Blot en 1985.

Ecran-titre
Introduction

Le but du jeu est de parcourir un labyrinthe en résolvant des énigmes. Le joueur utilise les flèches du pavé directionnel pour se déplacer dans les pièces voisines. Dans chaque pièce il est possible d’effectuer des actions à l’aide d’un verbe et d’un complément, chacun sur trois lettres.

Exemple : « PRE LIV » pour « prendre livre »

Dictionnaire des verbes

La numérotation des verbes correspond à celle du code source (variable V).

VTrigrammeVerbe
1PREPrendre
2EXAExaminer
3PROPrononcer
4LIRLire
5OUVOuvrir
6BOIBoire
7ACTActionner
8BOUBoucher
9UTIUtiliser
10CROCroire
11LANLancer
12FOUFouiller
13CHACharger, Charmer
14TRATraduire, Traverser
15POSPoser
16SOUSoulever
17FROFrotter

Dictionnaire des compléments

La liste des compléments est disponible dans le jeu (pièce 46). Le complément n°27 correspond à une énigme et n’est donc pas divulgué en début de jeu, il est remplacé par ???.

La numérotation des compléments correspond à celle du code source (variable N).

NTrigrammeComplément
1OBJObjet
2BOUBouteille, Bourse
3FLAFlacon
4LIVLivre
5REVRevolver
6BOIBoite
7PORPorte
8COFCoffre
9FORFormule
10MANManette
11TROTrou
12VASVasisdas, Vase
13MURMur
14CERCercueil
15SOUSouterrain
16MASMastic
17SERSerrure, Serpent, Sermon
18FLUFlûte
19COUCouverture
20FIOFiole
21CLEClé
22MESMessage
23TAPTapis
24CARCarnet, Cartouche
25CITCitron
26PAGPage
27NEUNeutralisateur

Plan du labyrinthe

Un point de couleur en haut à droite signifie une liaison entre deux pièces. Par exemple lorsque vous empruntez le passage secret de la pièce 36, celui ci vous mène en pièce 20.

La numérotation des pièces correspond à celle du code source (variable P).

Plan du labyrinthe

Mode opératoire

Voici les différentes étapes pour arriver à la fin du jeu.

Vous débutez en pièce 44, déplacez vous dans la pièce indiquée par le tableau en vous aidant du plan du labyrinthe, puis exécutez les actions indiquées.

PièceActionDescription
46EXA COUExaminer Couverture
36LIR MESLire Message
36PRO FORPrononcer Formule
28SOU TAPSoulever Tapis
28PRE CARPrendre Carnet
28LIR CARLire Carnet
37PRE REVPrendre Revolver
31PRE FLAPrendre Flacon
31EXA FLAExaminer Flacon
61EXA MURExaminer Mur
49PRE CITPrendre Citron
49FRO PAGFrotter Page
49LIR CARLire Carnet
49SOU TAPSoulever Tapis
49PRE BOIPrendre Boîte
49EXA BOIExaminer Boîte
49CHA REVCharger Revolver
55UTI REVUtiliser Revolver
55OUV POROuvrir Porte
63PRE MASPrendre Mastic
35LAN FLALancer Flacon
18<Flèche du haut>Faire monter l’eau
18<Flèche du haut>Faire monter l’eau
18<Flèche du haut>Faire monter l’eau
18BOU TROBoucher Trou
18OUV VASOuvrir Vasisdas
17ACT MANActionner Manette
32PRE OBJPrendre Objet (SCHMILBLIC)
34PRE FIOPrendre Fiole
34EXA FIOExamier Fiole
40BOI FIOBoire Fiole
57BOI FIOBoire Fiole
60LIR MESLire Message
60TRA MESTraduire Message (ABRACADABRA)
62EXA MURExaminer Mur
62OUV CEROuvrir Cercueil
62EXA CERExaminer Cercueil
62TRA SOUTraverser Souterrain
62<Flèche du haut>Avancer
10<Flèche de gauche ou droite>Répondre: VITE
10OUV POROuvrir Porte
9PRE FLUPrendre Flûte
0CHA SERCharmer Serpent
0FOU VASFouiller Vase
0PRE CLEPrendre Clé
3ACT MANActionner Manette
4PRE NEUPrendre Neutralisateur
21<Flèche de gauche>Entrer le code secret ! (jeu aléatoire)
21OUV POROuvrir Porte
7*La réponse universelle est 42, utiliser le caractère ascii n°42 pour répondre.
(Sous DCMOTO utiliser le clavier virtuel)
23OUV COFEntrer la combinaison ! (jeu aléatoire)
23UTI CLEUtiliser Clé
23OUV COFOuvrir Coffre
23POS NEUPoser Neutraliseur
23PRE BOUPrendre Bourse

Remarques :

  • en pièce 21 si vous ne trouvez pas la bonne réponse au bout de 50 essais, le jeu considère que vous avez trouvé.
  • si vous êtes coincés sur le jeu en pièce 23, il existe des outils comme celui-ci : https://www.dcode.fr/solveur-mastermind

Il y a quelques anomalies dans le jeu, le programme quitte et l’on revient à l’invite de commande Basic … Cela se produit dans les cas suivants :

4PRE OBJPrendre Objet (NEUTRALISATEUR) Dupicate Definition in 45 (DIML$(14)). Pour que cela fonctionne ne pas prendre le schmilblic dans la pièce 32
23UTI CLEEntrer la combinaison ! (jeu aléatoire) Syntax Error in 167 que l’on perde ou gagne (D(1O)=1 il y a un O au lieu d’un 0). Pour que cela fonctionne, utiliser OUV COF a la place de UTI CLE.