From cc73d90d6e3fbcac6b0cc5252f92929f2fac6ff9 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 31 Aug 2018 18:32:33 +0200 Subject: [PATCH] cbm charset codecs, name checking --- il65/examples/imported2.ill | 6 + il65/examples/test.ill | 1 - il65/src/il65/Main.kt | 4 +- il65/src/il65/ast/AST.kt | 49 +- il65/src/il65/ast/AstChecker.kt | 79 +- il65/src/il65/ast/AstIdentifiersChecker.kt | 84 ++ il65/src/il65/compiler/Petscii.kt | 1083 +++++++++++++++++ .../il65/optimizing/ExpressionOptimizer.kt | 2 +- .../il65/optimizing/StatementsOptimizer.kt | 2 +- il65/test/UnitTests.kt | 61 + 10 files changed, 1280 insertions(+), 91 deletions(-) create mode 100644 il65/src/il65/ast/AstIdentifiersChecker.kt create mode 100644 il65/src/il65/compiler/Petscii.kt diff --git a/il65/examples/imported2.ill b/il65/examples/imported2.ill index 5d62a8795..495074080 100644 --- a/il65/examples/imported2.ill +++ b/il65/examples/imported2.ill @@ -13,6 +13,12 @@ X = 42 return 44 + + sub foo() -> () { + A=99 + return + } + } diff --git a/il65/examples/test.ill b/il65/examples/test.ill index c5414b52c..e70b012ce 100644 --- a/il65/examples/test.ill +++ b/il65/examples/test.ill @@ -84,7 +84,6 @@ cool: } - some_label_def: A=44 return 1+999 %breakpoint diff --git a/il65/src/il65/Main.kt b/il65/src/il65/Main.kt index 76f78b216..0e0783daf 100644 --- a/il65/src/il65/Main.kt +++ b/il65/src/il65/Main.kt @@ -18,12 +18,14 @@ fun main(args: Array) { val moduleAst = importModule(filepath) moduleAst.linkParents() val globalNamespace = moduleAst.namespace() - // globalNamespace.debugPrint() + //globalNamespace.debugPrint() + moduleAst.checkIdentifiers(globalNamespace) moduleAst.optimizeExpressions(globalNamespace) moduleAst.optimizeStatements(globalNamespace) val globalNamespaceAfterOptimize = moduleAst.namespace() // it could have changed in the meantime moduleAst.checkValid(globalNamespaceAfterOptimize) // check if final tree is valid + val allScopedSymbolDefinitions = moduleAst.checkIdentifiers(globalNamespace) // determine special compiler options val options = moduleAst.statements.filter { it is Directive && it.directive=="%option" }.flatMap { (it as Directive).args }.toSet() diff --git a/il65/src/il65/ast/AST.kt b/il65/src/il65/ast/AST.kt index 6d191c682..353e0d380 100644 --- a/il65/src/il65/ast/AST.kt +++ b/il65/src/il65/ast/AST.kt @@ -38,13 +38,20 @@ class FatalAstException (override var message: String) : Exception(message) open class AstException (override var message: String) : Exception(message) -open class SyntaxError(override var message: String, val position: Position?) : AstException(message) { +class SyntaxError(override var message: String, val position: Position?) : AstException(message) { override fun toString(): String { val location = position?.toString() ?: "" return "$location Syntax error: $message" } } +class NameError(override var message: String, val position: Position?) : AstException(message) { + override fun toString(): String { + val location = position?.toString() ?: "" + return "$location Name error: $message" + } +} + class ExpressionException(message: String, val position: Position?) : AstException(message) { override fun toString(): String { val location = position?.toString() ?: "" @@ -95,7 +102,7 @@ interface IAstProcessor { functionCall.arglist = functionCall.arglist.map { it.process(this) } return functionCall } - fun process(identifier: Identifier): IExpression { + fun process(identifier: IdentifierReference): IExpression { return identifier } fun process(jump: Jump): IStatement { @@ -114,6 +121,10 @@ interface IAstProcessor { range.to = range.to.process(this) return range } + + fun process(label: Label): IStatement { + return label + } } @@ -126,11 +137,23 @@ interface Node { interface IStatement : Node { fun process(processor: IAstProcessor) : IStatement + fun scopedName(name: String): String { + val scope = mutableListOf() + var statementScope = this.parent + while(statementScope!=null && statementScope !is Module) { + if(statementScope is INameScope) { + scope.add(0, statementScope.name) + } + statementScope = statementScope.parent + } + scope.add(name) + return scope.joinToString(".") + } } interface IFunctionCall { - var target: Identifier + var target: IdentifierReference var arglist: List } @@ -289,7 +312,7 @@ data class Label(val name: String) : IStatement { this.parent = parent } - override fun process(processor: IAstProcessor) = this + override fun process(processor: IAstProcessor) = processor.process(this) } @@ -377,7 +400,7 @@ data class Assignment(var target: AssignTarget, val aug_op : String?, var value: } } -data class AssignTarget(val register: Register?, val identifier: Identifier?) : Node { +data class AssignTarget(val register: Register?, val identifier: IdentifierReference?) : Node { override var position: Position? = null override var parent: Node? = null @@ -510,7 +533,7 @@ data class RegisterExpr(val register: Register) : IExpression { } -data class Identifier(val scopedName: List) : IExpression { +data class IdentifierReference(val scopedName: List) : IExpression { override var position: Position? = null override var parent: Node? = null @@ -552,7 +575,7 @@ data class PostIncrDecr(var target: AssignTarget, val operator: String) : IState } -data class Jump(val address: Int?, val identifier: Identifier?) : IStatement { +data class Jump(val address: Int?, val identifier: IdentifierReference?) : IStatement { override var position: Position? = null override var parent: Node? = null @@ -565,7 +588,7 @@ data class Jump(val address: Int?, val identifier: Identifier?) : IStatement { } -data class FunctionCall(override var target: Identifier, override var arglist: List) : IExpression, IFunctionCall { +data class FunctionCall(override var target: IdentifierReference, override var arglist: List) : IExpression, IFunctionCall { override var position: Position? = null override var parent: Node? = null @@ -603,7 +626,7 @@ data class FunctionCall(override var target: Identifier, override var arglist: L } -data class FunctionCallStatement(override var target: Identifier, override var arglist: List) : IStatement, IFunctionCall { +data class FunctionCallStatement(override var target: IdentifierReference, override var arglist: List) : IStatement, IFunctionCall { override var position: Position? = null override var parent: Node? = null @@ -1029,15 +1052,15 @@ private fun il65Parser.ExpressionContext.toAst(withPosition: Boolean) : IExpress private fun il65Parser.Expression_listContext.toAst(withPosition: Boolean) = expression().map{ it.toAst(withPosition) } -private fun il65Parser.IdentifierContext.toAst(withPosition: Boolean) : Identifier { - val ident = Identifier(listOf(text)) +private fun il65Parser.IdentifierContext.toAst(withPosition: Boolean) : IdentifierReference { + val ident = IdentifierReference(listOf(text)) ident.position = toPosition(withPosition) return ident } -private fun il65Parser.Scoped_identifierContext.toAst(withPosition: Boolean) : Identifier { - val ident = Identifier(NAME().map { it.text }) +private fun il65Parser.Scoped_identifierContext.toAst(withPosition: Boolean) : IdentifierReference { + val ident = IdentifierReference(NAME().map { it.text }) ident.position = toPosition(withPosition) return ident } diff --git a/il65/src/il65/ast/AstChecker.kt b/il65/src/il65/ast/AstChecker.kt index 9d6773c69..f0e04c2bc 100644 --- a/il65/src/il65/ast/AstChecker.kt +++ b/il65/src/il65/ast/AstChecker.kt @@ -27,7 +27,6 @@ fun Module.checkValid(globalNamespace: INameScope) { class AstChecker(private val globalNamespace: INameScope) : IAstProcessor { private val checkResult: MutableList = mutableListOf() - private val blockNames: HashMap = hashMapOf() fun result(): List { return checkResult @@ -36,10 +35,10 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor { override fun process(module: Module) { super.process(module) val directives = module.statements.filter { it is Directive }.groupBy { (it as Directive).directive } - directives.filter { it.value.size > 1 }.forEach{ - when(it.key) { + directives.filter { it.value.size > 1 }.forEach{ entry -> + when(entry.key) { "%output", "%launcher", "%zeropage", "%address" -> - it.value.mapTo(checkResult) { SyntaxError("directive can just occur once", it.position) } + entry.value.mapTo(checkResult) { SyntaxError("directive can just occur once", it.position) } } } } @@ -55,51 +54,7 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor { if(block.address!=null && (block.address<0 || block.address>65535)) { checkResult.add(SyntaxError("block memory address must be valid integer 0..\$ffff", block.position)) } - val existing = blockNames[block.name] - if(existing!=null) { - checkResult.add(SyntaxError("block name conflict, first defined in ${existing.file} line ${existing.line}", block.position)) - } else { - blockNames[block.name] = block.position - } - super.process(block) - - // check if labels are unique - val labels = block.statements.filter { it is Label }.map { it as Label } - val labelnames = mutableMapOf() - labels.forEach { - val existing = labelnames[it.name] - if(existing!=null) { - checkResult.add(SyntaxError("label name conflict, first defined on line ${existing.line}", it.position)) - } else { - labelnames[it.name] = it.position - } - } - - // check if var names are unique - val variables = block.statements.filter { it is VarDecl }.map{ it as VarDecl } - val varnames= mutableMapOf() - variables.forEach { - val existing = varnames[it.name] - if(existing!=null) { - checkResult.add(SyntaxError("variable name conflict, first defined on line ${existing.line}", it.position)) - } else { - varnames[it.name] = it.position - } - } - - // check if subroutine names are unique - val subroutines = block.statements.filter { it is Subroutine }.map{ it as Subroutine } - val subnames = mutableMapOf() - subroutines.forEach { - val existing = subnames[it.name] - if(existing!=null) { - checkResult.add(SyntaxError("subroutine name conflict, first defined on line ${existing.line}", it.position)) - } else { - subnames[it.name] = it.position - } - } - return block } @@ -130,30 +85,6 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor { super.process(subroutine) - // check if labels are unique - val labels = subroutine.statements.filter { it is Label }.map { it as Label } - val labelnames = mutableMapOf() - labels.forEach { - val existing = labelnames[it.name] - if(existing!=null) { - checkResult.add(SyntaxError("label name conflict, first defined on line ${existing.line}", it.position)) - } else { - labelnames[it.name] = it.position - } - } - - // check if var names are unique - val variables = subroutine.statements.filter { it is VarDecl }.map{ it as VarDecl } - val varnames= mutableMapOf() - variables.forEach { - val existing = varnames[it.name] - if(existing!=null) { - checkResult.add(SyntaxError("variable name conflict, first defined on line ${existing.line}", it.position)) - } else { - varnames[it.name] = it.position - } - } - // subroutine must contain at least one 'return' or 'goto' // (or if it has an asm block, that must contain a 'rts' or 'jmp') if(subroutine.statements.count { it is Return || it is Jump } == 0) { @@ -165,7 +96,7 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor { it.contains(" jmp") || it.contains("\tjmp")} if(amount==0 ) err("subroutine must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)") - } + } } return subroutine @@ -377,7 +308,7 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor { return super.process(functionCall) } - private fun checkFunctionExists(target: Identifier, statement: IStatement) { + private fun checkFunctionExists(target: IdentifierReference, statement: IStatement) { if(globalNamespace.lookup(target.scopedName, statement)==null) checkResult.add(SyntaxError("undefined function or subroutine: ${target.scopedName.joinToString(".")}", statement.position)) } diff --git a/il65/src/il65/ast/AstIdentifiersChecker.kt b/il65/src/il65/ast/AstIdentifiersChecker.kt new file mode 100644 index 000000000..f33465ff5 --- /dev/null +++ b/il65/src/il65/ast/AstIdentifiersChecker.kt @@ -0,0 +1,84 @@ +package il65.ast + +import il65.parser.ParsingFailedError + +/** + * Checks the validity of all identifiers (no conflicts) + * Also builds a list of all (scoped) symbol definitions + */ + +fun Module.checkIdentifiers(globalNamespace: INameScope): MutableMap { + val checker = AstIdentifiersChecker(globalNamespace) + this.process(checker) + val checkResult = checker.result() + checkResult.forEach { + System.err.println(it) + } + if(checkResult.isNotEmpty()) + throw ParsingFailedError("There are ${checkResult.size} errors in module '$name'.") + return checker.symbols +} + + +class AstIdentifiersChecker(private val globalNamespace: INameScope) : IAstProcessor { + private val checkResult: MutableList = mutableListOf() + + var symbols: MutableMap = mutableMapOf() + private set + + fun result(): List { + return checkResult + } + + private fun nameError(name: String, position: Position?, existing: IStatement) { + checkResult.add(NameError("name conflict '$name', first defined in ${existing.position?.file} line ${existing.position?.line}", position)) + } + + override fun process(block: Block): IStatement { + val scopedName = block.scopedName(block.name) + val existing = symbols[scopedName] + if(existing!=null) { + nameError(block.name, block.position, existing) + } else { + symbols[scopedName] = block + } + super.process(block) + return block + } + + override fun process(decl: VarDecl): IStatement { + val scopedName = decl.scopedName(decl.name) + val existing = symbols[scopedName] + if(existing!=null) { + nameError(decl.name, decl.position, existing) + } else { + symbols[scopedName] = decl + } + super.process(decl) + return decl + } + + override fun process(subroutine: Subroutine): IStatement { + val scopedName = subroutine.scopedName(subroutine.name) + val existing = symbols[scopedName] + if(existing!=null) { + nameError(subroutine.name, subroutine.position, existing) + } else { + symbols[scopedName] = subroutine + } + super.process(subroutine) + return subroutine + } + + override fun process(label: Label): IStatement { + val scopedName = label.scopedName(label.name) + val existing = symbols[scopedName] + if(existing!=null) { + nameError(label.name, label.position, existing) + } else { + symbols[scopedName] = label + } + super.process(label) + return label + } +} diff --git a/il65/src/il65/compiler/Petscii.kt b/il65/src/il65/compiler/Petscii.kt new file mode 100644 index 000000000..d124cde01 --- /dev/null +++ b/il65/src/il65/compiler/Petscii.kt @@ -0,0 +1,1083 @@ +package il65.compiler + +class Petscii { + companion object { + + // decoding: from Petscii/Screencodes (0-255) to unicode + // character tables used from https://github.com/dj51d/cbmcodecs + + private val decodingPetsciiLowercase = arrayOf( + '\ufffe', // 0x00 -> UNDEFINED + '\ufffe', // 0x01 -> UNDEFINED + '\ufffe', // 0x02 -> UNDEFINED + '\ufffe', // 0x03 -> UNDEFINED + '\ufffe', // 0x04 -> UNDEFINED + '\uf100', // 0x05 -> WHITE COLOR SWITCH (CUS) + '\ufffe', // 0x06 -> UNDEFINED + '\ufffe', // 0x07 -> UNDEFINED + '\uf118', // 0x08 -> DISABLE CHARACTER SET SWITCHING (CUS) + '\uf119', // 0x09 -> ENABLE CHARACTER SET SWITCHING (CUS) + '\ufffe', // 0x0A -> UNDEFINED + '\ufffe', // 0x0B -> UNDEFINED + '\ufffe', // 0x0C -> UNDEFINED + '\r' , // 0x0D -> CARRIAGE RETURN + '\u000e', // 0x0E -> SHIFT OUT + '\ufffe', // 0x0F -> UNDEFINED + '\ufffe', // 0x10 -> UNDEFINED + '\uf11c', // 0x11 -> CURSOR DOWN (CUS) + '\uf11a', // 0x12 -> REVERSE VIDEO ON (CUS) + '\uf120', // 0x13 -> HOME (CUS) + '\u007f', // 0x14 -> DELETE + '\ufffe', // 0x15 -> UNDEFINED + '\ufffe', // 0x16 -> UNDEFINED + '\ufffe', // 0x17 -> UNDEFINED + '\ufffe', // 0x18 -> UNDEFINED + '\ufffe', // 0x19 -> UNDEFINED + '\ufffe', // 0x1A -> UNDEFINED + '\ufffe', // 0x1B -> UNDEFINED + '\uf101', // 0x1C -> RED COLOR SWITCH (CUS) + '\uf11d', // 0x1D -> CURSOR RIGHT (CUS) + '\uf102', // 0x1E -> GREEN COLOR SWITCH (CUS) + '\uf103', // 0x1F -> BLUE COLOR SWITCH (CUS) + ' ' , // 0x20 -> SPACE + '!' , // 0x21 -> EXCLAMATION MARK + '"' , // 0x22 -> QUOTATION MARK + '#' , // 0x23 -> NUMBER SIGN + '$' , // 0x24 -> DOLLAR SIGN + '%' , // 0x25 -> PERCENT SIGN + '&' , // 0x26 -> AMPERSAND + '\'' , // 0x27 -> APOSTROPHE + '(' , // 0x28 -> LEFT PARENTHESIS + ')' , // 0x29 -> RIGHT PARENTHESIS + '*' , // 0x2A -> ASTERISK + '+' , // 0x2B -> PLUS SIGN + ',' , // 0x2C -> COMMA + '-' , // 0x2D -> HYPHEN-MINUS + '.' , // 0x2E -> FULL STOP + '/' , // 0x2F -> SOLIDUS + '0' , // 0x30 -> DIGIT ZERO + '1' , // 0x31 -> DIGIT ONE + '2' , // 0x32 -> DIGIT TWO + '3' , // 0x33 -> DIGIT THREE + '4' , // 0x34 -> DIGIT FOUR + '5' , // 0x35 -> DIGIT FIVE + '6' , // 0x36 -> DIGIT SIX + '7' , // 0x37 -> DIGIT SEVEN + '8' , // 0x38 -> DIGIT EIGHT + '9' , // 0x39 -> DIGIT NINE + ':' , // 0x3A -> COLON + ';' , // 0x3B -> SEMICOLON + '<' , // 0x3C -> LESS-THAN SIGN + '=' , // 0x3D -> EQUALS SIGN + '>' , // 0x3E -> GREATER-THAN SIGN + '?' , // 0x3F -> QUESTION MARK + '@' , // 0x40 -> COMMERCIAL AT + 'a' , // 0x41 -> LATIN SMALL LETTER A + 'b' , // 0x42 -> LATIN SMALL LETTER B + 'c' , // 0x43 -> LATIN SMALL LETTER C + 'd' , // 0x44 -> LATIN SMALL LETTER D + 'e' , // 0x45 -> LATIN SMALL LETTER E + 'f' , // 0x46 -> LATIN SMALL LETTER F + 'g' , // 0x47 -> LATIN SMALL LETTER G + 'h' , // 0x48 -> LATIN SMALL LETTER H + 'i' , // 0x49 -> LATIN SMALL LETTER I + 'j' , // 0x4A -> LATIN SMALL LETTER J + 'k' , // 0x4B -> LATIN SMALL LETTER K + 'l' , // 0x4C -> LATIN SMALL LETTER L + 'm' , // 0x4D -> LATIN SMALL LETTER M + 'n' , // 0x4E -> LATIN SMALL LETTER N + 'o' , // 0x4F -> LATIN SMALL LETTER O + 'p' , // 0x50 -> LATIN SMALL LETTER P + 'q' , // 0x51 -> LATIN SMALL LETTER Q + 'r' , // 0x52 -> LATIN SMALL LETTER R + 's' , // 0x53 -> LATIN SMALL LETTER S + 't' , // 0x54 -> LATIN SMALL LETTER T + 'u' , // 0x55 -> LATIN SMALL LETTER U + 'v' , // 0x56 -> LATIN SMALL LETTER V + 'w' , // 0x57 -> LATIN SMALL LETTER W + 'x' , // 0x58 -> LATIN SMALL LETTER X + 'y' , // 0x59 -> LATIN SMALL LETTER Y + 'z' , // 0x5A -> LATIN SMALL LETTER Z + '[' , // 0x5B -> LEFT SQUARE BRACKET + '\u00a3', // 0x5C -> POUND SIGN + ']' , // 0x5D -> RIGHT SQUARE BRACKET + '\u2191', // 0x5E -> UPWARDS ARROW + '\u2190', // 0x5F -> LEFTWARDS ARROW + '\u2500', // 0x60 -> BOX DRAWINGS LIGHT HORIZONTAL + 'A' , // 0x61 -> LATIN CAPITAL LETTER A + 'B' , // 0x62 -> LATIN CAPITAL LETTER B + 'C' , // 0x63 -> LATIN CAPITAL LETTER C + 'D' , // 0x64 -> LATIN CAPITAL LETTER D + 'E' , // 0x65 -> LATIN CAPITAL LETTER E + 'F' , // 0x66 -> LATIN CAPITAL LETTER F + 'G' , // 0x67 -> LATIN CAPITAL LETTER G + 'H' , // 0x68 -> LATIN CAPITAL LETTER H + 'I' , // 0x69 -> LATIN CAPITAL LETTER I + 'J' , // 0x6A -> LATIN CAPITAL LETTER J + 'K' , // 0x6B -> LATIN CAPITAL LETTER K + 'L' , // 0x6C -> LATIN CAPITAL LETTER L + 'M' , // 0x6D -> LATIN CAPITAL LETTER M + 'N' , // 0x6E -> LATIN CAPITAL LETTER N + 'O' , // 0x6F -> LATIN CAPITAL LETTER O + 'P' , // 0x70 -> LATIN CAPITAL LETTER P + 'Q' , // 0x71 -> LATIN CAPITAL LETTER Q + 'R' , // 0x72 -> LATIN CAPITAL LETTER R + 'S' , // 0x73 -> LATIN CAPITAL LETTER S + 'T' , // 0x74 -> LATIN CAPITAL LETTER T + 'U' , // 0x75 -> LATIN CAPITAL LETTER U + 'V' , // 0x76 -> LATIN CAPITAL LETTER V + 'W' , // 0x77 -> LATIN CAPITAL LETTER W + 'X' , // 0x78 -> LATIN CAPITAL LETTER X + 'Y' , // 0x79 -> LATIN CAPITAL LETTER Y + 'Z' , // 0x7A -> LATIN CAPITAL LETTER Z + '\u253c', // 0x7B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', // 0x7C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // 0x7D -> BOX DRAWINGS LIGHT VERTICAL + '\u2592', // 0x7E -> MEDIUM SHADE + '\uf139', // 0x7F -> MEDIUM SHADE SLASHED LEFT (CUS) + '\ufffe', // 0x80 -> UNDEFINED + '\uf104', // 0x81 -> ORANGE COLOR SWITCH (CUS) + '\ufffe', // 0x82 -> UNDEFINED + '\ufffe', // 0x83 -> UNDEFINED + '\ufffe', // 0x84 -> UNDEFINED + '\uf110', // 0x85 -> FUNCTION KEY 1 (CUS) + '\uf112', // 0x86 -> FUNCTION KEY 3 (CUS) + '\uf114', // 0x87 -> FUNCTION KEY 5 (CUS) + '\uf116', // 0x88 -> FUNCTION KEY 7 (CUS) + '\uf111', // 0x89 -> FUNCTION KEY 2 (CUS) + '\uf113', // 0x8A -> FUNCTION KEY 4 (CUS) + '\uf115', // 0x8B -> FUNCTION KEY 6 (CUS) + '\uf117', // 0x8C -> FUNCTION KEY 8 (CUS) + '\n' , // 0x8D -> LINE FEED + '\u000f', // 0x8E -> SHIFT IN + '\ufffe', // 0x8F -> UNDEFINED + '\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS) + '\uf11e', // 0x91 -> CURSOR UP (CUS) + '\uf11b', // 0x92 -> REVERSE VIDEO OFF (CUS) + '\u000c', // 0x93 -> FORM FEED + '\uf121', // 0x94 -> INSERT (CUS) + '\uf106', // 0x95 -> BROWN COLOR SWITCH (CUS) + '\uf107', // 0x96 -> LIGHT RED COLOR SWITCH (CUS) + '\uf108', // 0x97 -> GRAY 1 COLOR SWITCH (CUS) + '\uf109', // 0x98 -> GRAY 2 COLOR SWITCH (CUS) + '\uf10a', // 0x99 -> LIGHT GREEN COLOR SWITCH (CUS) + '\uf10b', // 0x9A -> LIGHT BLUE COLOR SWITCH (CUS) + '\uf10c', // 0x9B -> GRAY 3 COLOR SWITCH (CUS) + '\uf10d', // 0x9C -> PURPLE COLOR SWITCH (CUS) + '\uf11d', // 0x9D -> CURSOR LEFT (CUS) + '\uf10e', // 0x9E -> YELLOW COLOR SWITCH (CUS) + '\uf10f', // 0x9F -> CYAN COLOR SWITCH (CUS) + '\u00a0', // 0xA0 -> NO-BREAK SPACE + '\u258c', // 0xA1 -> LEFT HALF BLOCK + '\u2584', // 0xA2 -> LOWER HALF BLOCK + '\u2594', // 0xA3 -> UPPER ONE EIGHTH BLOCK + '\u2581', // 0xA4 -> LOWER ONE EIGHTH BLOCK + '\u258f', // 0xA5 -> LEFT ONE EIGHTH BLOCK + '\u2592', // 0xA6 -> MEDIUM SHADE + '\u2595', // 0xA7 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', // 0xA8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\uf13a', // 0xA9 -> MEDIUM SHADE SLASHED RIGHT (CUS) + '\uf130', // 0xAA -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // 0xAB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // 0xAC -> QUADRANT LOWER RIGHT + '\u2514', // 0xAD -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // 0xAE -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // 0xAF -> LOWER ONE QUARTER BLOCK + '\u250c', // 0xB0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // 0xB1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // 0xB2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // 0xB3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // 0xB4 -> LEFT ONE QUARTER BLOCK + '\u258d', // 0xB5 -> LEFT THREE EIGTHS BLOCK + '\uf131', // 0xB6 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', // 0xB7 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', // 0xB8 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // 0xB9 -> LOWER THREE EIGHTHS BLOCK + '\u2713', // 0xBA -> CHECK MARK + '\u2596', // 0xBB -> QUADRANT LOWER LEFT + '\u259d', // 0xBC -> QUADRANT UPPER RIGHT + '\u2518', // 0xBD -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // 0xBE -> QUADRANT UPPER LEFT + '\u259a', // 0xBF -> QUADRANT UPPER LEFT AND LOWER RIGHT + '\u2500', // 0xC0 -> BOX DRAWINGS LIGHT HORIZONTAL + 'A' , // 0xC1 -> LATIN CAPITAL LETTER A + 'B' , // 0xC2 -> LATIN CAPITAL LETTER B + 'C' , // 0xC3 -> LATIN CAPITAL LETTER C + 'D' , // 0xC4 -> LATIN CAPITAL LETTER D + 'E' , // 0xC5 -> LATIN CAPITAL LETTER E + 'F' , // 0xC6 -> LATIN CAPITAL LETTER F + 'G' , // 0xC7 -> LATIN CAPITAL LETTER G + 'H' , // 0xC8 -> LATIN CAPITAL LETTER H + 'I' , // 0xC9 -> LATIN CAPITAL LETTER I + 'J' , // 0xCA -> LATIN CAPITAL LETTER J + 'K' , // 0xCB -> LATIN CAPITAL LETTER K + 'L' , // 0xCC -> LATIN CAPITAL LETTER L + 'M' , // 0xCD -> LATIN CAPITAL LETTER M + 'N' , // 0xCE -> LATIN CAPITAL LETTER N + 'O' , // 0xCF -> LATIN CAPITAL LETTER O + 'P' , // 0xD0 -> LATIN CAPITAL LETTER P + 'Q' , // 0xD1 -> LATIN CAPITAL LETTER Q + 'R' , // 0xD2 -> LATIN CAPITAL LETTER R + 'S' , // 0xD3 -> LATIN CAPITAL LETTER S + 'T' , // 0xD4 -> LATIN CAPITAL LETTER T + 'U' , // 0xD5 -> LATIN CAPITAL LETTER U + 'V' , // 0xD6 -> LATIN CAPITAL LETTER V + 'W' , // 0xD7 -> LATIN CAPITAL LETTER W + 'X' , // 0xD8 -> LATIN CAPITAL LETTER X + 'Y' , // 0xD9 -> LATIN CAPITAL LETTER Y + 'Z' , // 0xDA -> LATIN CAPITAL LETTER Z + '\u253c', // 0xDB -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', // 0xDC -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // 0xDD -> BOX DRAWINGS LIGHT VERTICAL + '\u2592', // 0xDE -> MEDIUM SHADE + '\uf139', // 0xDF -> MEDIUM SHADE SLASHED LEFT (CUS) + '\u00a0', // 0xE0 -> NO-BREAK SPACE + '\u258c', // 0xE1 -> LEFT HALF BLOCK + '\u2584', // 0xE2 -> LOWER HALF BLOCK + '\u2594', // 0xE3 -> UPPER ONE EIGHTH BLOCK + '\u2581', // 0xE4 -> LOWER ONE EIGHTH BLOCK + '\u258f', // 0xE5 -> LEFT ONE EIGHTH BLOCK + '\u2592', // 0xE6 -> MEDIUM SHADE + '\u2595', // 0xE7 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', // 0xE8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\uf13a', // 0xE9 -> MEDIUM SHADE SLASHED RIGHT (CUS) + '\uf130', // 0xEA -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // 0xEB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // 0xEC -> QUADRANT LOWER RIGHT + '\u2514', // 0xED -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // 0xEE -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // 0xEF -> LOWER ONE QUARTER BLOCK + '\u250c', // 0xF0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // 0xF1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // 0xF2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // 0xF3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // 0xF4 -> LEFT ONE QUARTER BLOCK + '\u258d', // 0xF5 -> LEFT THREE EIGTHS BLOCK + '\uf131', // 0xF6 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', // 0xF7 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', // 0xF8 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // 0xF9 -> LOWER THREE EIGHTHS BLOCK + '\u2713', // 0xFA -> CHECK MARK + '\u2596', // 0xFB -> QUADRANT LOWER LEFT + '\u259d', // 0xFC -> QUADRANT UPPER RIGHT + '\u2518', // 0xFD -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // 0xFE -> QUADRANT UPPER LEFT + '\u2592' // 0xFF -> MEDIUM SHADE + ) + + private val decodingPetsciiUppercase = arrayOf( + '\ufffe', // 0x00 -> UNDEFINED + '\ufffe', // 0x01 -> UNDEFINED + '\ufffe', // 0x02 -> UNDEFINED + '\ufffe', // 0x03 -> UNDEFINED + '\ufffe', // 0x04 -> UNDEFINED + '\uf100', // 0x05 -> WHITE COLOR SWITCH (CUS) + '\ufffe', // 0x06 -> UNDEFINED + '\ufffe', // 0x07 -> UNDEFINED + '\uf118', // 0x08 -> DISABLE CHARACTER SET SWITCHING (CUS) + '\uf119', // 0x09 -> ENABLE CHARACTER SET SWITCHING (CUS) + '\ufffe', // 0x0A -> UNDEFINED + '\ufffe', // 0x0B -> UNDEFINED + '\ufffe', // 0x0C -> UNDEFINED + '\r' , // 0x0D -> CARRIAGE RETURN + '\u000e', // 0x0E -> SHIFT OUT + '\ufffe', // 0x0F -> UNDEFINED + '\ufffe', // 0x10 -> UNDEFINED + '\uf11c', // 0x11 -> CURSOR DOWN (CUS) + '\uf11a', // 0x12 -> REVERSE VIDEO ON (CUS) + '\uf120', // 0x13 -> HOME (CUS) + '\u007f', // 0x14 -> DELETE + '\ufffe', // 0x15 -> UNDEFINED + '\ufffe', // 0x16 -> UNDEFINED + '\ufffe', // 0x17 -> UNDEFINED + '\ufffe', // 0x18 -> UNDEFINED + '\ufffe', // 0x19 -> UNDEFINED + '\ufffe', // 0x1A -> UNDEFINED + '\ufffe', // 0x1B -> UNDEFINED + '\uf101', // 0x1C -> RED COLOR SWITCH (CUS) + '\uf11d', // 0x1D -> CURSOR RIGHT (CUS) + '\uf102', // 0x1E -> GREEN COLOR SWITCH (CUS) + '\uf103', // 0x1F -> BLUE COLOR SWITCH (CUS) + ' ' , // 0x20 -> SPACE + '!' , // 0x21 -> EXCLAMATION MARK + '"' , // 0x22 -> QUOTATION MARK + '#' , // 0x23 -> NUMBER SIGN + '$' , // 0x24 -> DOLLAR SIGN + '%' , // 0x25 -> PERCENT SIGN + '&' , // 0x26 -> AMPERSAND + '\'' , // 0x27 -> APOSTROPHE + '(' , // 0x28 -> LEFT PARENTHESIS + ')' , // 0x29 -> RIGHT PARENTHESIS + '*' , // 0x2A -> ASTERISK + '+' , // 0x2B -> PLUS SIGN + ',' , // 0x2C -> COMMA + '-' , // 0x2D -> HYPHEN-MINUS + '.' , // 0x2E -> FULL STOP + '/' , // 0x2F -> SOLIDUS + '0' , // 0x30 -> DIGIT ZERO + '1' , // 0x31 -> DIGIT ONE + '2' , // 0x32 -> DIGIT TWO + '3' , // 0x33 -> DIGIT THREE + '4' , // 0x34 -> DIGIT FOUR + '5' , // 0x35 -> DIGIT FIVE + '6' , // 0x36 -> DIGIT SIX + '7' , // 0x37 -> DIGIT SEVEN + '8' , // 0x38 -> DIGIT EIGHT + '9' , // 0x39 -> DIGIT NINE + ':' , // 0x3A -> COLON + ';' , // 0x3B -> SEMICOLON + '<' , // 0x3C -> LESS-THAN SIGN + '=' , // 0x3D -> EQUALS SIGN + '>' , // 0x3E -> GREATER-THAN SIGN + '?' , // 0x3F -> QUESTION MARK + '@' , // 0x40 -> COMMERCIAL AT + 'A' , // 0x41 -> LATIN CAPITAL LETTER A + 'B' , // 0x42 -> LATIN CAPITAL LETTER B + 'C' , // 0x43 -> LATIN CAPITAL LETTER C + 'D' , // 0x44 -> LATIN CAPITAL LETTER D + 'E' , // 0x45 -> LATIN CAPITAL LETTER E + 'F' , // 0x46 -> LATIN CAPITAL LETTER F + 'G' , // 0x47 -> LATIN CAPITAL LETTER G + 'H' , // 0x48 -> LATIN CAPITAL LETTER H + 'I' , // 0x49 -> LATIN CAPITAL LETTER I + 'J' , // 0x4A -> LATIN CAPITAL LETTER J + 'K' , // 0x4B -> LATIN CAPITAL LETTER K + 'L' , // 0x4C -> LATIN CAPITAL LETTER L + 'M' , // 0x4D -> LATIN CAPITAL LETTER M + 'N' , // 0x4E -> LATIN CAPITAL LETTER N + 'O' , // 0x4F -> LATIN CAPITAL LETTER O + 'P' , // 0x50 -> LATIN CAPITAL LETTER P + 'Q' , // 0x51 -> LATIN CAPITAL LETTER Q + 'R' , // 0x52 -> LATIN CAPITAL LETTER R + 'S' , // 0x53 -> LATIN CAPITAL LETTER S + 'T' , // 0x54 -> LATIN CAPITAL LETTER T + 'U' , // 0x55 -> LATIN CAPITAL LETTER U + 'V' , // 0x56 -> LATIN CAPITAL LETTER V + 'W' , // 0x57 -> LATIN CAPITAL LETTER W + 'X' , // 0x58 -> LATIN CAPITAL LETTER X + 'Y' , // 0x59 -> LATIN CAPITAL LETTER Y + 'Z' , // 0x5A -> LATIN CAPITAL LETTER Z + '[' , // 0x5B -> LEFT SQUARE BRACKET + '\u00a3', // 0x5C -> POUND SIGN + ']' , // 0x5D -> RIGHT SQUARE BRACKET + '\u2191', // 0x5E -> UPWARDS ARROW + '\u2190', // 0x5F -> LEFTWARDS ARROW + '\u2500', // 0x60 -> BOX DRAWINGS LIGHT HORIZONTAL + '\u2660', // 0x61 -> BLACK SPADE SUIT + '\u2502', // 0x62 -> BOX DRAWINGS LIGHT VERTICAL + '\u2500', // 0x63 -> BOX DRAWINGS LIGHT HORIZONTAL + '\uf122', // 0x64 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER UP (CUS) + '\uf123', // 0x65 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS UP (CUS) + '\uf124', // 0x66 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER DOWN (CUS) + '\uf126', // 0x67 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER LEFT (CUS) + '\uf128', // 0x68 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER RIGHT (CUS) + '\u256e', // 0x69 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT + '\u2570', // 0x6A -> BOX DRAWINGS LIGHT ARC UP AND RIGHT + '\u256f', // 0x6B -> BOX DRAWINGS LIGHT ARC UP AND LEFT + '\uf12a', // 0x6C -> ONE EIGHTH BLOCK UP AND RIGHT (CUS) + '\u2572', // 0x6D -> BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + '\u2571', // 0x6E -> BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + '\uf12b', // 0x6F -> ONE EIGHTH BLOCK DOWN AND RIGHT (CUS) + '\uf12c', // 0x70 -> ONE EIGHTH BLOCK DOWN AND LEFT (CUS) + '\u25cf', // 0x71 -> BLACK CIRCLE + '\uf125', // 0x72 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS DOWN (CUS) + '\u2665', // 0x73 -> BLACK HEART SUIT + '\uf127', // 0x74 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS LEFT (CUS) + '\u256d', // 0x75 -> BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + '\u2573', // 0x76 -> BOX DRAWINGS LIGHT DIAGONAL CROSS + '\u25cb', // 0x77 -> WHITE CIRCLE + '\u2663', // 0x78 -> BLACK CLUB SUIT + '\uf129', // 0x79 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS RIGHT (CUS) + '\u2666', // 0x7A -> BLACK DIAMOND SUIT + '\u253c', // 0x7B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', // 0x7C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // 0x7D -> BOX DRAWINGS LIGHT VERTICAL + '\u03c0', // 0x7E -> GREEK SMALL LETTER PI + '\u25e5', // 0x7F -> BLACK UPPER RIGHT TRIANGLE + '\ufffe', // 0x80 -> UNDEFINED + '\uf104', // 0x81 -> ORANGE COLOR SWITCH (CUS) + '\ufffe', // 0x82 -> UNDEFINED + '\ufffe', // 0x83 -> UNDEFINED + '\ufffe', // 0x84 -> UNDEFINED + '\uf110', // 0x85 -> FUNCTION KEY 1 (CUS) + '\uf112', // 0x86 -> FUNCTION KEY 3 (CUS) + '\uf114', // 0x87 -> FUNCTION KEY 5 (CUS) + '\uf116', // 0x88 -> FUNCTION KEY 7 (CUS) + '\uf111', // 0x89 -> FUNCTION KEY 2 (CUS) + '\uf113', // 0x8A -> FUNCTION KEY 4 (CUS) + '\uf115', // 0x8B -> FUNCTION KEY 6 (CUS) + '\uf117', // 0x8C -> FUNCTION KEY 8 (CUS) + '\n' , // 0x8D -> LINE FEED + '\u000f', // 0x8E -> SHIFT IN + '\ufffe', // 0x8F -> UNDEFINED + '\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS) + '\uf11e', // 0x91 -> CURSOR UP (CUS) + '\uf11b', // 0x92 -> REVERSE VIDEO OFF (CUS) + '\u000c', // 0x93 -> FORM FEED + '\uf121', // 0x94 -> INSERT (CUS) + '\uf106', // 0x95 -> BROWN COLOR SWITCH (CUS) + '\uf107', // 0x96 -> LIGHT RED COLOR SWITCH (CUS) + '\uf108', // 0x97 -> GRAY 1 COLOR SWITCH (CUS) + '\uf109', // 0x98 -> GRAY 2 COLOR SWITCH (CUS) + '\uf10a', // 0x99 -> LIGHT GREEN COLOR SWITCH (CUS) + '\uf10b', // 0x9A -> LIGHT BLUE COLOR SWITCH (CUS) + '\uf10c', // 0x9B -> GRAY 3 COLOR SWITCH (CUS) + '\uf10d', // 0x9C -> PURPLE COLOR SWITCH (CUS) + '\uf11d', // 0x9D -> CURSOR LEFT (CUS) + '\uf10e', // 0x9E -> YELLOW COLOR SWITCH (CUS) + '\uf10f', // 0x9F -> CYAN COLOR SWITCH (CUS) + '\u00a0', // 0xA0 -> NO-BREAK SPACE + '\u258c', // 0xA1 -> LEFT HALF BLOCK + '\u2584', // 0xA2 -> LOWER HALF BLOCK + '\u2594', // 0xA3 -> UPPER ONE EIGHTH BLOCK + '\u2581', // 0xA4 -> LOWER ONE EIGHTH BLOCK + '\u258f', // 0xA5 -> LEFT ONE EIGHTH BLOCK + '\u2592', // 0xA6 -> MEDIUM SHADE + '\u2595', // 0xA7 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', // 0xA8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\u25e4', // 0xA9 -> BLACK UPPER LEFT TRIANGLE + '\uf130', // 0xAA -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // 0xAB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // 0xAC -> QUADRANT LOWER RIGHT + '\u2514', // 0xAD -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // 0xAE -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // 0xAF -> LOWER ONE QUARTER BLOCK + '\u250c', // 0xB0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // 0xB1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // 0xB2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // 0xB3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // 0xB4 -> LEFT ONE QUARTER BLOCK + '\u258d', // 0xB5 -> LEFT THREE EIGTHS BLOCK + '\uf131', // 0xB6 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', // 0xB7 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', // 0xB8 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // 0xB9 -> LOWER THREE EIGHTHS BLOCK + '\uf12d', // 0xBA -> ONE EIGHTH BLOCK UP AND LEFT (CUS) + '\u2596', // 0xBB -> QUADRANT LOWER LEFT + '\u259d', // 0xBC -> QUADRANT UPPER RIGHT + '\u2518', // 0xBD -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // 0xBE -> QUADRANT UPPER LEFT + '\u259a', // 0xBF -> QUADRANT UPPER LEFT AND LOWER RIGHT + '\u2500', // 0xC0 -> BOX DRAWINGS LIGHT HORIZONTAL + '\u2660', // 0xC1 -> BLACK SPADE SUIT + '\u2502', // 0xC2 -> BOX DRAWINGS LIGHT VERTICAL + '\u2500', // 0xC3 -> BOX DRAWINGS LIGHT HORIZONTAL + '\uf122', // 0xC4 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER UP (CUS) + '\uf123', // 0xC5 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS UP (CUS) + '\uf124', // 0xC6 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER DOWN (CUS) + '\uf126', // 0xC7 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER LEFT (CUS) + '\uf128', // 0xC8 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER RIGHT (CUS) + '\u256e', // 0xC9 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT + '\u2570', // 0xCA -> BOX DRAWINGS LIGHT ARC UP AND RIGHT + '\u256f', // 0xCB -> BOX DRAWINGS LIGHT ARC UP AND LEFT + '\uf12a', // 0xCC -> ONE EIGHTH BLOCK UP AND RIGHT (CUS) + '\u2572', // 0xCD -> BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + '\u2571', // 0xCE -> BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + '\uf12b', // 0xCF -> ONE EIGHTH BLOCK DOWN AND RIGHT (CUS) + '\uf12c', // 0xD0 -> ONE EIGHTH BLOCK DOWN AND LEFT (CUS) + '\u25cf', // 0xD1 -> BLACK CIRCLE + '\uf125', // 0xD2 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS DOWN (CUS) + '\u2665', // 0xD3 -> BLACK HEART SUIT + '\uf127', // 0xD4 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS LEFT (CUS) + '\u256d', // 0xD5 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT + '\u2573', // 0xD6 -> BOX DRAWINGS LIGHT DIAGONAL CROSS + '\u25cb', // 0xD7 -> WHITE CIRCLE + '\u2663', // 0xD8 -> BLACK CLUB SUIT + '\uf129', // 0xD9 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS RIGHT (CUS) + '\u2666', // 0xDA -> BLACK DIAMOND SUIT + '\u253c', // 0xDB -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', // 0xDC -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // 0xDD -> BOX DRAWINGS LIGHT VERTICAL + '\u03c0', // 0xDE -> GREEK SMALL LETTER PI + '\u25e5', // 0xDF -> BLACK UPPER RIGHT TRIANGLE + '\u00a0', // 0xE0 -> NO-BREAK SPACE + '\u258c', // 0xE1 -> LEFT HALF BLOCK + '\u2584', // 0xE2 -> LOWER HALF BLOCK + '\u2594', // 0xE3 -> UPPER ONE EIGHTH BLOCK + '\u2581', // 0xE4 -> LOWER ONE EIGHTH BLOCK + '\u258f', // 0xE5 -> LEFT ONE EIGHTH BLOCK + '\u2592', // 0xE6 -> MEDIUM SHADE + '\u2595', // 0xE7 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', // 0xE8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\u25e4', // 0xE9 -> BLACK UPPER LEFT TRIANGLE + '\uf130', // 0xEA -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // 0xEB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // 0xEC -> QUADRANT LOWER RIGHT + '\u2514', // 0xED -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // 0xEE -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // 0xEF -> LOWER ONE QUARTER BLOCK + '\u250c', // 0xF0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // 0xF1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // 0xF2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // 0xF3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // 0xF4 -> LEFT ONE QUARTER BLOCK + '\u258d', // 0xF5 -> LEFT THREE EIGTHS BLOCK + '\uf131', // 0xF6 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', // 0xF7 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', // 0xF8 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // 0xF9 -> LOWER THREE EIGHTHS BLOCK + '\uf12d', // 0xFA -> ONE EIGHTH BLOCK UP AND LEFT (CUS) + '\u2596', // 0xFB -> QUADRANT LOWER LEFT + '\u259d', // 0xFC -> QUADRANT UPPER RIGHT + '\u2518', // 0xFD -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // 0xFE -> QUADRANT UPPER LEFT + '\u03c0' // 0xFF -> GREEK SMALL LETTER PI + ) + + private val decodingScreencodeLowercase = arrayOf( + '@' , // 0x00 -> COMMERCIAL AT + 'a' , // 0x01 -> LATIN SMALL LETTER A + 'b' , // 0x02 -> LATIN SMALL LETTER B + 'c' , // 0x03 -> LATIN SMALL LETTER C + 'd' , // 0x04 -> LATIN SMALL LETTER D + 'e' , // 0x05 -> LATIN SMALL LETTER E + 'f' , // 0x06 -> LATIN SMALL LETTER F + 'g' , // 0x07 -> LATIN SMALL LETTER G + 'h' , // 0x08 -> LATIN SMALL LETTER H + 'i' , // 0x09 -> LATIN SMALL LETTER I + 'j' , // 0x0A -> LATIN SMALL LETTER J + 'k' , // 0x0B -> LATIN SMALL LETTER K + 'l' , // 0x0C -> LATIN SMALL LETTER L + 'm' , // 0x0D -> LATIN SMALL LETTER M + 'n' , // 0x0E -> LATIN SMALL LETTER N + 'o' , // 0x0F -> LATIN SMALL LETTER O + 'p' , // 0x10 -> LATIN SMALL LETTER P + 'q' , // 0x11 -> LATIN SMALL LETTER Q + 'r' , // 0x12 -> LATIN SMALL LETTER R + 's' , // 0x13 -> LATIN SMALL LETTER S + 't' , // 0x14 -> LATIN SMALL LETTER T + 'u' , // 0x15 -> LATIN SMALL LETTER U + 'v' , // 0x16 -> LATIN SMALL LETTER V + 'w' , // 0x17 -> LATIN SMALL LETTER W + 'x' , // 0x18 -> LATIN SMALL LETTER X + 'y' , // 0x19 -> LATIN SMALL LETTER Y + 'z' , // 0x1A -> LATIN SMALL LETTER Z + '[' , // 0x1B -> LEFT SQUARE BRACKET + '\u00a3', // 0x1C -> POUND SIGN + ']' , // 0x1D -> RIGHT SQUARE BRACKET + '\u2191', // 0x1E -> UPWARDS ARROW + '\u2190', // 0x1F -> LEFTWARDS ARROW + ' ' , // 0x20 -> SPACE + '!' , // 0x21 -> EXCLAMATION MARK + '"' , // 0x22 -> QUOTATION MARK + '#' , // 0x23 -> NUMBER SIGN + '$' , // 0x24 -> DOLLAR SIGN + '%' , // 0x25 -> PERCENT SIGN + '&' , // 0x26 -> AMPERSAND + '\'' , // 0x27 -> APOSTROPHE + '(' , // 0x28 -> LEFT PARENTHESIS + ')' , // 0x29 -> RIGHT PARENTHESIS + '*' , // 0x2A -> ASTERISK + '+' , // 0x2B -> PLUS SIGN + ',' , // 0x2C -> COMMA + '-' , // 0x2D -> HYPHEN-MINUS + '.' , // 0x2E -> FULL STOP + '/' , // 0x2F -> SOLIDUS + '0' , // 0x30 -> DIGIT ZERO + '1' , // 0x31 -> DIGIT ONE + '2' , // 0x32 -> DIGIT TWO + '3' , // 0x33 -> DIGIT THREE + '4' , // 0x34 -> DIGIT FOUR + '5' , // 0x35 -> DIGIT FIVE + '6' , // 0x36 -> DIGIT SIX + '7' , // 0x37 -> DIGIT SEVEN + '8' , // 0x38 -> DIGIT EIGHT + '9' , // 0x39 -> DIGIT NINE + ':' , // 0x3A -> COLON + ';' , // 0x3B -> SEMICOLON + '<' , // 0x3C -> LESS-THAN SIGN + '=' , // 0x3D -> EQUALS SIGN + '>' , // 0x3E -> GREATER-THAN SIGN + '?' , // 0x3F -> QUESTION MARK + '\u2500', // 0x40 -> BOX DRAWINGS LIGHT HORIZONTAL + 'A' , // 0x41 -> LATIN CAPITAL LETTER A + 'B' , // 0x42 -> LATIN CAPITAL LETTER B + 'C' , // 0x43 -> LATIN CAPITAL LETTER C + 'D' , // 0x44 -> LATIN CAPITAL LETTER D + 'E' , // 0x45 -> LATIN CAPITAL LETTER E + 'F' , // 0x46 -> LATIN CAPITAL LETTER F + 'G' , // 0x47 -> LATIN CAPITAL LETTER G + 'H' , // 0x48 -> LATIN CAPITAL LETTER H + 'I' , // 0x49 -> LATIN CAPITAL LETTER I + 'J' , // 0x4A -> LATIN CAPITAL LETTER J + 'K' , // 0x4B -> LATIN CAPITAL LETTER K + 'L' , // 0x4C -> LATIN CAPITAL LETTER L + 'M' , // 0x4D -> LATIN CAPITAL LETTER M + 'N' , // 0x4E -> LATIN CAPITAL LETTER N + 'O' , // 0x4F -> LATIN CAPITAL LETTER O + 'P' , // 0x50 -> LATIN CAPITAL LETTER P + 'Q' , // 0x51 -> LATIN CAPITAL LETTER Q + 'R' , // 0x52 -> LATIN CAPITAL LETTER R + 'S' , // 0x53 -> LATIN CAPITAL LETTER S + 'T' , // 0x54 -> LATIN CAPITAL LETTER T + 'U' , // 0x55 -> LATIN CAPITAL LETTER U + 'V' , // 0x56 -> LATIN CAPITAL LETTER V + 'W' , // 0x57 -> LATIN CAPITAL LETTER W + 'X' , // 0x58 -> LATIN CAPITAL LETTER X + 'Y' , // 0x59 -> LATIN CAPITAL LETTER Y + 'Z' , // 0x5A -> LATIN CAPITAL LETTER Z + '\u253c', // 0x5B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', // 0x5C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // 0x5D -> BOX DRAWINGS LIGHT VERTICAL + '\u2592', // 0x5E -> MEDIUM SHADE + '\uf139', // 0x5F -> MEDIUM SHADE SLASHED LEFT (CUS) + '\u00a0', // 0x60 -> NO-BREAK SPACE + '\u258c', // 0x61 -> LEFT HALF BLOCK + '\u2584', // 0x62 -> LOWER HALF BLOCK + '\u2594', // 0x63 -> UPPER ONE EIGHTH BLOCK + '\u2581', // 0x64 -> LOWER ONE EIGHTH BLOCK + '\u258f', // 0x65 -> LEFT ONE EIGHTH BLOCK + '\u2592', // 0x66 -> MEDIUM SHADE + '\u2595', // 0x67 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', // 0x68 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\uf13a', // 0x69 -> MEDIUM SHADE SLASHED RIGHT (CUS) + '\uf130', // 0x6A -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // 0x6B -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // 0x6C -> QUADRANT LOWER RIGHT + '\u2514', // 0x6D -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // 0x6E -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // 0x6F -> LOWER ONE QUARTER BLOCK + '\u250c', // 0x70 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // 0x71 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // 0x72 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // 0x73 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // 0x74 -> LEFT ONE QUARTER BLOCK + '\u258d', // 0x75 -> LEFT THREE EIGTHS BLOCK + '\uf131', // 0x76 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', // 0x77 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', // 0x78 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // 0x79 -> LOWER THREE EIGHTHS BLOCK + '\u2713', // 0x7A -> CHECK MARK + '\u2596', // 0x7B -> QUADRANT LOWER LEFT + '\u259d', // 0x7C -> QUADRANT UPPER RIGHT + '\u2518', // 0x7D -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // 0x7E -> QUADRANT UPPER LEFT + '\u259a', // 0x7F -> QUADRANT UPPER LEFT AND LOWER RIGHT + '\ufffe', // 0x80 -> UNDEFINED + '\ufffe', // 0x81 -> UNDEFINED + '\ufffe', // 0x82 -> UNDEFINED + '\ufffe', // 0x83 -> UNDEFINED + '\ufffe', // 0x84 -> UNDEFINED + '\ufffe', // 0x85 -> UNDEFINED + '\ufffe', // 0x86 -> UNDEFINED + '\ufffe', // 0x87 -> UNDEFINED + '\ufffe', // 0x88 -> UNDEFINED + '\ufffe', // 0x89 -> UNDEFINED + '\ufffe', // 0x8A -> UNDEFINED + '\ufffe', // 0x8B -> UNDEFINED + '\ufffe', // 0x8C -> UNDEFINED + '\ufffe', // 0x8D -> UNDEFINED + '\ufffe', // 0x8E -> UNDEFINED + '\ufffe', // 0x8F -> UNDEFINED + '\ufffe', // 0x90 -> UNDEFINED + '\ufffe', // 0x91 -> UNDEFINED + '\ufffe', // 0x92 -> UNDEFINED + '\ufffe', // 0x93 -> UNDEFINED + '\ufffe', // 0x94 -> UNDEFINED + '\ufffe', // 0x95 -> UNDEFINED + '\ufffe', // 0x96 -> UNDEFINED + '\ufffe', // 0x97 -> UNDEFINED + '\ufffe', // 0x98 -> UNDEFINED + '\ufffe', // 0x99 -> UNDEFINED + '\ufffe', // 0x9A -> UNDEFINED + '\ufffe', // 0x9B -> UNDEFINED + '\ufffe', // 0x9C -> UNDEFINED + '\ufffe', // 0x9D -> UNDEFINED + '\ufffe', // 0x9E -> UNDEFINED + '\ufffe', // 0x9F -> UNDEFINED + '\ufffe', // 0xA0 -> UNDEFINED + '\ufffe', // 0xA1 -> UNDEFINED + '\ufffe', // 0xA2 -> UNDEFINED + '\ufffe', // 0xA3 -> UNDEFINED + '\ufffe', // 0xA4 -> UNDEFINED + '\ufffe', // 0xA5 -> UNDEFINED + '\ufffe', // 0xA6 -> UNDEFINED + '\ufffe', // 0xA7 -> UNDEFINED + '\ufffe', // 0xA8 -> UNDEFINED + '\ufffe', // 0xA9 -> UNDEFINED + '\ufffe', // 0xAA -> UNDEFINED + '\ufffe', // 0xAB -> UNDEFINED + '\ufffe', // 0xAC -> UNDEFINED + '\ufffe', // 0xAD -> UNDEFINED + '\ufffe', // 0xAE -> UNDEFINED + '\ufffe', // 0xAF -> UNDEFINED + '\ufffe', // 0xB0 -> UNDEFINED + '\ufffe', // 0xB1 -> UNDEFINED + '\ufffe', // 0xB2 -> UNDEFINED + '\ufffe', // 0xB3 -> UNDEFINED + '\ufffe', // 0xB4 -> UNDEFINED + '\ufffe', // 0xB5 -> UNDEFINED + '\ufffe', // 0xB6 -> UNDEFINED + '\ufffe', // 0xB7 -> UNDEFINED + '\ufffe', // 0xB8 -> UNDEFINED + '\ufffe', // 0xB9 -> UNDEFINED + '\ufffe', // 0xBA -> UNDEFINED + '\ufffe', // 0xBB -> UNDEFINED + '\ufffe', // 0xBC -> UNDEFINED + '\ufffe', // 0xBD -> UNDEFINED + '\ufffe', // 0xBE -> UNDEFINED + '\ufffe', // 0xBF -> UNDEFINED + '\ufffe', // 0xC0 -> UNDEFINED + '\ufffe', // 0xC1 -> UNDEFINED + '\ufffe', // 0xC2 -> UNDEFINED + '\ufffe', // 0xC3 -> UNDEFINED + '\ufffe', // 0xC4 -> UNDEFINED + '\ufffe', // 0xC5 -> UNDEFINED + '\ufffe', // 0xC6 -> UNDEFINED + '\ufffe', // 0xC7 -> UNDEFINED + '\ufffe', // 0xC8 -> UNDEFINED + '\ufffe', // 0xC9 -> UNDEFINED + '\ufffe', // 0xCA -> UNDEFINED + '\ufffe', // 0xCB -> UNDEFINED + '\ufffe', // 0xCC -> UNDEFINED + '\ufffe', // 0xCD -> UNDEFINED + '\ufffe', // 0xCE -> UNDEFINED + '\ufffe', // 0xCF -> UNDEFINED + '\ufffe', // 0xD0 -> UNDEFINED + '\ufffe', // 0xD1 -> UNDEFINED + '\ufffe', // 0xD2 -> UNDEFINED + '\ufffe', // 0xD3 -> UNDEFINED + '\ufffe', // 0xD4 -> UNDEFINED + '\ufffe', // 0xD5 -> UNDEFINED + '\ufffe', // 0xD6 -> UNDEFINED + '\ufffe', // 0xD7 -> UNDEFINED + '\ufffe', // 0xD8 -> UNDEFINED + '\ufffe', // 0xD9 -> UNDEFINED + '\ufffe', // 0xDA -> UNDEFINED + '\ufffe', // 0xDB -> UNDEFINED + '\ufffe', // 0xDC -> UNDEFINED + '\ufffe', // 0xDD -> UNDEFINED + '\ufffe', // 0xDE -> UNDEFINED + '\ufffe', // 0xDF -> UNDEFINED + '\ufffe', // 0xE0 -> UNDEFINED + '\ufffe', // 0xE1 -> UNDEFINED + '\ufffe', // 0xE2 -> UNDEFINED + '\ufffe', // 0xE3 -> UNDEFINED + '\ufffe', // 0xE4 -> UNDEFINED + '\ufffe', // 0xE5 -> UNDEFINED + '\ufffe', // 0xE6 -> UNDEFINED + '\ufffe', // 0xE7 -> UNDEFINED + '\ufffe', // 0xE8 -> UNDEFINED + '\ufffe', // 0xE9 -> UNDEFINED + '\ufffe', // 0xEA -> UNDEFINED + '\ufffe', // 0xEB -> UNDEFINED + '\ufffe', // 0xEC -> UNDEFINED + '\ufffe', // 0xED -> UNDEFINED + '\ufffe', // 0xEE -> UNDEFINED + '\ufffe', // 0xEF -> UNDEFINED + '\ufffe', // 0xF0 -> UNDEFINED + '\ufffe', // 0xF1 -> UNDEFINED + '\ufffe', // 0xF2 -> UNDEFINED + '\ufffe', // 0xF3 -> UNDEFINED + '\ufffe', // 0xF4 -> UNDEFINED + '\ufffe', // 0xF5 -> UNDEFINED + '\ufffe', // 0xF6 -> UNDEFINED + '\ufffe', // 0xF7 -> UNDEFINED + '\ufffe', // 0xF8 -> UNDEFINED + '\ufffe', // 0xF9 -> UNDEFINED + '\ufffe', // 0xFA -> UNDEFINED + '\ufffe', // 0xFB -> UNDEFINED + '\ufffe', // 0xFC -> UNDEFINED + '\ufffe', // 0xFD -> UNDEFINED + '\ufffe', // 0xFE -> UNDEFINED + '\ufffe' // 0xFF -> UNDEFINED + ) + + private val decodingScreencodeUppercase = arrayOf( + '@' , // 0x00 -> COMMERCIAL AT + 'A' , // 0x01 -> LATIN CAPITAL LETTER A + 'B' , // 0x02 -> LATIN CAPITAL LETTER B + 'C' , // 0x03 -> LATIN CAPITAL LETTER C + 'D' , // 0x04 -> LATIN CAPITAL LETTER D + 'E' , // 0x05 -> LATIN CAPITAL LETTER E + 'F' , // 0x06 -> LATIN CAPITAL LETTER F + 'G' , // 0x07 -> LATIN CAPITAL LETTER G + 'H' , // 0x08 -> LATIN CAPITAL LETTER H + 'I' , // 0x09 -> LATIN CAPITAL LETTER I + 'J' , // 0x0A -> LATIN CAPITAL LETTER J + 'K' , // 0x0B -> LATIN CAPITAL LETTER K + 'L' , // 0x0C -> LATIN CAPITAL LETTER L + 'M' , // 0x0D -> LATIN CAPITAL LETTER M + 'N' , // 0x0E -> LATIN CAPITAL LETTER N + 'O' , // 0x0F -> LATIN CAPITAL LETTER O + 'P' , // 0x10 -> LATIN CAPITAL LETTER P + 'Q' , // 0x11 -> LATIN CAPITAL LETTER Q + 'R' , // 0x12 -> LATIN CAPITAL LETTER R + 'S' , // 0x13 -> LATIN CAPITAL LETTER S + 'T' , // 0x14 -> LATIN CAPITAL LETTER T + 'U' , // 0x15 -> LATIN CAPITAL LETTER U + 'V' , // 0x16 -> LATIN CAPITAL LETTER V + 'W' , // 0x17 -> LATIN CAPITAL LETTER W + 'X' , // 0x18 -> LATIN CAPITAL LETTER X + 'Y' , // 0x19 -> LATIN CAPITAL LETTER Y + 'Z' , // 0x1A -> LATIN CAPITAL LETTER Z + '[' , // 0x1B -> LEFT SQUARE BRACKET + '\u00a3', // 0x1C -> POUND SIGN + ']' , // 0x1D -> RIGHT SQUARE BRACKET + '\u2191', // 0x1E -> UPWARDS ARROW + '\u2190', // 0x1F -> LEFTWARDS ARROW + ' ' , // 0x20 -> SPACE + '!' , // 0x21 -> EXCLAMATION MARK + '"' , // 0x22 -> QUOTATION MARK + '#' , // 0x23 -> NUMBER SIGN + '$' , // 0x24 -> DOLLAR SIGN + '%' , // 0x25 -> PERCENT SIGN + '&' , // 0x26 -> AMPERSAND + '\'' , // 0x27 -> APOSTROPHE + '(' , // 0x28 -> LEFT PARENTHESIS + ')' , // 0x29 -> RIGHT PARENTHESIS + '*' , // 0x2A -> ASTERISK + '+' , // 0x2B -> PLUS SIGN + ',' , // 0x2C -> COMMA + '-' , // 0x2D -> HYPHEN-MINUS + '.' , // 0x2E -> FULL STOP + '/' , // 0x2F -> SOLIDUS + '0' , // 0x30 -> DIGIT ZERO + '1' , // 0x31 -> DIGIT ONE + '2' , // 0x32 -> DIGIT TWO + '3' , // 0x33 -> DIGIT THREE + '4' , // 0x34 -> DIGIT FOUR + '5' , // 0x35 -> DIGIT FIVE + '6' , // 0x36 -> DIGIT SIX + '7' , // 0x37 -> DIGIT SEVEN + '8' , // 0x38 -> DIGIT EIGHT + '9' , // 0x39 -> DIGIT NINE + ':' , // 0x3A -> COLON + ';' , // 0x3B -> SEMICOLON + '<' , // 0x3C -> LESS-THAN SIGN + '=' , // 0x3D -> EQUALS SIGN + '>' , // 0x3E -> GREATER-THAN SIGN + '?' , // 0x3F -> QUESTION MARK + '\u2500', // 0x40 -> BOX DRAWINGS LIGHT HORIZONTAL + '\u2660', // 0x41 -> BLACK SPADE SUIT + '\u2502', // 0x42 -> BOX DRAWINGS LIGHT VERTICAL + '\u2500', // 0x43 -> BOX DRAWINGS LIGHT HORIZONTAL + '\uf122', // 0x44 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER UP (CUS) + '\uf123', // 0x45 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS UP (CUS) + '\uf124', // 0x46 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER DOWN (CUS) + '\uf126', // 0x47 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER LEFT (CUS) + '\uf128', // 0x48 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER RIGHT (CUS) + '\u256e', // 0x49 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT + '\u2570', // 0x4A -> BOX DRAWINGS LIGHT ARC UP AND RIGHT + '\u256f', // 0x4B -> BOX DRAWINGS LIGHT ARC UP AND LEFT + '\uf12a', // 0x4C -> ONE EIGHTH BLOCK UP AND RIGHT (CUS) + '\u2572', // 0x4D -> BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + '\u2571', // 0x4E -> BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + '\uf12b', // 0x4F -> ONE EIGHTH BLOCK DOWN AND RIGHT (CUS) + '\uf12c', // 0x50 -> ONE EIGHTH BLOCK DOWN AND LEFT (CUS) + '\u25cf', // 0x51 -> BLACK CIRCLE + '\uf125', // 0x52 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS DOWN (CUS) + '\u2665', // 0x53 -> BLACK HEART SUIT + '\uf127', // 0x54 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS LEFT (CUS) + '\u256d', // 0x55 -> BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + '\u2573', // 0x56 -> BOX DRAWINGS LIGHT DIAGONAL CROSS + '\u25cb', // 0x57 -> WHITE CIRCLE + '\u2663', // 0x58 -> BLACK CLUB SUIT + '\uf129', // 0x59 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS RIGHT (CUS) + '\u2666', // 0x5A -> BLACK DIAMOND SUIT + '\u253c', // 0x5B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', // 0x5C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // 0x5D -> BOX DRAWINGS LIGHT VERTICAL + '\u03c0', // 0x5E -> GREEK SMALL LETTER PI + '\u25e5', // 0x5F -> BLACK UPPER RIGHT TRIANGLE + '\u00a0', // 0x60 -> NO-BREAK SPACE + '\u258c', // 0x61 -> LEFT HALF BLOCK + '\u2584', // 0x62 -> LOWER HALF BLOCK + '\u2594', // 0x63 -> UPPER ONE EIGHTH BLOCK + '\u2581', // 0x64 -> LOWER ONE EIGHTH BLOCK + '\u258f', // 0x65 -> LEFT ONE EIGHTH BLOCK + '\u2592', // 0x66 -> MEDIUM SHADE + '\u2595', // 0x67 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', // 0x68 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\u25e4', // 0x69 -> BLACK UPPER LEFT TRIANGLE + '\uf130', // 0x6A -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // 0x6B -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // 0x6C -> QUADRANT LOWER RIGHT + '\u2514', // 0x6D -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // 0x6E -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // 0x6F -> LOWER ONE QUARTER BLOCK + '\u250c', // 0x70 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // 0x71 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // 0x72 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // 0x73 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // 0x74 -> LEFT ONE QUARTER BLOCK + '\u258d', // 0x75 -> LEFT THREE EIGTHS BLOCK + '\uf131', // 0x76 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', // 0x77 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', // 0x78 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // 0x79 -> LOWER THREE EIGHTHS BLOCK + '\uf12d', // 0x7A -> ONE EIGHTH BLOCK UP AND LEFT (CUS) + '\u2596', // 0x7B -> QUADRANT LOWER LEFT + '\u259d', // 0x7C -> QUADRANT UPPER RIGHT + '\u2518', // 0x7D -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // 0x7E -> QUADRANT UPPER LEFT + '\u259a', // 0x7F -> QUADRANT UPPER LEFT AND LOWER RIGHT + '\ufffe', // 0x80 -> UNDEFINED + '\ufffe', // 0x81 -> UNDEFINED + '\ufffe', // 0x82 -> UNDEFINED + '\ufffe', // 0x83 -> UNDEFINED + '\ufffe', // 0x84 -> UNDEFINED + '\ufffe', // 0x85 -> UNDEFINED + '\ufffe', // 0x86 -> UNDEFINED + '\ufffe', // 0x87 -> UNDEFINED + '\ufffe', // 0x88 -> UNDEFINED + '\ufffe', // 0x89 -> UNDEFINED + '\ufffe', // 0x8A -> UNDEFINED + '\ufffe', // 0x8B -> UNDEFINED + '\ufffe', // 0x8C -> UNDEFINED + '\ufffe', // 0x8D -> UNDEFINED + '\ufffe', // 0x8E -> UNDEFINED + '\ufffe', // 0x8F -> UNDEFINED + '\ufffe', // 0x90 -> UNDEFINED + '\ufffe', // 0x91 -> UNDEFINED + '\ufffe', // 0x92 -> UNDEFINED + '\ufffe', // 0x93 -> UNDEFINED + '\ufffe', // 0x94 -> UNDEFINED + '\ufffe', // 0x95 -> UNDEFINED + '\ufffe', // 0x96 -> UNDEFINED + '\ufffe', // 0x97 -> UNDEFINED + '\ufffe', // 0x98 -> UNDEFINED + '\ufffe', // 0x99 -> UNDEFINED + '\ufffe', // 0x9A -> UNDEFINED + '\ufffe', // 0x9B -> UNDEFINED + '\ufffe', // 0x9C -> UNDEFINED + '\ufffe', // 0x9D -> UNDEFINED + '\ufffe', // 0x9E -> UNDEFINED + '\ufffe', // 0x9F -> UNDEFINED + '\ufffe', // 0xA0 -> UNDEFINED + '\ufffe', // 0xA1 -> UNDEFINED + '\ufffe', // 0xA2 -> UNDEFINED + '\ufffe', // 0xA3 -> UNDEFINED + '\ufffe', // 0xA4 -> UNDEFINED + '\ufffe', // 0xA5 -> UNDEFINED + '\ufffe', // 0xA6 -> UNDEFINED + '\ufffe', // 0xA7 -> UNDEFINED + '\ufffe', // 0xA8 -> UNDEFINED + '\ufffe', // 0xA9 -> UNDEFINED + '\ufffe', // 0xAA -> UNDEFINED + '\ufffe', // 0xAB -> UNDEFINED + '\ufffe', // 0xAC -> UNDEFINED + '\ufffe', // 0xAD -> UNDEFINED + '\ufffe', // 0xAE -> UNDEFINED + '\ufffe', // 0xAF -> UNDEFINED + '\ufffe', // 0xB0 -> UNDEFINED + '\ufffe', // 0xB1 -> UNDEFINED + '\ufffe', // 0xB2 -> UNDEFINED + '\ufffe', // 0xB3 -> UNDEFINED + '\ufffe', // 0xB4 -> UNDEFINED + '\ufffe', // 0xB5 -> UNDEFINED + '\ufffe', // 0xB6 -> UNDEFINED + '\ufffe', // 0xB7 -> UNDEFINED + '\ufffe', // 0xB8 -> UNDEFINED + '\ufffe', // 0xB9 -> UNDEFINED + '\ufffe', // 0xBA -> UNDEFINED + '\ufffe', // 0xBB -> UNDEFINED + '\ufffe', // 0xBC -> UNDEFINED + '\ufffe', // 0xBD -> UNDEFINED + '\ufffe', // 0xBE -> UNDEFINED + '\ufffe', // 0xBF -> UNDEFINED + '\ufffe', // 0xC0 -> UNDEFINED + '\ufffe', // 0xC1 -> UNDEFINED + '\ufffe', // 0xC2 -> UNDEFINED + '\ufffe', // 0xC3 -> UNDEFINED + '\ufffe', // 0xC4 -> UNDEFINED + '\ufffe', // 0xC5 -> UNDEFINED + '\ufffe', // 0xC6 -> UNDEFINED + '\ufffe', // 0xC7 -> UNDEFINED + '\ufffe', // 0xC8 -> UNDEFINED + '\ufffe', // 0xC9 -> UNDEFINED + '\ufffe', // 0xCA -> UNDEFINED + '\ufffe', // 0xCB -> UNDEFINED + '\ufffe', // 0xCC -> UNDEFINED + '\ufffe', // 0xCD -> UNDEFINED + '\ufffe', // 0xCE -> UNDEFINED + '\ufffe', // 0xCF -> UNDEFINED + '\ufffe', // 0xD0 -> UNDEFINED + '\ufffe', // 0xD1 -> UNDEFINED + '\ufffe', // 0xD2 -> UNDEFINED + '\ufffe', // 0xD3 -> UNDEFINED + '\ufffe', // 0xD4 -> UNDEFINED + '\ufffe', // 0xD5 -> UNDEFINED + '\ufffe', // 0xD6 -> UNDEFINED + '\ufffe', // 0xD7 -> UNDEFINED + '\ufffe', // 0xD8 -> UNDEFINED + '\ufffe', // 0xD9 -> UNDEFINED + '\ufffe', // 0xDA -> UNDEFINED + '\ufffe', // 0xDB -> UNDEFINED + '\ufffe', // 0xDC -> UNDEFINED + '\ufffe', // 0xDD -> UNDEFINED + '\ufffe', // 0xDE -> UNDEFINED + '\ufffe', // 0xDF -> UNDEFINED + '\ufffe', // 0xE0 -> UNDEFINED + '\ufffe', // 0xE1 -> UNDEFINED + '\ufffe', // 0xE2 -> UNDEFINED + '\ufffe', // 0xE3 -> UNDEFINED + '\ufffe', // 0xE4 -> UNDEFINED + '\ufffe', // 0xE5 -> UNDEFINED + '\ufffe', // 0xE6 -> UNDEFINED + '\ufffe', // 0xE7 -> UNDEFINED + '\ufffe', // 0xE8 -> UNDEFINED + '\ufffe', // 0xE9 -> UNDEFINED + '\ufffe', // 0xEA -> UNDEFINED + '\ufffe', // 0xEB -> UNDEFINED + '\ufffe', // 0xEC -> UNDEFINED + '\ufffe', // 0xED -> UNDEFINED + '\ufffe', // 0xEE -> UNDEFINED + '\ufffe', // 0xEF -> UNDEFINED + '\ufffe', // 0xF0 -> UNDEFINED + '\ufffe', // 0xF1 -> UNDEFINED + '\ufffe', // 0xF2 -> UNDEFINED + '\ufffe', // 0xF3 -> UNDEFINED + '\ufffe', // 0xF4 -> UNDEFINED + '\ufffe', // 0xF5 -> UNDEFINED + '\ufffe', // 0xF6 -> UNDEFINED + '\ufffe', // 0xF7 -> UNDEFINED + '\ufffe', // 0xF8 -> UNDEFINED + '\ufffe', // 0xF9 -> UNDEFINED + '\ufffe', // 0xFA -> UNDEFINED + '\ufffe', // 0xFB -> UNDEFINED + '\ufffe', // 0xFC -> UNDEFINED + '\ufffe', // 0xFD -> UNDEFINED + '\ufffe', // 0xFE -> UNDEFINED + '\ufffe' // 0xFF -> UNDEFINED + ) + + // encoding: from unicode to Petscii/Screencodes (0-255) + private val encodingPetsciiLowercase = decodingPetsciiLowercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() + private val encodingPetsciiUppercase = decodingPetsciiUppercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() + private val encodingScreencodeLowercase = decodingScreencodeLowercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() + private val encodingScreencodeUppercase = decodingScreencodeUppercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() + + + fun encodePetscii(text: String, lowercase: Boolean = false): ShortArray { + val result = ShortArray(text.length) + val lookup = if(lowercase) encodingPetsciiLowercase else encodingPetsciiUppercase + text.forEachIndexed { index, c -> + val petscii = lookup[c] ?: throw CompilerException("no Petscii character for '$c'") + result[index] = petscii.toShort() + } + + return result + } + + fun decodePetscii(petscii: ShortArray, lowercase: Boolean = false): String { + val decodeTable = if(lowercase) decodingPetsciiLowercase else decodingPetsciiUppercase + return petscii.map { decodeTable[it.toInt()] }.joinToString("") + } + + fun encodeScreencode(text: String, lowercase: Boolean = false): ShortArray { + val result = ShortArray(text.length) + val lookup = if(lowercase) encodingScreencodeLowercase else encodingScreencodeUppercase + text.forEachIndexed { index, c -> + val screencode = lookup[c] ?: throw CompilerException("no Screencode character for '$c'") + result[index] = screencode.toShort() + } + return result + } + + fun decodeScreencode(screencode: ShortArray, lowercase: Boolean = false): String { + val decodeTable = if(lowercase) decodingScreencodeLowercase else decodingScreencodeUppercase + return screencode.map { decodeTable[it.toInt()] }.joinToString("") + } + } +} diff --git a/il65/src/il65/optimizing/ExpressionOptimizer.kt b/il65/src/il65/optimizing/ExpressionOptimizer.kt index 2077c0a13..4d4b1bd78 100644 --- a/il65/src/il65/optimizing/ExpressionOptimizer.kt +++ b/il65/src/il65/optimizing/ExpressionOptimizer.kt @@ -70,7 +70,7 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess /** * replace identifiers that refer to const value, with the value itself */ - override fun process(identifier: Identifier): IExpression { + override fun process(identifier: IdentifierReference): IExpression { return try { identifier.constValue(globalNamespace) ?: identifier } catch (ax: AstException) { diff --git a/il65/src/il65/optimizing/StatementsOptimizer.kt b/il65/src/il65/optimizing/StatementsOptimizer.kt index 17de274d1..0c0b15a18 100644 --- a/il65/src/il65/optimizing/StatementsOptimizer.kt +++ b/il65/src/il65/optimizing/StatementsOptimizer.kt @@ -18,7 +18,7 @@ fun Module.optimizeStatements(globalNamespace: INameScope) { } /* - todo remove unused blocks and unused subroutines + todo remove unused blocks, subroutines and variable decls (replace with empty AnonymousStatementList) todo statement optimization: create augmented assignment from assignment that only refers to its lvalue (A=A+10, A=4*A, ...) todo statement optimization: X+=1, X-=1 --> X++/X-- , todo remove statements that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc diff --git a/il65/test/UnitTests.kt b/il65/test/UnitTests.kt index add1edd35..40ebeeed7 100644 --- a/il65/test/UnitTests.kt +++ b/il65/test/UnitTests.kt @@ -202,3 +202,64 @@ class TestZeropage { assert(zp.available()==0) } } + + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class TestPetscii { + + @Test + fun testLowercase() { + assertThat(Petscii.encodePetscii("hello WORLD 123 @!£", true), equalTo( + shortArrayOf(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(shortArrayOf(0x12))) // reverse vid + assertThat(Petscii.encodePetscii("✓", true), equalTo(shortArrayOf(0xfa))) + assertFailsWith { Petscii.encodePetscii("π", true) } + assertFailsWith { Petscii.encodePetscii("♥", true) } + + assertThat(Petscii.decodePetscii(shortArrayOf(72, 0xd7, 0x5c, 0xfa, 0x12), true), equalTo("hW£✓\uF11A")) + assertFailsWith { Petscii.decodePetscii(shortArrayOf(-1), true) } + assertFailsWith { Petscii.decodePetscii(shortArrayOf(256), true) } + } + + @Test + fun testUppercase() { + assertThat(Petscii.encodePetscii("HELLO 123 @!£"), equalTo( + shortArrayOf(72, 69, 76, 76, 79, 32, 49, 50, 51, 32, 64, 33, 0x5c))) + assertThat(Petscii.encodePetscii("\uf11a"), equalTo(shortArrayOf(0x12))) // reverse vid + assertThat(Petscii.encodePetscii("♥"), equalTo(shortArrayOf(0xd3))) + assertThat(Petscii.encodePetscii("π"), equalTo(shortArrayOf(0xff))) + assertFailsWith { Petscii.encodePetscii("✓") } + + assertThat(Petscii.decodePetscii(shortArrayOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π")) + assertFailsWith { Petscii.decodePetscii(shortArrayOf(-1)) } + assertFailsWith { Petscii.decodePetscii(shortArrayOf(256)) } + } + + @Test + fun testScreencodeLowercase() { + assertThat(Petscii.encodeScreencode("hello WORLD 123 @!£", true), equalTo( + shortArrayOf(0x08, 0x05, 0x0c, 0x0c, 0x0f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c) + )) + assertThat(Petscii.encodeScreencode("✓", true), equalTo(shortArrayOf(0x7a))) + assertFailsWith { Petscii.encodeScreencode("♥", true) } + assertFailsWith { Petscii.encodeScreencode("π", true) } + + assertThat(Petscii.decodeScreencode(shortArrayOf(0x08, 0x57, 0x1c, 0x7a), true), equalTo("hW£✓")) + assertFailsWith { Petscii.decodeScreencode(shortArrayOf(-1), true) } + assertFailsWith { Petscii.decodeScreencode(shortArrayOf(256), true) } + } + + @Test + fun testScreencodeUppercase() { + assertThat(Petscii.encodeScreencode("WORLD 123 @!£"), equalTo( + shortArrayOf(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c))) + assertThat(Petscii.encodeScreencode("♥"), equalTo(shortArrayOf(0x53))) + assertThat(Petscii.encodeScreencode("π"), equalTo(shortArrayOf(0x5e))) + assertFailsWith { Petscii.encodeScreencode("✓") } + assertFailsWith { Petscii.encodeScreencode("hello") } + + assertThat(Petscii.decodeScreencode(shortArrayOf(0x17, 0x1c, 0x53, 0x5e)), equalTo("W£♥π")) + assertFailsWith { Petscii.decodeScreencode(shortArrayOf(-1)) } + assertFailsWith { Petscii.decodeScreencode(shortArrayOf(256)) } + } +}