diff --git a/docs/lang/literals.md b/docs/lang/literals.md index d5c52dde..f9eeb91f 100644 --- a/docs/lang/literals.md +++ b/docs/lang/literals.md @@ -35,19 +35,33 @@ If there is no encoding name specified, then the `default` encoding is used. Two encoding names are special and refer to platform-specific encodings: `default` and `scr`. +## Zero-terminated strings + 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 `nullchar`. -The exact value of `nullchar` is encoding-dependent: +This means that the string will have a string terminator appended, usually a single byte. +The exact value of that byte is encoding-dependent: * in the `vectrex` encoding it's 128, * in the `zx80` encoding it's 1, * in the `zx81` encoding it's 11, * in the `utf16be` and `utf16le` encodings it's exceptionally two bytes: 0, 0 -* in other encodings it's 0 (this might be a subject to change in future versions). - +* in other encodings it's 0 (this **will** be a subject to change in future versions). "this is a zero-terminated string" asciiz "this is also a zero-terminated string"z +The byte constant `nullchar` is defined to be equal to the string terminator in the `default` encoding (or, in other words, to `'{nullchar}'`) +and the byte constant `nullchar_scr` is defined to be equal to the string terminator in the `scr` encoding (`'{nullchar}'scr`). + +You can override the values for `nullchar` and `nullchar_scr` +by defining preprocesor features `NULLCHAR` and `NULLCHAR_SCR` respectively. + +Warning: If you define UTF-16 to be you default or screen encoding, you will encounter several problems: + +* `nullchar` and `nullchar_scr` will still be bytes, equal to zero. +* the `string` module in the Millfork standard library will not work correctly + +## Escape sequences and miscellaneous compatibility issues + Most characters between the quotes are interpreted literally. To allow characters that cannot be inserted normally, each encoding may define escape sequences. diff --git a/docs/lang/preprocessor.md b/docs/lang/preprocessor.md index a32f8d33..dee5498e 100644 --- a/docs/lang/preprocessor.md +++ b/docs/lang/preprocessor.md @@ -56,6 +56,12 @@ The following features are defined based on the chosen CPU and compilation optio * `ENCODING_SAME` - 1 if the encodings `default` and `src` are the same, 0 otherwise. +* `NULLCHAR_SAME` - 1 if the encodings `default` and `src` have the same string terminator, 0 otherwise. + +* `NULLCHAR` – the value of the `nullchar` constant + +* `NULLCHAR_SRC` – the value of the `nullchar_src` constant + * `INIT_RW_MEMORY` – 1 if the option `ram_init_segment` is defined, 0 otherwise. See [the ROM vs RAM guide](../api/rom-vs-ram.md) for more information. diff --git a/docs/lang/text.md b/docs/lang/text.md index 371ed714..5d7968ec 100644 --- a/docs/lang/text.md +++ b/docs/lang/text.md @@ -81,7 +81,14 @@ Some escape sequences may expand to multiple characters. For example, in several * `{program_name_upper}` – the same, but uppercased -* `{nullchar}` – the null terminator for strings (`"{nullchar}"` is equivalent to `""z`) +* `{nullchar}` – the null terminator for strings (`"{nullchar}"` is equivalent to `""z`). +The exact value of `{nullchar}` is encoding-dependent: + + * in the `vectrex` encoding it's `{x80}`, + * in the `zx80` encoding it's `{x01}`, + * in the `zx81` encoding it's `{x0b}`, + * in the `utf16be` and `utf16le` encodings it's exceptionally two bytes: `{x00}{x00}` + * in other encodings it's `{x00}` (this **will** be a subject to change in future versions). ##### Available only in some encodings diff --git a/src/main/scala/millfork/Platform.scala b/src/main/scala/millfork/Platform.scala index cc257ab4..f1295958 100644 --- a/src/main/scala/millfork/Platform.scala +++ b/src/main/scala/millfork/Platform.scala @@ -281,7 +281,8 @@ object Platform { log.fatal(s"Invalid label file format: `$debugOutputFormatName`")) val builtInFeatures = builtInCpuFeatures(cpu) ++ Map( - "ENCODING_SAME" -> toLong(codec.name == srcCodec.name) + "ENCODING_SAME" -> toLong(codec.name == srcCodec.name), + "NULLCHAR_SAME" -> toLong(codec.stringTerminator == srcCodec.stringTerminator) ) import scala.collection.JavaConverters._ diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index 2b217511..b07436e9 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -439,8 +439,11 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa addThing(ConstantThing("nullptr.raw.hi", nullptrConstant.hiByte.quickSimplify, b), None) addThing(ConstantThing("nullptr.raw.lo", nullptrConstant.loByte.quickSimplify, b), None) val nullcharValue = options.features.getOrElse("NULLCHAR", options.platform.defaultCodec.stringTerminator.head.toLong) + val nullcharScrValue = options.features.getOrElse("NULLCHAR_SCR", options.platform.screenCodec.stringTerminator.head.toLong) val nullcharConstant = NumericConstant(nullcharValue, 1) + val nullcharScrConstant = NumericConstant(nullcharScrValue, 1) addThing(ConstantThing("nullchar", nullcharConstant, b), None) + addThing(ConstantThing("nullchar_scr", nullcharScrConstant, b), None) val __zeropage_usage = UnexpandedConstant("__zeropage_usage", 1) addThing(ConstantThing("__zeropage_usage", __zeropage_usage, b), None) def addUnexpandedWordConstant(name: String): Unit = {