/// <summary> /// Gets the specified BASIC code line /// </summary> /// <param name="progStart">Code line address in the memory</param> /// <param name="lineVm">BASIC line view model</param> /// <returns></returns> public ushort GetBasicLine(ushort progStart, out BasicLineViewModel lineVm) { lineVm = new BasicLineViewModel { LineNo = Memory[progStart++] * 0x100 + Memory[progStart++], Length = Memory[progStart++] + Memory[progStart++] * 0x100 }; var lineEnd = progStart + lineVm.Length; if (lineEnd > Memory.Length - 1) { lineEnd = Memory.Length - 1; } var spaceBeforeToken = false; var sb = new StringBuilder(256); while (progStart < lineEnd) { var nextSymbol = Memory[progStart++]; if (nextSymbol >= 0xA5) { // --- This is a token if (spaceBeforeToken) { sb.Append(" "); } var tokenCode = nextSymbol - 0xA5; var token = _tokens[tokenCode]; sb.Append(token); if (tokenCode > 2 && char.IsLetter(token[token.Length - 1])) { sb.Append(" "); spaceBeforeToken = false; } continue; } // --- Whatever we print, the next token needs a space spaceBeforeToken = true; if (nextSymbol >= 0x20 && nextSymbol <= 0x7F) { // --- Printable character sb.Append((char)nextSymbol); continue; } if (nextSymbol == 0x0D) { continue; } if (nextSymbol == 0x0E) { // --- Skip the binary form of a floating point number progStart += 5; continue; } // --- Non-printable character, let's display it with an escape sequence sb.Append($"°{nextSymbol:X2}°"); } lineVm.Text = sb.ToString(); return(progStart); }
/// <summary> /// Gets the specified BASIC code line /// </summary> /// <param name="progStart">Code line address in the memory</param> /// <param name="lineVm">BASIC line view model</param> /// <returns></returns> public ushort GetBasicLine(ushort progStart, out BasicLineViewModel lineVm) { lineVm = new BasicLineViewModel { LineNo = Memory[progStart++] * 0x100 + Memory[progStart++], Length = Memory[progStart++] + Memory[progStart++] * 0x100 }; var lineEnd = progStart + lineVm.Length; if (lineEnd > Memory.Length - 1) { lineEnd = Memory.Length - 1; } var spaceBeforeToken = false; var withinQuotes = false; var sb = new StringBuilder(256); while (progStart < lineEnd) { var nextSymbol = Memory[progStart++]; if (nextSymbol >= 0xA5) { // --- This is a token if (spaceBeforeToken) { sb.Append(" "); } var tokenCode = nextSymbol - 0xA5; var token = _tokens[tokenCode]; sb.Append(token); if (tokenCode > 2 && char.IsLetter(token[token.Length - 1])) { sb.Append(" "); spaceBeforeToken = false; } continue; } // --- Whatever we print, the next token needs a space spaceBeforeToken = true; // --- Skip ENTER if (nextSymbol == 0x0D) { continue; } // --- Skip binary number characters if (nextSymbol == 0x0E) { // --- Skip the binary form of a floating point number progStart += 5; continue; } if (nextSymbol == 0x22) { // --- Printable character sb.Append((char)nextSymbol); withinQuotes = !withinQuotes; continue; } if (MimicZxBasic && !withinQuotes && nextSymbol < 0x20) { // --- Skip all remaining control characters in ZX BASIC mode continue; } if (nextSymbol >= 0x20 && nextSymbol <= 0x7F) { // --- Printable character if (withinQuotes) { if (nextSymbol == (int)'\\') { sb.Append(MimicZxBasic ? "\\\\" : "\\"); continue; } else if (nextSymbol == 0x60) { sb.Append(MimicZxBasic ? "\\`" : "Ł"); continue; } else if (nextSymbol == 0x7f) { sb.Append(MimicZxBasic ? "\\*" : "©"); continue; } } else { if (nextSymbol == (int)'\\') { sb.Append("\\"); continue; } else if (nextSymbol == 0x60) { sb.Append("Ł"); continue; } else if (nextSymbol == 0x7f) { sb.Append("©"); continue; } } sb.Append((char)nextSymbol); continue; } // --- Non-printable character, let's display it with an escape sequence if (MimicZxBasic && withinQuotes) { if (nextSymbol >= 0x90 && nextSymbol <= 0xA4) { // --- Handle UDG chars in ZX BASIC sb.Append($"\\{(char)(nextSymbol - 0x90 + 'A')}"); continue; } var lookahead = progStart < Memory.Length ? Memory[progStart] : -1; switch (nextSymbol) { case 0x10: if (lookahead >= 0) { sb.Append("\\{i" + lookahead + "}"); progStart++; } break; case 0x11: if (lookahead >= 0) { sb.Append("\\{p" + lookahead + "}"); progStart++; } break; case 0x12: if (lookahead >= 0) { sb.Append("\\{f" + lookahead + "}"); progStart++; } break; case 0x13: if (lookahead >= 0) { sb.Append("\\{b" + lookahead + "}"); progStart++; } break; case 0x80: sb.Append("\\ "); break; case 0x81: sb.Append("\\ '"); break; case 0x82: sb.Append("\\' "); break; case 0x83: sb.Append("\\''"); break; case 0x84: sb.Append("\\ ."); break; case 0x85: sb.Append("\\ :"); break; case 0x86: sb.Append("\\'."); break; case 0x87: sb.Append("\\':"); break; case 0x88: sb.Append("\\. "); break; case 0x89: sb.Append("\\.'"); break; case 0x8a: sb.Append("\\: "); break; case 0x8b: sb.Append("\\:'"); break; case 0x8c: sb.Append("\\.."); break; case 0x8d: sb.Append("\\.:"); break; case 0x8e: sb.Append("\\:."); break; case 0x8f: sb.Append("\\::"); break; default: sb.Append($"#{nextSymbol & 0xff}"); break; } } else { sb.Append($"°{nextSymbol:X2}°"); } } lineVm.Text = sb.ToString(); return(progStart); }