mirror of
https://github.com/KarolS/millfork.git
synced 2024-09-27 12:57:41 +00:00
Character literals
This commit is contained in:
parent
95375378ed
commit
d6995091cf
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
* Added multiple new text codecs.
|
* Added multiple new text codecs.
|
||||||
|
|
||||||
|
* Added character literals.
|
||||||
|
|
||||||
* Fixed several bugs, most importantly invalid offsets for branching instructions.
|
* Fixed several bugs, most importantly invalid offsets for branching instructions.
|
||||||
|
|
||||||
* Other improvements.
|
* Other improvements.
|
||||||
|
@ -36,7 +36,7 @@ Currently available encodings:
|
|||||||
|
|
||||||
* `bbc` – BBC Micro and ZX Spectrum character set
|
* `bbc` – BBC Micro and ZX Spectrum character set
|
||||||
|
|
||||||
* `jis` – JIS X 0201
|
* `jis` or `jisx` – JIS X 0201
|
||||||
|
|
||||||
* `iso_de`, `iso_no`, `iso_se`, `iso_yu` – various variants of ISO/IEC-646
|
* `iso_de`, `iso_no`, `iso_se`, `iso_yu` – various variants of ISO/IEC-646
|
||||||
|
|
||||||
@ -46,6 +46,13 @@ 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 `scr` for strings you're copying to screen memory directly.
|
and `scr` for strings you're copying to screen memory directly.
|
||||||
|
|
||||||
|
## Character literals
|
||||||
|
|
||||||
|
Character literals are surrounded by single quotes and followed by the name of the encoding:
|
||||||
|
|
||||||
|
'x' ascii
|
||||||
|
|
||||||
|
From the type system point of view, they are constants of type byte.
|
||||||
|
|
||||||
## Array initialisers
|
## Array initialisers
|
||||||
|
|
||||||
|
@ -53,6 +53,28 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
|
|
||||||
// def operator: P[String] = P(CharsWhileIn("!-+*/><=~|&^", min=1).!) // TODO: only valid operators
|
// def operator: P[String] = P(CharsWhileIn("!-+*/><=~|&^", min=1).!) // TODO: only valid operators
|
||||||
|
|
||||||
|
private val invalidCharLiteralTypes = Set[Int](
|
||||||
|
Character.LINE_SEPARATOR,
|
||||||
|
Character.PARAGRAPH_SEPARATOR,
|
||||||
|
Character.CONTROL,
|
||||||
|
Character.PRIVATE_USE,
|
||||||
|
Character.SURROGATE,
|
||||||
|
Character.UNASSIGNED)
|
||||||
|
|
||||||
|
def charAtom: P[LiteralExpression] = for {
|
||||||
|
p <- position()
|
||||||
|
c <- "'" ~/ CharPred(c => c >= ' ' && !invalidCharLiteralTypes(Character.getType(c))).! ~/ "'"
|
||||||
|
co <- HWS ~ codec
|
||||||
|
} yield {
|
||||||
|
co.encode(Some(p), c.charAt(0)) match {
|
||||||
|
case List(value) =>
|
||||||
|
LiteralExpression(value, 1)
|
||||||
|
case _ =>
|
||||||
|
ErrorReporting.error(s"Character `$c` cannot be encoded as one byte", Some(p))
|
||||||
|
LiteralExpression(0, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: 3-byte types
|
// TODO: 3-byte types
|
||||||
def size(value: Int, wordLiteral: Boolean, longLiteral: Boolean): Int =
|
def size(value: Int, wordLiteral: Boolean, longLiteral: Boolean): Int =
|
||||||
if (value > 255 || value < -128 || wordLiteral)
|
if (value > 255 || value < -128 || wordLiteral)
|
||||||
@ -120,7 +142,7 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
LiteralExpression(value, size(value, s.length > 4, s.length > 8)).pos(p)
|
LiteralExpression(value, size(value, s.length > 4, s.length > 8)).pos(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
val literalAtom: P[LiteralExpression] = binaryAtom | hexAtom | octalAtom | quaternaryAtom | decimalAtom
|
val literalAtom: P[LiteralExpression] = charAtom | binaryAtom | hexAtom | octalAtom | quaternaryAtom | decimalAtom
|
||||||
|
|
||||||
val atom: P[Expression] = P(literalAtom | (position() ~ identifier).map { case (p, i) => VariableExpression(i).pos(p) })
|
val atom: P[Expression] = P(literalAtom | (position() ~ identifier).map { case (p, i) => VariableExpression(i).pos(p) })
|
||||||
|
|
||||||
@ -200,7 +222,7 @@ case class MfParser(filename: String, input: String, currentDirectory: String, o
|
|||||||
|
|
||||||
val doubleQuotedString: P[List[Char]] = P("\"" ~/ CharsWhile(c => c != '\"' && c != '\n' && c != '\r').! ~ "\"").map(_.toList)
|
val doubleQuotedString: P[List[Char]] = P("\"" ~/ CharsWhile(c => c != '\"' && c != '\n' && c != '\r').! ~ "\"").map(_.toList)
|
||||||
|
|
||||||
val codec: P[TextCodec] = P(position() ~ identifier).map {
|
def codec: P[TextCodec] = P(position() ~ identifier).map {
|
||||||
case (_, "ascii") => TextCodec.Ascii
|
case (_, "ascii") => TextCodec.Ascii
|
||||||
case (_, "petscii") => TextCodec.Petscii
|
case (_, "petscii") => TextCodec.Petscii
|
||||||
case (_, "pet") => TextCodec.Petscii
|
case (_, "pet") => TextCodec.Petscii
|
||||||
|
25
src/test/scala/millfork/test/TextCodecSuite.scala
Normal file
25
src/test/scala/millfork/test/TextCodecSuite.scala
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package millfork.test
|
||||||
|
|
||||||
|
import millfork.test.emu.{EmuBenchmarkRun, EmuUnoptimizedRun}
|
||||||
|
import org.scalatest.{FunSuite, Matchers}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karol Stasiak
|
||||||
|
*/
|
||||||
|
class TextCodecSuite extends FunSuite with Matchers {
|
||||||
|
|
||||||
|
test("Char literals") {
|
||||||
|
val m = EmuUnoptimizedRun(
|
||||||
|
"""
|
||||||
|
| void main() {
|
||||||
|
| if 'a'ascii != 'a' ascii { poke($bfff, 0) }
|
||||||
|
| if '¥'jis != '\' ascii { poke($bffe, 0) }
|
||||||
|
| if '£'pet != '\' ascii { poke($bffd, 0) }
|
||||||
|
| if '£'bbc != 'é' iso_se { poke($bffc, 0) }
|
||||||
|
| }
|
||||||
|
| macro asm void poke(word const addr, byte a) {
|
||||||
|
| STA addr
|
||||||
|
| }
|
||||||
|
""".stripMargin)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user