mirror of
https://github.com/KarolS/millfork.git
synced 2025-08-15 19:27:22 +00:00
Add nullchar constant, NULLCHAR feature, and vectrex encoding
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## Current version
|
## Current version
|
||||||
|
|
||||||
|
* Added `nullchar` constant as the null terminator for strings and `NULLCHAR` feature to define its value.
|
||||||
|
|
||||||
|
* Added `vectrex` text encoding.
|
||||||
|
|
||||||
## 0.3.6
|
## 0.3.6
|
||||||
|
|
||||||
* **Breaking change!**
|
* **Breaking change!**
|
||||||
|
@@ -36,7 +36,9 @@ Two encoding names are special and refer to platform-specific encodings:
|
|||||||
`default` and `scr`.
|
`default` and `scr`.
|
||||||
|
|
||||||
You can also append `z` to the name of the encoding to make the string zero-terminated.
|
You can also append `z` to the name of the encoding to make the string zero-terminated.
|
||||||
This means that the string will have one extra byte appended, equal to 0.
|
This means that the string will have one extra byte appended, equal to `nullchar`.
|
||||||
|
The exact value of `nullchar` is encoding-dependent: in the `vectrex` encoding it's $80,
|
||||||
|
in other encodings it's 0 (this might be a subject to change in future versions).
|
||||||
|
|
||||||
"this is a zero-terminated string" asciiz
|
"this is a zero-terminated string" asciiz
|
||||||
"this is also a zero-terminated string"z
|
"this is also a zero-terminated string"z
|
||||||
|
@@ -43,6 +43,8 @@
|
|||||||
|
|
||||||
* `atasciiscr` or `atariscr` – screencodes used by Atari 8-bit computers
|
* `atasciiscr` or `atariscr` – screencodes used by Atari 8-bit computers
|
||||||
|
|
||||||
|
* `vectrex` – built-in Vectrex font
|
||||||
|
|
||||||
When programming for Commodore,
|
When programming for Commodore,
|
||||||
use `pet` for strings you're printing using standard I/O routines
|
use `pet` for strings you're printing using standard I/O routines
|
||||||
and `petscr` for strings you're copying to screen memory directly.
|
and `petscr` for strings you're copying to screen memory directly.
|
||||||
@@ -61,6 +63,12 @@ Some escape sequences may expand to multiple characters. For example, in several
|
|||||||
|
|
||||||
* `{x00}`–`{xff}` – a character of the given hexadecimal value
|
* `{x00}`–`{xff}` – a character of the given hexadecimal value
|
||||||
|
|
||||||
|
* `{copyright_year}` – this expands to the current year in digits
|
||||||
|
|
||||||
|
* `{program_name}` – this expands to the name of the output file without the file extension
|
||||||
|
|
||||||
|
* `{program_name_upper}` – the same, but uppercased
|
||||||
|
|
||||||
##### Available only in some encodings
|
##### Available only in some encodings
|
||||||
|
|
||||||
* `{n}` – new line
|
* `{n}` – new line
|
||||||
@@ -79,6 +87,8 @@ control codes for changing the text background color
|
|||||||
|
|
||||||
* `{reverse}`, `{reverseoff}` – inverted mode on/off
|
* `{reverse}`, `{reverseoff}` – inverted mode on/off
|
||||||
|
|
||||||
|
* `{yen}`, `{pound}`, `{copy}` – yen symbol, pound symbol, copyright symbol
|
||||||
|
|
||||||
##### Character availability
|
##### Character availability
|
||||||
|
|
||||||
Encoding | lowercase letters | backslash | pound | yen | katakana | card suits
|
Encoding | lowercase letters | backslash | pound | yen | katakana | card suits
|
||||||
@@ -96,6 +106,7 @@ Encoding | lowercase letters | backslash | pound | yen | katakana | card suits
|
|||||||
`msx_intl` | yes | yes | yes | yes | no | yes
|
`msx_intl` | yes | yes | yes | yes | no | yes
|
||||||
`msx_jp` | yes | no | no | yes | yes | yes
|
`msx_jp` | yes | no | no | yes | yes | yes
|
||||||
`msx_ru` | yes | yes | no | no | no | yes
|
`msx_ru` | yes | yes | no | no | no | yes
|
||||||
|
`vectrex` | no | yes | no | no | no | no
|
||||||
all the rest | yes | yes | no | no | no | no
|
all the rest | yes | yes | no | no | no | no
|
||||||
|
|
||||||
1. `pet`, `origpet` and `petscr` cannot display card suit symbols and lowercase letters at the same time.
|
1. `pet`, `origpet` and `petscr` cannot display card suit symbols and lowercase letters at the same time.
|
||||||
@@ -124,4 +135,5 @@ Encoding | new line | braces | backspace | cursor movement | text colour | rever
|
|||||||
`apple2` | no | yes | no | no | no | no | no
|
`apple2` | no | yes | no | no | no | no | no
|
||||||
`atascii` | yes | no | yes | yes | no | no | no
|
`atascii` | yes | no | yes | yes | no | no | no
|
||||||
`atasciiscr` | no | no | no | no | no | no | no
|
`atasciiscr` | no | no | no | no | no | no | no
|
||||||
|
`vectrex` | no | no | no | no | no | no | no
|
||||||
all the rest | yes | yes | no | no | no | no | no
|
all the rest | yes | yes | no | no | no | no | no
|
||||||
|
@@ -26,7 +26,7 @@ asm void putstrz(pointer hl) @$5550 extern
|
|||||||
void putstrz(pointer str) {
|
void putstrz(pointer str) {
|
||||||
byte index
|
byte index
|
||||||
index = 0
|
index = 0
|
||||||
while str[index] != 0 {
|
while str[index] != nullchar {
|
||||||
putchar(str[index])
|
putchar(str[index])
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ word strz2word(pointer str) {
|
|||||||
errno = err_ok
|
errno = err_ok
|
||||||
while true {
|
while true {
|
||||||
char = str[i]
|
char = str[i]
|
||||||
if char == 0 {
|
if char == nullchar {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
errno = err_numberformat
|
errno = err_numberformat
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
byte strzlen(pointer str) {
|
byte strzlen(pointer str) {
|
||||||
byte index
|
byte index
|
||||||
index = 0
|
index = 0
|
||||||
while str[index] != 0 {
|
while str[index] != nullchar {
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
return index
|
return index
|
||||||
@@ -17,7 +17,7 @@ sbyte strzcmp(pointer str1, pointer str2) {
|
|||||||
if str1[i1] < str2[i2] { return -1 }
|
if str1[i1] < str2[i2] { return -1 }
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if str1[i1] == 0 {
|
if str1[i1] == nullchar {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
i1 += 1
|
i1 += 1
|
||||||
@@ -33,5 +33,5 @@ void strzcopy(pointer dest, pointer src) {
|
|||||||
c = src[i]
|
c = src[i]
|
||||||
dest[i] = c
|
dest[i] = c
|
||||||
i += 1
|
i += 1
|
||||||
} while c != 0
|
} while c != nullchar
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
byte strzlen(pointer str) {
|
byte strzlen(pointer str) {
|
||||||
pointer end
|
pointer end
|
||||||
end = str
|
end = str
|
||||||
while end[0] != 0 {
|
while end[0] != nullchar {
|
||||||
end += 1
|
end += 1
|
||||||
}
|
}
|
||||||
return lo(end - str)
|
return lo(end - str)
|
||||||
@@ -11,8 +11,8 @@ byte strzlen(pointer str) {
|
|||||||
|
|
||||||
sbyte strzcmp(pointer str1, pointer str2) {
|
sbyte strzcmp(pointer str1, pointer str2) {
|
||||||
while true {
|
while true {
|
||||||
if str1[0] == 0 {
|
if str1[0] == nullchar {
|
||||||
if str2[0] == 0 {
|
if str2[0] == nullchar {
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
return -1
|
return -1
|
||||||
@@ -33,5 +33,5 @@ void strzcopy(pointer dest, pointer src) {
|
|||||||
dest[0] = c
|
dest[0] = c
|
||||||
src += 1
|
src += 1
|
||||||
dest += 1
|
dest += 1
|
||||||
} while c != 0
|
} while c != nullchar
|
||||||
}
|
}
|
||||||
|
@@ -433,6 +433,9 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
|||||||
addThing(ConstantThing("nullptr.raw", nullptrConstant, p), None)
|
addThing(ConstantThing("nullptr.raw", nullptrConstant, p), None)
|
||||||
addThing(ConstantThing("nullptr.raw.hi", nullptrConstant.hiByte.quickSimplify, b), None)
|
addThing(ConstantThing("nullptr.raw.hi", nullptrConstant.hiByte.quickSimplify, b), None)
|
||||||
addThing(ConstantThing("nullptr.raw.lo", nullptrConstant.loByte.quickSimplify, b), None)
|
addThing(ConstantThing("nullptr.raw.lo", nullptrConstant.loByte.quickSimplify, b), None)
|
||||||
|
val nullcharValue = options.features.getOrElse("NULLCHAR", 0L)
|
||||||
|
val nullcharConstant = NumericConstant(nullcharValue, 1)
|
||||||
|
addThing(ConstantThing("nullchar", nullcharConstant, b), None)
|
||||||
val __zeropage_usage = UnexpandedConstant("__zeropage_usage", 1)
|
val __zeropage_usage = UnexpandedConstant("__zeropage_usage", 1)
|
||||||
addThing(ConstantThing("__zeropage_usage", __zeropage_usage, b), None)
|
addThing(ConstantThing("__zeropage_usage", __zeropage_usage, b), None)
|
||||||
def addUnexpandedWordConstant(name: String): Unit = {
|
def addUnexpandedWordConstant(name: String): Unit = {
|
||||||
|
@@ -68,12 +68,12 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
|
|||||||
if (zt) {
|
if (zt) {
|
||||||
log.error("Zero-terminated encoding is not a valid encoding for a character literal", Some(p))
|
log.error("Zero-terminated encoding is not a valid encoding for a character literal", Some(p))
|
||||||
}
|
}
|
||||||
co.encode(options.log, Some(p), c.toList, lenient = lenient) match {
|
co.encode(options.log, Some(p), c.toList, options, lenient = lenient) match {
|
||||||
case List(value) =>
|
case List(value) =>
|
||||||
LiteralExpression(value, 1)
|
LiteralExpression(value, 1)
|
||||||
case _ =>
|
case _ =>
|
||||||
log.error(s"Character `$c` cannot be encoded as one byte", Some(p))
|
log.error(s"Character `$c` cannot be encoded as one byte", Some(p))
|
||||||
LiteralExpression(0, 1)
|
LiteralExpression(co.stringTerminator, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,8 +87,8 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
|
|||||||
|
|
||||||
val textLiteral: P[List[Expression]] = P(position() ~ doubleQuotedString ~/ HWS ~ codec).map {
|
val textLiteral: P[List[Expression]] = P(position() ~ doubleQuotedString ~/ HWS ~ codec).map {
|
||||||
case (p, s, ((co, zt), lenient)) =>
|
case (p, s, ((co, zt), lenient)) =>
|
||||||
val characters = co.encode(options.log, None, s, lenient = lenient).map(c => LiteralExpression(c, 1).pos(p))
|
val characters = co.encode(options.log, None, s, options, lenient = lenient).map(c => LiteralExpression(c, 1).pos(p))
|
||||||
if (zt) characters :+ LiteralExpression(0,1)
|
if (zt) characters :+ LiteralExpression(co.stringTerminator, 1)
|
||||||
else characters
|
else characters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
package millfork.parser
|
package millfork.parser
|
||||||
|
|
||||||
|
import java.time.LocalDate
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
import millfork.CompilationOptions
|
import millfork.{CompilationFlag, CompilationOptions}
|
||||||
import millfork.error.{ConsoleLogger, Logger}
|
import millfork.error.{ConsoleLogger, Logger}
|
||||||
import millfork.node.Position
|
import millfork.node.Position
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ import millfork.node.Position
|
|||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
class TextCodec(val name: String,
|
class TextCodec(val name: String,
|
||||||
|
val stringTerminator: Int,
|
||||||
private val map: String,
|
private val map: String,
|
||||||
private val extra: Map[Char, Int],
|
private val extra: Map[Char, Int],
|
||||||
private val decompositions: Map[Char, String],
|
private val decompositions: Map[Char, String],
|
||||||
@@ -56,17 +58,17 @@ class TextCodec(val name: String,
|
|||||||
if (s.forall(isPrintable)) f"`$s%s` ($u%s)"
|
if (s.forall(isPrintable)) f"`$s%s` ($u%s)"
|
||||||
else u
|
else u
|
||||||
}
|
}
|
||||||
private def encodeChar(log: Logger, position: Option[Position], c: Char, lenient: Boolean): Option[List[Int]] = {
|
private def encodeChar(log: Logger, position: Option[Position], c: Char, options: CompilationOptions, lenient: Boolean): Option[List[Int]] = {
|
||||||
if (decompositions.contains(c)) {
|
if (decompositions.contains(c)) {
|
||||||
Some(decompositions(c).toList.flatMap(x => encodeChar(log, position, x, lenient).getOrElse(List(x.toInt))))
|
Some(decompositions(c).toList.flatMap(x => encodeChar(log, position, x, options, lenient).getOrElse(List(x.toInt))))
|
||||||
} else if (extra.contains(c)) Some(List(extra(c))) else {
|
} else if (extra.contains(c)) Some(List(extra(c))) else {
|
||||||
val index = map.indexOf(c)
|
val index = map.indexOf(c)
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
Some(List(index))
|
Some(List(index))
|
||||||
} else if (lenient) {
|
} else if (lenient) {
|
||||||
val alternative = TextCodec.lossyAlternatives.getOrElse(c, Nil).:+("?").find(alts => alts.forall(alt => encodeChar(log, position, alt, lenient = false).isDefined)).getOrElse("")
|
val alternative = TextCodec.lossyAlternatives.getOrElse(c, Nil).:+("?").find(alts => alts.forall(alt => encodeChar(log, position, alt, options, lenient = false).isDefined)).getOrElse("")
|
||||||
log.warn(s"Cannot encode ${format(c)} in encoding `$name`, replaced it with ${format(alternative)}", position)
|
log.warn(s"Cannot encode ${format(c)} in encoding `$name`, replaced it with ${format(alternative)}", position)
|
||||||
Some(alternative.toList.flatMap(encodeChar(log, position, _, lenient = false).get))
|
Some(alternative.toList.flatMap(encodeChar(log, position, _, options, lenient = false).get))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -74,27 +76,30 @@ class TextCodec(val name: String,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def encode(log: Logger, position: Option[Position], s: List[Char], lenient: Boolean): List[Int] = s match {
|
def encode(log: Logger, position: Option[Position], s: List[Char], options: CompilationOptions, lenient: Boolean): List[Int] = {
|
||||||
case '{' :: tail =>
|
val lenient = options.flag(CompilationFlag.LenientTextEncoding)
|
||||||
val (escSeq, closingBrace) = tail.span(_ != '}')
|
s match {
|
||||||
closingBrace match {
|
case '{' :: tail =>
|
||||||
case '}' :: xs =>
|
val (escSeq, closingBrace) = tail.span(_ != '}')
|
||||||
encodeEscapeSequence(log, escSeq.mkString(""), position, lenient) ++ encode(log, position, xs, lenient)
|
closingBrace match {
|
||||||
case _ =>
|
case '}' :: xs =>
|
||||||
log.error(f"Unclosed escape sequence", position)
|
encodeEscapeSequence(log, escSeq.mkString(""), position, options, lenient) ++ encode(log, position, xs, options, lenient)
|
||||||
Nil
|
case _ =>
|
||||||
}
|
log.error(f"Unclosed escape sequence", position)
|
||||||
case head :: tail =>
|
Nil
|
||||||
(encodeChar(log, position, head, lenient) match {
|
}
|
||||||
case Some(x) => x
|
case head :: tail =>
|
||||||
case None =>
|
(encodeChar(log, position, head, options, lenient) match {
|
||||||
log.error(f"Invalid character ${format(head)} in string", position)
|
case Some(x) => x
|
||||||
Nil
|
case None =>
|
||||||
}) ++ encode(log, position, tail, lenient)
|
log.error(f"Invalid character ${format(head)} in string", position)
|
||||||
case Nil => Nil
|
Nil
|
||||||
|
}) ++ encode(log, position, tail, options, lenient)
|
||||||
|
case Nil => Nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def encodeEscapeSequence(log: Logger, escSeq: String, position: Option[Position], lenient: Boolean): List[Int] = {
|
private def encodeEscapeSequence(log: Logger, escSeq: String, position: Option[Position], options: CompilationOptions, lenient: Boolean): List[Int] = {
|
||||||
if (escSeq.length == 3 && (escSeq(0) == 'X' || escSeq(0) == 'x' || escSeq(0) == '$')){
|
if (escSeq.length == 3 && (escSeq(0) == 'X' || escSeq(0) == 'x' || escSeq(0) == '$')){
|
||||||
try {
|
try {
|
||||||
return List(Integer.parseInt(escSeq.tail, 16))
|
return List(Integer.parseInt(escSeq.tail, 16))
|
||||||
@@ -102,6 +107,15 @@ class TextCodec(val name: String,
|
|||||||
case _: NumberFormatException =>
|
case _: NumberFormatException =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (escSeq == "program_name_upper") {
|
||||||
|
return encode(log, position, options.outputFileName.getOrElse("MILLFORK").toUpperCase(Locale.ROOT).toList, options, lenient)
|
||||||
|
}
|
||||||
|
if (escSeq == "program_name") {
|
||||||
|
return encode(log, position, options.outputFileName.getOrElse("MILLFORK").toList, options, lenient)
|
||||||
|
}
|
||||||
|
if (escSeq == "copyright_year") {
|
||||||
|
return encode(log, position, LocalDate.now.getYear.toString.toList, options, lenient)
|
||||||
|
}
|
||||||
escapeSequences.getOrElse(escSeq, {
|
escapeSequences.getOrElse(escSeq, {
|
||||||
if (lenient) {
|
if (lenient) {
|
||||||
log.warn(s"Cannot encode escape sequence {$escSeq} in encoding `$name`, skipped it", position)
|
log.warn(s"Cannot encode escape sequence {$escSeq} in encoding `$name`, skipped it", position)
|
||||||
@@ -164,6 +178,7 @@ object TextCodec {
|
|||||||
case (_, "msx_es") => TextCodec.MsxWest
|
case (_, "msx_es") => TextCodec.MsxWest
|
||||||
case (_, "msx_ru") => TextCodec.MsxRu
|
case (_, "msx_ru") => TextCodec.MsxRu
|
||||||
case (_, "msx_jp") => TextCodec.MsxJp
|
case (_, "msx_jp") => TextCodec.MsxJp
|
||||||
|
case (_, "vectrex") => TextCodec.Vectrex
|
||||||
case (p, _) =>
|
case (p, _) =>
|
||||||
log.error(s"Unknown string encoding: `$name`", p)
|
log.error(s"Unknown string encoding: `$name`", p)
|
||||||
TextCodec.Ascii
|
TextCodec.Ascii
|
||||||
@@ -208,16 +223,16 @@ object TextCodec {
|
|||||||
"はひふへほ".zip("ぱぴぷぺぽ").map { case (h, p) => p -> (h + "゜") }.toMap
|
"はひふへほ".zip("ぱぴぷぺぽ").map { case (h, p) => p -> (h + "゜") }.toMap
|
||||||
}
|
}
|
||||||
|
|
||||||
val Ascii = new TextCodec("ASCII", 0.until(127).map { i => if (i < 32) NotAChar else i.toChar }.mkString, Map.empty, Map.empty, AsciiEscapeSequences)
|
val Ascii = new TextCodec("ASCII", 0, 0.until(127).map { i => if (i < 32) NotAChar else i.toChar }.mkString, Map.empty, Map.empty, AsciiEscapeSequences)
|
||||||
|
|
||||||
val Apple2 = new TextCodec("APPLE-II", 0.until(255).map { i =>
|
val Apple2 = new TextCodec("APPLE-II", 0, 0.until(255).map { i =>
|
||||||
if (i < 0xa0) NotAChar
|
if (i < 0xa0) NotAChar
|
||||||
else if (i < 0xe0) (i - 128).toChar
|
else if (i < 0xe0) (i - 128).toChar
|
||||||
else NotAChar
|
else NotAChar
|
||||||
}.mkString,
|
}.mkString,
|
||||||
('a' to 'z').map(l => l -> (l - 'a' + 0xC1)).toMap, Map.empty, MinimalEscapeSequencesWithBraces)
|
('a' to 'z').map(l => l -> (l - 'a' + 0xC1)).toMap, Map.empty, MinimalEscapeSequencesWithBraces)
|
||||||
|
|
||||||
val IsoIec646De = new TextCodec("ISO-IEC-646-DE",
|
val IsoIec646De = new TextCodec("ISO-IEC-646-DE", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
" !\"#$%^'()*+,-./0123456789:;<=>?" +
|
" !\"#$%^'()*+,-./0123456789:;<=>?" +
|
||||||
"§ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ^_" +
|
"§ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ^_" +
|
||||||
@@ -233,7 +248,7 @@ object TextCodec {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val IsoIec646Se = new TextCodec("ISO-IEC-646-SE",
|
val IsoIec646Se = new TextCodec("ISO-IEC-646-SE", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
" !\"#¤%^'()*+,-./0123456789:;<=>?" +
|
" !\"#¤%^'()*+,-./0123456789:;<=>?" +
|
||||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÅ^_" +
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÅ^_" +
|
||||||
@@ -255,7 +270,7 @@ object TextCodec {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val IsoIec646No = new TextCodec("ISO-IEC-646-NO",
|
val IsoIec646No = new TextCodec("ISO-IEC-646-NO", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
" !\"#$%^'()*+,-./0123456789:;<=>?" +
|
" !\"#$%^'()*+,-./0123456789:;<=>?" +
|
||||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ^_" +
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ^_" +
|
||||||
@@ -282,7 +297,7 @@ object TextCodec {
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
val IsoIec646Yu = new TextCodec("ISO-IEC-646-YU",
|
val IsoIec646Yu = new TextCodec("ISO-IEC-646-YU", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
" !\"#$%^'()*+,-./0123456789:;<=>?" +
|
" !\"#$%^'()*+,-./0123456789:;<=>?" +
|
||||||
"ŽABCDEFGHIJKLMNOPQRSTUVWXYZŠĐĆČ_" +
|
"ŽABCDEFGHIJKLMNOPQRSTUVWXYZŠĐĆČ_" +
|
||||||
@@ -290,15 +305,18 @@ object TextCodec {
|
|||||||
Map('Ë' -> '$'.toInt, 'ë' -> '_'.toInt),
|
Map('Ë' -> '$'.toInt, 'ë' -> '_'.toInt),
|
||||||
Map.empty, AsciiEscapeSequences)
|
Map.empty, AsciiEscapeSequences)
|
||||||
|
|
||||||
val CbmScreencodes = new TextCodec("CBM-Screen",
|
val CbmScreencodes = new TextCodec("CBM-Screen", 0,
|
||||||
"@abcdefghijklmnopqrstuvwxyz[£]↑←" +
|
"@abcdefghijklmnopqrstuvwxyz[£]↑←" +
|
||||||
0x20.to(0x3f).map(_.toChar).mkString +
|
0x20.to(0x3f).map(_.toChar).mkString +
|
||||||
"–ABCDEFGHIJKLMNOPQRSTUVWXYZ\ufffd\ufffd\ufffdπ",
|
"–ABCDEFGHIJKLMNOPQRSTUVWXYZ\ufffd\ufffd\ufffdπ",
|
||||||
Map('^' -> 0x1E, '♥' -> 0x53, '♡' -> 0x53, '♠' -> 0x41, '♣' -> 0x58, '♢' -> 0x5A, '•' -> 0x51),
|
Map('^' -> 0x1E, '♥' -> 0x53, '♡' -> 0x53, '♠' -> 0x41, '♣' -> 0x58, '♢' -> 0x5A, '•' -> 0x51),
|
||||||
Map.empty, MinimalEscapeSequencesWithoutBraces
|
Map.empty, MinimalEscapeSequencesWithoutBraces ++ Map(
|
||||||
|
"pound" -> List(0x1c),
|
||||||
|
"pi" -> List(0x5f),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val CbmScreencodesJp = new TextCodec("CBM-Screen-JP",
|
val CbmScreencodesJp = new TextCodec("CBM-Screen-JP", 0,
|
||||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]↑←" + // 00-1f
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]↑←" + // 00-1f
|
||||||
0x20.to(0x3f).map(_.toChar).mkString +
|
0x20.to(0x3f).map(_.toChar).mkString +
|
||||||
"タチツテトナニヌネノハヒフヘホマ" + // 40-4f
|
"タチツテトナニヌネノハヒフヘホマ" + // 40-4f
|
||||||
@@ -323,10 +341,13 @@ object TextCodec {
|
|||||||
('a' to 'z').map(l => l -> (l - 'a' + 1)) ++
|
('a' to 'z').map(l => l -> (l - 'a' + 1)) ++
|
||||||
(1 to 0xf).map(i => (i + 0xff70).toChar -> (i + 0x70)) ++
|
(1 to 0xf).map(i => (i + 0xff70).toChar -> (i + 0x70)) ++
|
||||||
(0x10 to 0x2f).map(i => (i + 0xff70).toChar -> (i + 0x40)),
|
(0x10 to 0x2f).map(i => (i + 0xff70).toChar -> (i + 0x40)),
|
||||||
StandardKatakanaDecompositions, MinimalEscapeSequencesWithoutBraces
|
StandardKatakanaDecompositions, MinimalEscapeSequencesWithoutBraces ++ Map(
|
||||||
|
"pi" -> List(0x70),
|
||||||
|
"yen" -> List(0x1c),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val Petscii = new TextCodec("PETSCII",
|
val Petscii = new TextCodec("PETSCII", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
0x20.to(0x3f).map(_.toChar).mkString +
|
0x20.to(0x3f).map(_.toChar).mkString +
|
||||||
"@abcdefghijklmnopqrstuvwxyz[£]↑←" +
|
"@abcdefghijklmnopqrstuvwxyz[£]↑←" +
|
||||||
@@ -337,6 +358,8 @@ object TextCodec {
|
|||||||
Map('^' -> 0x5E, '♥' -> 0xD3, '♡' -> 0xD3, '♠' -> 0xC1, '♣' -> 0xD8, '♢' -> 0xDA, '•' -> 0xD1), Map.empty, Map(
|
Map('^' -> 0x5E, '♥' -> 0xD3, '♡' -> 0xD3, '♠' -> 0xC1, '♣' -> 0xD8, '♢' -> 0xDA, '•' -> 0xD1), Map.empty, Map(
|
||||||
"n" -> List(13),
|
"n" -> List(13),
|
||||||
"q" -> List('\"'.toInt),
|
"q" -> List('\"'.toInt),
|
||||||
|
"pound" -> List(0x5c),
|
||||||
|
"pi" -> List(0xdf),
|
||||||
"apos" -> List('\''.toInt),
|
"apos" -> List('\''.toInt),
|
||||||
"up" -> List(0x91),
|
"up" -> List(0x91),
|
||||||
"down" -> List(0x11),
|
"down" -> List(0x11),
|
||||||
@@ -355,7 +378,7 @@ object TextCodec {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val PetsciiJp = new TextCodec("PETSCII-JP",
|
val PetsciiJp = new TextCodec("PETSCII-JP", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
0x20.to(0x3f).map(_.toChar).mkString +
|
0x20.to(0x3f).map(_.toChar).mkString +
|
||||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]↑←" +
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]↑←" +
|
||||||
@@ -385,6 +408,8 @@ object TextCodec {
|
|||||||
"n" -> List(13),
|
"n" -> List(13),
|
||||||
"q" -> List('\"'.toInt),
|
"q" -> List('\"'.toInt),
|
||||||
"apos" -> List('\''.toInt),
|
"apos" -> List('\''.toInt),
|
||||||
|
"yen" -> List(0x5c),
|
||||||
|
"pi" -> List(0xb0),
|
||||||
"up" -> List(0x91),
|
"up" -> List(0x91),
|
||||||
"down" -> List(0x11),
|
"down" -> List(0x11),
|
||||||
"left" -> List(0x9d),
|
"left" -> List(0x9d),
|
||||||
@@ -402,7 +427,18 @@ object TextCodec {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val OldPetscii = new TextCodec("Old PETSCII",
|
val Vectrex = new TextCodec("Vectrex", 0x80,
|
||||||
|
"\ufffd" * 32 +
|
||||||
|
0x20.to(0x3f).map(_.toChar).mkString +
|
||||||
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" +
|
||||||
|
"\ufffd↑\ufffd↓\ufffd\ufffd\ufffd©\ufffd\ufffd\ufffd\ufffd∞",
|
||||||
|
('a' to 'z').map(l => l -> l.toUpper.toInt).toMap,
|
||||||
|
Map.empty, Map(
|
||||||
|
"copy" -> List('g'.toInt)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val OldPetscii = new TextCodec("Old PETSCII", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
0x20.to(0x3f).map(_.toChar).mkString +
|
0x20.to(0x3f).map(_.toChar).mkString +
|
||||||
"@abcdefghijklmnopqrstuvwxyz[\\]↑←" +
|
"@abcdefghijklmnopqrstuvwxyz[\\]↑←" +
|
||||||
@@ -413,6 +449,7 @@ object TextCodec {
|
|||||||
Map('^' -> 0x5E, '♥' -> 0xD3, '♡' -> 0xD3, '♠' -> 0xC1, '♣' -> 0xC8, '♢' -> 0xDA, '•' -> 0xD1), Map.empty, Map(
|
Map('^' -> 0x5E, '♥' -> 0xD3, '♡' -> 0xD3, '♠' -> 0xC1, '♣' -> 0xC8, '♢' -> 0xDA, '•' -> 0xD1), Map.empty, Map(
|
||||||
"n" -> List(13),
|
"n" -> List(13),
|
||||||
"q" -> List('\"'.toInt),
|
"q" -> List('\"'.toInt),
|
||||||
|
"pi" -> List(0xdf),
|
||||||
"apos" -> List('\''.toInt),
|
"apos" -> List('\''.toInt),
|
||||||
"up" -> List(0x91),
|
"up" -> List(0x91),
|
||||||
"down" -> List(0x11),
|
"down" -> List(0x11),
|
||||||
@@ -423,7 +460,7 @@ object TextCodec {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val OriginalPetscii = new TextCodec("Original PETSCII",
|
val OriginalPetscii = new TextCodec("Original PETSCII", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
0x20.to(0x3f).map(_.toChar).mkString +
|
0x20.to(0x3f).map(_.toChar).mkString +
|
||||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]↑←" +
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]↑←" +
|
||||||
@@ -435,6 +472,7 @@ object TextCodec {
|
|||||||
"n" -> List(13),
|
"n" -> List(13),
|
||||||
"q" -> List('\"'.toInt),
|
"q" -> List('\"'.toInt),
|
||||||
"apos" -> List('\''.toInt),
|
"apos" -> List('\''.toInt),
|
||||||
|
"pi" -> List(0xdf),
|
||||||
"up" -> List(0x91),
|
"up" -> List(0x91),
|
||||||
"down" -> List(0x11),
|
"down" -> List(0x11),
|
||||||
"left" -> List(0x9d),
|
"left" -> List(0x9d),
|
||||||
@@ -444,7 +482,7 @@ object TextCodec {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val Atascii = new TextCodec("ATASCII",
|
val Atascii = new TextCodec("ATASCII", 0,
|
||||||
"♡" +
|
"♡" +
|
||||||
"\ufffd" * 15 +
|
"\ufffd" * 15 +
|
||||||
"♣\ufffd–\ufffd•" +
|
"♣\ufffd–\ufffd•" +
|
||||||
@@ -461,7 +499,7 @@ object TextCodec {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val AtasciiScreencodes = new TextCodec("ATASCII-Screen",
|
val AtasciiScreencodes = new TextCodec("ATASCII-Screen", 0,
|
||||||
0x20.to(0x3f).map(_.toChar).mkString +
|
0x20.to(0x3f).map(_.toChar).mkString +
|
||||||
0x40.to(0x5f).map(_.toChar).mkString +
|
0x40.to(0x5f).map(_.toChar).mkString +
|
||||||
"♡" +
|
"♡" +
|
||||||
@@ -472,14 +510,18 @@ object TextCodec {
|
|||||||
Map('♥' -> 0x40, '·' -> 0x54), Map.empty, MinimalEscapeSequencesWithoutBraces
|
Map('♥' -> 0x40, '·' -> 0x54), Map.empty, MinimalEscapeSequencesWithoutBraces
|
||||||
)
|
)
|
||||||
|
|
||||||
val Bbc = new TextCodec("BBC",
|
val Bbc = new TextCodec("BBC", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
0x20.to(0x5f).map(_.toChar).mkString +
|
0x20.to(0x5f).map(_.toChar).mkString +
|
||||||
"£" + 0x61.to(0x7E).map(_.toChar).mkString + "©",
|
"£" + 0x61.to(0x7E).map(_.toChar).mkString + "©",
|
||||||
Map('↑' -> '^'.toInt), Map.empty, MinimalEscapeSequencesWithBraces + ("n" -> List(13))
|
Map('↑' -> '^'.toInt), Map.empty, MinimalEscapeSequencesWithBraces ++ Map(
|
||||||
|
"n" -> List(13),
|
||||||
|
"pound" -> List(0x60),
|
||||||
|
"copy" -> List(0x7f),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val Sinclair = new TextCodec("Sinclair",
|
val Sinclair = new TextCodec("Sinclair", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
0x20.to(0x5f).map(_.toChar).mkString +
|
0x20.to(0x5f).map(_.toChar).mkString +
|
||||||
"£" + 0x61.to(0x7E).map(_.toChar).mkString + "©",
|
"£" + 0x61.to(0x7E).map(_.toChar).mkString + "©",
|
||||||
@@ -487,6 +529,8 @@ object TextCodec {
|
|||||||
"n" -> List(13),
|
"n" -> List(13),
|
||||||
"q" -> List('\"'.toInt),
|
"q" -> List('\"'.toInt),
|
||||||
"apos" -> List('\''.toInt),
|
"apos" -> List('\''.toInt),
|
||||||
|
"pound" -> List(0x60),
|
||||||
|
"copy" -> List(0x7f),
|
||||||
"lbrace" -> List('{'.toInt),
|
"lbrace" -> List('{'.toInt),
|
||||||
"rbrace" -> List('}'.toInt),
|
"rbrace" -> List('}'.toInt),
|
||||||
"up" -> List(11),
|
"up" -> List(11),
|
||||||
@@ -521,7 +565,7 @@ object TextCodec {
|
|||||||
"ミムメモヤユヨラリルレロワン゛゜"
|
"ミムメモヤユヨラリルレロワン゛゜"
|
||||||
|
|
||||||
//noinspection ScalaUnnecessaryParentheses
|
//noinspection ScalaUnnecessaryParentheses
|
||||||
val Jis = new TextCodec("JIS-X-0201",
|
val Jis = new TextCodec("JIS-X-0201", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
' '.to('Z').mkString +
|
' '.to('Z').mkString +
|
||||||
"[¥]^_" +
|
"[¥]^_" +
|
||||||
@@ -535,10 +579,13 @@ object TextCodec {
|
|||||||
"\ufffd" * 3 + "\\",
|
"\ufffd" * 3 + "\\",
|
||||||
Map('¯' -> '~'.toInt, '‾' -> '~'.toInt, '♥' -> 0xE9) ++
|
Map('¯' -> '~'.toInt, '‾' -> '~'.toInt, '♥' -> 0xE9) ++
|
||||||
1.to(0x3F).map(i => (i + 0xff60).toChar -> (i + 0xA0)).toMap,
|
1.to(0x3F).map(i => (i + 0xff60).toChar -> (i + 0xA0)).toMap,
|
||||||
StandardKatakanaDecompositions, MinimalEscapeSequencesWithBraces + ("n" -> List(13, 10))
|
StandardKatakanaDecompositions, MinimalEscapeSequencesWithBraces ++ Map(
|
||||||
|
"n" -> List(13, 10),
|
||||||
|
"yen" -> List(0x5c)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val MsxWest = new TextCodec("MSX-International",
|
val MsxWest = new TextCodec("MSX-International", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
(0x20 to 0x7e).map(_.toChar).mkString("") +
|
(0x20 to 0x7e).map(_.toChar).mkString("") +
|
||||||
"\ufffd" +
|
"\ufffd" +
|
||||||
@@ -552,10 +599,14 @@ object TextCodec {
|
|||||||
"≡±≥≤\ufffd\ufffd÷\ufffd\ufffd\ufffd\ufffd\ufffdⁿ²",
|
"≡±≥≤\ufffd\ufffd÷\ufffd\ufffd\ufffd\ufffd\ufffdⁿ²",
|
||||||
Map('ß' -> 0xE1, '¦' -> 0x7C),
|
Map('ß' -> 0xE1, '¦' -> 0x7C),
|
||||||
Map('♥' -> "\u0001C", '♡' -> "\u0001C", '♢' -> "\u0001D", '♢' -> "\u0001D", '♣' -> "\u0001E", '♠' -> "\u0001F", '·' -> "\u0001G") ,
|
Map('♥' -> "\u0001C", '♡' -> "\u0001C", '♢' -> "\u0001D", '♢' -> "\u0001D", '♣' -> "\u0001E", '♠' -> "\u0001F", '·' -> "\u0001G") ,
|
||||||
MinimalEscapeSequencesWithBraces + ("n" -> List(13, 10))
|
MinimalEscapeSequencesWithBraces ++ Map(
|
||||||
|
"n" -> List(13, 10),
|
||||||
|
"pound" -> List(0x9c),
|
||||||
|
"yen" -> List(0x9d),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val MsxRu = new TextCodec("MSX-RU",
|
val MsxRu = new TextCodec("MSX-RU", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
(0x20 to 0x7e).map(_.toChar).mkString("") +
|
(0x20 to 0x7e).map(_.toChar).mkString("") +
|
||||||
"\ufffd" +
|
"\ufffd" +
|
||||||
@@ -571,7 +622,7 @@ object TextCodec {
|
|||||||
MinimalEscapeSequencesWithBraces + ("n" -> List(13, 10))
|
MinimalEscapeSequencesWithBraces + ("n" -> List(13, 10))
|
||||||
)
|
)
|
||||||
|
|
||||||
val MsxJp = new TextCodec("MSX-JP",
|
val MsxJp = new TextCodec("MSX-JP", 0,
|
||||||
"\ufffd" * 32 +
|
"\ufffd" * 32 +
|
||||||
(0x20 to 0x7e).map(c => if (c == 0x5c) '¥' else c.toChar).mkString("") +
|
(0x20 to 0x7e).map(c => if (c == 0x5c) '¥' else c.toChar).mkString("") +
|
||||||
"\ufffd" +
|
"\ufffd" +
|
||||||
@@ -605,7 +656,10 @@ object TextCodec {
|
|||||||
'小' -> "\u0001_"
|
'小' -> "\u0001_"
|
||||||
) ++
|
) ++
|
||||||
StandardHiraganaDecompositions ++ StandardKatakanaDecompositions,
|
StandardHiraganaDecompositions ++ StandardKatakanaDecompositions,
|
||||||
MinimalEscapeSequencesWithBraces + ("n" -> List(13, 10))
|
MinimalEscapeSequencesWithBraces ++ Map(
|
||||||
|
"n" -> List(13, 10),
|
||||||
|
"yen" -> List(0x5c)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val lossyAlternatives: Map[Char, List[String]] = {
|
val lossyAlternatives: Map[Char, List[String]] = {
|
||||||
|
Reference in New Issue
Block a user