codegen now uses correct machine target's string encoder/decoder. Encoding more robust by checking upper case mapping if lowercase mapping fails.

This commit is contained in:
Irmen de Jong 2021-04-09 23:08:19 +02:00
parent e0454e95db
commit 2b7b925090
6 changed files with 81 additions and 49 deletions

View File

@ -7,6 +7,7 @@ import prog8.ast.base.*
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.AssignTarget
import prog8.compiler.AssemblyError
import prog8.compiler.CompilationOptions
import prog8.compiler.IErrorReporter
import prog8.compiler.Zeropage
@ -14,6 +15,7 @@ import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.cbm.Petscii
import prog8.compiler.target.cpu6502.codegen.AsmGen
import prog8.compiler.target.cx16.CX16MachineDefinition
import java.io.CharConversionException
import java.nio.file.Path
@ -70,9 +72,17 @@ internal object C64Target: ICompilationTarget {
override val name = "c64"
override val machine = C64MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean) =
if(altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
try {
if (altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
} catch (x: CharConversionException) {
throw AssemblyError("There was a problem converting a string to the target machine's char encoding: ${x.message}")
}
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
if(altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
try {
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
} catch (x: CharConversionException) {
throw AssemblyError("There was a problem decoding to a string: ${x.message}")
}
override fun memorySize(dt: DataType): Int {
return when(dt) {
@ -89,9 +99,17 @@ internal object Cx16Target: ICompilationTarget {
override val name = "cx16"
override val machine = CX16MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean) =
if(altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
try {
if (altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
} catch (x: CharConversionException) {
throw AssemblyError("There was a problem converting a string to the target machine's char encoding: ${x.message}")
}
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
if(altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
try {
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
} catch (x: CharConversionException) {
throw AssemblyError("There was a problem decoding to a string: ${x.message}")
}
override fun memorySize(dt: DataType): Int {
return when(dt) {

View File

@ -1051,49 +1051,75 @@ object Petscii {
fun encodePetscii(text: String, lowercase: Boolean = false): List<Short> {
val lookup = if(lowercase) encodingPetsciiLowercase else encodingPetsciiUppercase
return text.map {
val petscii = lookup[it]
petscii?.toShort() ?: when (it) {
fun encodeChar(chr: Char, lowercase: Boolean): Short {
val screencode = if(lowercase) encodingPetsciiLowercase[chr] else encodingPetsciiUppercase[chr]
return screencode?.toShort() ?: when (chr) {
'\u0000' -> 0.toShort()
in '\u8000'..'\u80ff' -> {
// special case: take the lower 8 bit hex value directly
(it.toInt() - 0x8000).toShort()
(chr.toInt() - 0x8000).toShort()
}
else -> {
val case = if (lowercase) "lower" else "upper"
throw CharConversionException("no ${case}case Petscii character for '$it' (${it.toShort()})")
throw CharConversionException("no ${case}Petscii character for '$chr' (${chr.toShort()})")
}
}
}
return text.map{
try {
encodeChar(it, lowercase)
} catch (x: CharConversionException) {
encodeChar(it, !lowercase)
}
}
}
fun decodePetscii(petscii: Iterable<Short>, lowercase: Boolean = false): String {
val decodeTable = if(lowercase) decodingPetsciiLowercase else decodingPetsciiUppercase
return petscii.map { decodeTable[it.toInt()] }.joinToString("")
return petscii.map {
val code = it.toInt()
try {
if(lowercase) decodingPetsciiLowercase[code] else decodingPetsciiUppercase[code]
} catch(x: CharConversionException) {
if(lowercase) decodingPetsciiUppercase[code] else decodingPetsciiLowercase[code]
}
}.joinToString("")
}
fun encodeScreencode(text: String, lowercase: Boolean = false): List<Short> {
val lookup = if(lowercase) encodingScreencodeLowercase else encodingScreencodeUppercase
return text.map{
val screencode = lookup[it]
screencode?.toShort() ?: when (it) {
fun encodeChar(chr: Char, lowercase: Boolean): Short {
val screencode = if(lowercase) encodingScreencodeLowercase[chr] else encodingScreencodeUppercase[chr]
return screencode?.toShort() ?: when (chr) {
'\u0000' -> 0.toShort()
in '\u8000'..'\u80ff' -> {
// special case: take the lower 8 bit hex value directly
(it.toInt() - 0x8000).toShort()
(chr.toInt() - 0x8000).toShort()
}
else -> {
val case = if (lowercase) "lower" else "upper"
throw CharConversionException("no ${case}Screencode character for '$it' (${it.toShort()})")
throw CharConversionException("no ${case}Screencode character for '$chr' (${chr.toShort()})")
}
}
}
return text.map{
try {
encodeChar(it, lowercase)
} catch (x: CharConversionException) {
encodeChar(it, !lowercase)
}
}
}
fun decodeScreencode(screencode: Iterable<Short>, lowercase: Boolean = false): String {
val decodeTable = if(lowercase) decodingScreencodeLowercase else decodingScreencodeUppercase
return screencode.map { decodeTable[it.toInt()] }.joinToString("")
return screencode.map {
val code = it.toInt()
try {
if (lowercase) decodingScreencodeLowercase[code] else decodingScreencodeUppercase[code]
} catch (x: CharConversionException) {
if (lowercase) decodingScreencodeUppercase[code] else decodingScreencodeLowercase[code]
}
}.joinToString("")
}
fun petscii2scr(petscii_code: Short, inverseVideo: Boolean): Short {

View File

@ -10,11 +10,9 @@ import prog8.compiler.functions.BuiltinFunctions
import prog8.compiler.functions.FSignature
import prog8.compiler.target.*
import prog8.compiler.target.cbm.AssemblyProgram
import prog8.compiler.target.cbm.Petscii
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignment
import prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen
import prog8.optimizer.CallGraph
import java.io.CharConversionException
import java.nio.file.Path
import java.nio.file.Paths
import java.time.LocalDate
@ -257,15 +255,6 @@ internal class AsmGen(private val program: Program,
} else assemblyLines.add(fragment)
}
private fun encode(str: String, altEncoding: Boolean): List<Short> {
try {
val bytes = if (altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
return bytes.plus(0)
} catch(x: CharConversionException) {
throw AssemblyError("There was a problem converting a string to the target machine's char encoding: ${x.message}")
}
}
private fun zeropagevars2asm(statements: List<Statement>) {
out("; vars allocated on zeropage")
val variables = statements.filterIsInstance<VarDecl>().filter { it.type==VarDeclType.VAR }
@ -304,7 +293,7 @@ internal class AsmGen(private val program: Program,
DataType.STRUCT -> {} // is flattened
DataType.STR -> {
val str = decl.value as StringLiteralValue
outputStringvar(decl, encode(str.value, str.altEncoding))
outputStringvar(decl, compTarget.encodeString(str.value, str.altEncoding).plus(0))
}
DataType.ARRAY_UB -> {
val data = makeArrayFillDataUnsigned(decl)
@ -401,7 +390,7 @@ internal class AsmGen(private val program: Program,
.filter {it.datatype == DataType.STR }
.map {
val str = it.value as StringLiteralValue
it to encode(str.value, str.altEncoding)
it to compTarget.encodeString(str.value, str.altEncoding).plus(0)
}
.groupBy({it.second}, {it.first})
for((encoded, variables) in encodedstringVars) {

View File

@ -348,8 +348,8 @@ class TestPetscii {
listOf<Short>(72, 69, 76, 76, 79, 32, 0xd7, 0xcf, 0xd2, 0xcc, 0xc4, 32, 49, 50, 51, 32, 64, 33, 0x5c)))
assertThat(Petscii.encodePetscii("\uf11a", true), equalTo(listOf<Short>(0x12))) // reverse vid
assertThat(Petscii.encodePetscii("", true), equalTo(listOf<Short>(0xfa)))
assertFailsWith<CharConversionException> { Petscii.encodePetscii("π", true) }
assertFailsWith<CharConversionException> { Petscii.encodePetscii("", true) }
assertThat("expect lowercase error fallback", Petscii.encodePetscii("π", true), equalTo(listOf<Short>(255)))
assertThat("expect lowercase error fallback", Petscii.encodePetscii("", true), equalTo(listOf<Short>(0xd3)))
assertThat(Petscii.decodePetscii(listOf(72, 0xd7, 0x5c, 0xfa, 0x12), true), equalTo("hW£✓\uF11A"))
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodePetscii(listOf(-1), true) }
@ -363,7 +363,7 @@ class TestPetscii {
assertThat(Petscii.encodePetscii("\uf11a"), equalTo(listOf<Short>(0x12))) // reverse vid
assertThat(Petscii.encodePetscii(""), equalTo(listOf<Short>(0xd3)))
assertThat(Petscii.encodePetscii("π"), equalTo(listOf<Short>(0xff)))
assertFailsWith<CharConversionException> { Petscii.encodePetscii("") }
assertThat("expecting fallback", Petscii.encodePetscii(""), equalTo(listOf<Short>(250)))
assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π"))
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodePetscii(listOf(-1)) }
@ -376,8 +376,8 @@ class TestPetscii {
listOf<Short>(0x08, 0x05, 0x0c, 0x0c, 0x0f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)
))
assertThat(Petscii.encodeScreencode("", true), equalTo(listOf<Short>(0x7a)))
assertFailsWith<CharConversionException> { Petscii.encodeScreencode("", true) }
assertFailsWith<CharConversionException> { Petscii.encodeScreencode("π", true) }
assertThat("expect fallback", Petscii.encodeScreencode("", true), equalTo(listOf<Short>(83)))
assertThat("expect fallback", Petscii.encodeScreencode("π", true), equalTo(listOf<Short>(94)))
assertThat(Petscii.decodeScreencode(listOf(0x08, 0x57, 0x1c, 0x7a), true), equalTo("hW£✓"))
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodeScreencode(listOf(-1), true) }
@ -390,8 +390,9 @@ class TestPetscii {
listOf<Short>(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)))
assertThat(Petscii.encodeScreencode(""), equalTo(listOf<Short>(0x53)))
assertThat(Petscii.encodeScreencode("π"), equalTo(listOf<Short>(0x5e)))
assertFailsWith<CharConversionException> { Petscii.encodeScreencode("") }
assertFailsWith<CharConversionException> { Petscii.encodeScreencode("hello") }
assertThat(Petscii.encodeScreencode("HELLO"), equalTo(listOf<Short>(8, 5, 12, 12, 15)))
assertThat("expecting fallback", Petscii.encodeScreencode("hello"), equalTo(listOf<Short>(8, 5, 12, 12, 15)))
assertThat("expecting fallback", Petscii.encodeScreencode(""), equalTo(listOf<Short>(122)))
assertThat(Petscii.decodeScreencode(listOf(0x17, 0x1c, 0x53, 0x5e)), equalTo("W£♥π"))
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodeScreencode(listOf(-1)) }

View File

@ -206,7 +206,7 @@ waitkey:
num_lines++
ubyte x
for x in boardOffsetX to boardOffsetX+boardWidth-1
txt.setcc(x, linepos, 160, 1)
txt.setcc(x, linepos, @'▒', 1)
}
}
if num_lines {
@ -338,7 +338,7 @@ waitkey:
for i in len(colors)-1 downto 0 {
ubyte x
for x in 5 downto 0 {
txt.setcc(6+x-i, 11+2*i, 102, colors[i])
txt.setcc(6+x-i, 11+2*i, @'▒', colors[i])
}
}
drawScore()

View File

@ -3,13 +3,11 @@
main {
sub start() {
ubyte lives=2
ubyte lvs
for lvs in 10 to lives {
txt.print_ub(lvs)
txt.spc()
}
txt.print("✓✓✓✓✓")
txt.nl()
txt.print("WWWWW")
txt.nl()
txt.print("●●●●●")
txt.nl()
}
}