mirror of
https://github.com/irmen/prog8.git
synced 2025-02-19 11:31:07 +00:00
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:
parent
e0454e95db
commit
2b7b925090
@ -7,6 +7,7 @@ import prog8.ast.base.*
|
|||||||
import prog8.ast.expressions.IdentifierReference
|
import prog8.ast.expressions.IdentifierReference
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.expressions.NumericLiteralValue
|
||||||
import prog8.ast.statements.AssignTarget
|
import prog8.ast.statements.AssignTarget
|
||||||
|
import prog8.compiler.AssemblyError
|
||||||
import prog8.compiler.CompilationOptions
|
import prog8.compiler.CompilationOptions
|
||||||
import prog8.compiler.IErrorReporter
|
import prog8.compiler.IErrorReporter
|
||||||
import prog8.compiler.Zeropage
|
import prog8.compiler.Zeropage
|
||||||
@ -14,6 +15,7 @@ import prog8.compiler.target.c64.C64MachineDefinition
|
|||||||
import prog8.compiler.target.cbm.Petscii
|
import prog8.compiler.target.cbm.Petscii
|
||||||
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
||||||
import prog8.compiler.target.cx16.CX16MachineDefinition
|
import prog8.compiler.target.cx16.CX16MachineDefinition
|
||||||
|
import java.io.CharConversionException
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
|
||||||
@ -70,9 +72,17 @@ internal object C64Target: ICompilationTarget {
|
|||||||
override val name = "c64"
|
override val name = "c64"
|
||||||
override val machine = C64MachineDefinition
|
override val machine = C64MachineDefinition
|
||||||
override fun encodeString(str: String, altEncoding: Boolean) =
|
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) =
|
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 {
|
override fun memorySize(dt: DataType): Int {
|
||||||
return when(dt) {
|
return when(dt) {
|
||||||
@ -89,9 +99,17 @@ internal object Cx16Target: ICompilationTarget {
|
|||||||
override val name = "cx16"
|
override val name = "cx16"
|
||||||
override val machine = CX16MachineDefinition
|
override val machine = CX16MachineDefinition
|
||||||
override fun encodeString(str: String, altEncoding: Boolean) =
|
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) =
|
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 {
|
override fun memorySize(dt: DataType): Int {
|
||||||
return when(dt) {
|
return when(dt) {
|
||||||
|
@ -1051,49 +1051,75 @@ object Petscii {
|
|||||||
|
|
||||||
|
|
||||||
fun encodePetscii(text: String, lowercase: Boolean = false): List<Short> {
|
fun encodePetscii(text: String, lowercase: Boolean = false): List<Short> {
|
||||||
val lookup = if(lowercase) encodingPetsciiLowercase else encodingPetsciiUppercase
|
fun encodeChar(chr: Char, lowercase: Boolean): Short {
|
||||||
return text.map {
|
val screencode = if(lowercase) encodingPetsciiLowercase[chr] else encodingPetsciiUppercase[chr]
|
||||||
val petscii = lookup[it]
|
return screencode?.toShort() ?: when (chr) {
|
||||||
petscii?.toShort() ?: when (it) {
|
|
||||||
'\u0000' -> 0.toShort()
|
'\u0000' -> 0.toShort()
|
||||||
in '\u8000'..'\u80ff' -> {
|
in '\u8000'..'\u80ff' -> {
|
||||||
// special case: take the lower 8 bit hex value directly
|
// special case: take the lower 8 bit hex value directly
|
||||||
(it.toInt() - 0x8000).toShort()
|
(chr.toInt() - 0x8000).toShort()
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val case = if (lowercase) "lower" else "upper"
|
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 {
|
fun decodePetscii(petscii: Iterable<Short>, lowercase: Boolean = false): String {
|
||||||
val decodeTable = if(lowercase) decodingPetsciiLowercase else decodingPetsciiUppercase
|
return petscii.map {
|
||||||
return petscii.map { decodeTable[it.toInt()] }.joinToString("")
|
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> {
|
fun encodeScreencode(text: String, lowercase: Boolean = false): List<Short> {
|
||||||
val lookup = if(lowercase) encodingScreencodeLowercase else encodingScreencodeUppercase
|
fun encodeChar(chr: Char, lowercase: Boolean): Short {
|
||||||
return text.map{
|
val screencode = if(lowercase) encodingScreencodeLowercase[chr] else encodingScreencodeUppercase[chr]
|
||||||
val screencode = lookup[it]
|
return screencode?.toShort() ?: when (chr) {
|
||||||
screencode?.toShort() ?: when (it) {
|
|
||||||
'\u0000' -> 0.toShort()
|
'\u0000' -> 0.toShort()
|
||||||
in '\u8000'..'\u80ff' -> {
|
in '\u8000'..'\u80ff' -> {
|
||||||
// special case: take the lower 8 bit hex value directly
|
// special case: take the lower 8 bit hex value directly
|
||||||
(it.toInt() - 0x8000).toShort()
|
(chr.toInt() - 0x8000).toShort()
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val case = if (lowercase) "lower" else "upper"
|
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 {
|
fun decodeScreencode(screencode: Iterable<Short>, lowercase: Boolean = false): String {
|
||||||
val decodeTable = if(lowercase) decodingScreencodeLowercase else decodingScreencodeUppercase
|
return screencode.map {
|
||||||
return screencode.map { decodeTable[it.toInt()] }.joinToString("")
|
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 {
|
fun petscii2scr(petscii_code: Short, inverseVideo: Boolean): Short {
|
||||||
|
@ -10,11 +10,9 @@ import prog8.compiler.functions.BuiltinFunctions
|
|||||||
import prog8.compiler.functions.FSignature
|
import prog8.compiler.functions.FSignature
|
||||||
import prog8.compiler.target.*
|
import prog8.compiler.target.*
|
||||||
import prog8.compiler.target.cbm.AssemblyProgram
|
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.AsmAssignment
|
||||||
import prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen
|
import prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen
|
||||||
import prog8.optimizer.CallGraph
|
import prog8.optimizer.CallGraph
|
||||||
import java.io.CharConversionException
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@ -257,15 +255,6 @@ internal class AsmGen(private val program: Program,
|
|||||||
} else assemblyLines.add(fragment)
|
} 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>) {
|
private fun zeropagevars2asm(statements: List<Statement>) {
|
||||||
out("; vars allocated on zeropage")
|
out("; vars allocated on zeropage")
|
||||||
val variables = statements.filterIsInstance<VarDecl>().filter { it.type==VarDeclType.VAR }
|
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.STRUCT -> {} // is flattened
|
||||||
DataType.STR -> {
|
DataType.STR -> {
|
||||||
val str = decl.value as StringLiteralValue
|
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 -> {
|
DataType.ARRAY_UB -> {
|
||||||
val data = makeArrayFillDataUnsigned(decl)
|
val data = makeArrayFillDataUnsigned(decl)
|
||||||
@ -401,7 +390,7 @@ internal class AsmGen(private val program: Program,
|
|||||||
.filter {it.datatype == DataType.STR }
|
.filter {it.datatype == DataType.STR }
|
||||||
.map {
|
.map {
|
||||||
val str = it.value as StringLiteralValue
|
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})
|
.groupBy({it.second}, {it.first})
|
||||||
for((encoded, variables) in encodedstringVars) {
|
for((encoded, variables) in encodedstringVars) {
|
||||||
|
@ -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)))
|
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("\uf11a", true), equalTo(listOf<Short>(0x12))) // reverse vid
|
||||||
assertThat(Petscii.encodePetscii("✓", true), equalTo(listOf<Short>(0xfa)))
|
assertThat(Petscii.encodePetscii("✓", true), equalTo(listOf<Short>(0xfa)))
|
||||||
assertFailsWith<CharConversionException> { Petscii.encodePetscii("π", true) }
|
assertThat("expect lowercase error fallback", Petscii.encodePetscii("π", true), equalTo(listOf<Short>(255)))
|
||||||
assertFailsWith<CharConversionException> { Petscii.encodePetscii("♥", true) }
|
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"))
|
assertThat(Petscii.decodePetscii(listOf(72, 0xd7, 0x5c, 0xfa, 0x12), true), equalTo("hW£✓\uF11A"))
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodePetscii(listOf(-1), true) }
|
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("\uf11a"), equalTo(listOf<Short>(0x12))) // reverse vid
|
||||||
assertThat(Petscii.encodePetscii("♥"), equalTo(listOf<Short>(0xd3)))
|
assertThat(Petscii.encodePetscii("♥"), equalTo(listOf<Short>(0xd3)))
|
||||||
assertThat(Petscii.encodePetscii("π"), equalTo(listOf<Short>(0xff)))
|
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£♥π"))
|
assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π"))
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodePetscii(listOf(-1)) }
|
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)
|
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)))
|
assertThat(Petscii.encodeScreencode("✓", true), equalTo(listOf<Short>(0x7a)))
|
||||||
assertFailsWith<CharConversionException> { Petscii.encodeScreencode("♥", true) }
|
assertThat("expect fallback", Petscii.encodeScreencode("♥", true), equalTo(listOf<Short>(83)))
|
||||||
assertFailsWith<CharConversionException> { Petscii.encodeScreencode("π", true) }
|
assertThat("expect fallback", Petscii.encodeScreencode("π", true), equalTo(listOf<Short>(94)))
|
||||||
|
|
||||||
assertThat(Petscii.decodeScreencode(listOf(0x08, 0x57, 0x1c, 0x7a), true), equalTo("hW£✓"))
|
assertThat(Petscii.decodeScreencode(listOf(0x08, 0x57, 0x1c, 0x7a), true), equalTo("hW£✓"))
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodeScreencode(listOf(-1), true) }
|
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)))
|
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>(0x53)))
|
||||||
assertThat(Petscii.encodeScreencode("π"), equalTo(listOf<Short>(0x5e)))
|
assertThat(Petscii.encodeScreencode("π"), equalTo(listOf<Short>(0x5e)))
|
||||||
assertFailsWith<CharConversionException> { Petscii.encodeScreencode("✓") }
|
assertThat(Petscii.encodeScreencode("HELLO"), equalTo(listOf<Short>(8, 5, 12, 12, 15)))
|
||||||
assertFailsWith<CharConversionException> { Petscii.encodeScreencode("hello") }
|
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£♥π"))
|
assertThat(Petscii.decodeScreencode(listOf(0x17, 0x1c, 0x53, 0x5e)), equalTo("W£♥π"))
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodeScreencode(listOf(-1)) }
|
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodeScreencode(listOf(-1)) }
|
||||||
|
@ -206,7 +206,7 @@ waitkey:
|
|||||||
num_lines++
|
num_lines++
|
||||||
ubyte x
|
ubyte x
|
||||||
for x in boardOffsetX to boardOffsetX+boardWidth-1
|
for x in boardOffsetX to boardOffsetX+boardWidth-1
|
||||||
txt.setcc(x, linepos, 160, 1)
|
txt.setcc(x, linepos, @'▒', 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if num_lines {
|
if num_lines {
|
||||||
@ -338,7 +338,7 @@ waitkey:
|
|||||||
for i in len(colors)-1 downto 0 {
|
for i in len(colors)-1 downto 0 {
|
||||||
ubyte x
|
ubyte x
|
||||||
for x in 5 downto 0 {
|
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()
|
drawScore()
|
||||||
|
@ -3,13 +3,11 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte lives=2
|
txt.print("✓✓✓✓✓")
|
||||||
ubyte lvs
|
txt.nl()
|
||||||
|
txt.print("WWWWW")
|
||||||
for lvs in 10 to lives {
|
txt.nl()
|
||||||
txt.print_ub(lvs)
|
txt.print("●●●●●")
|
||||||
txt.spc()
|
|
||||||
}
|
|
||||||
txt.nl()
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user