diff --git a/docs/index.md b/docs/index.md index 3f2aa70d..37e42dea 100644 --- a/docs/index.md +++ b/docs/index.md @@ -39,9 +39,11 @@ * [`stdlib` module](stdlib/stdlib.md) +* [`string` module](stdlib/string.md) + * [Modules for reading input devices](stdlib/input.md) -* [Other cross-platform modules](stdlib/other.md) +* [Other cross-platform modules (`err`, `stdio`)](stdlib/other.md) * [Definitions available on only some platforms](stdlib/frequent.md) diff --git a/docs/lang/preprocessor.md b/docs/lang/preprocessor.md index 130a085c..5bd60d94 100644 --- a/docs/lang/preprocessor.md +++ b/docs/lang/preprocessor.md @@ -84,6 +84,10 @@ The following features are defined based on the chosen CPU and compilation optio * `CPM` – 1 if the target is CP/M, 0 otherwise +* `NTSC` – 1 if the target is NTSC, 0 otherwise + +* `PAL` – 1 if the target is PAL, 0 otherwise + ### Built-in preprocessor functions and operators The `defined` function returns 1 if the feature is defined, 0 otherwise. diff --git a/docs/stdlib/frequent.md b/docs/stdlib/frequent.md index 1d855de7..79c3a4e8 100644 --- a/docs/stdlib/frequent.md +++ b/docs/stdlib/frequent.md @@ -16,6 +16,19 @@ Moves the cursor to the next line. Available for: all computer targets. +#### `pointer readline()` + +Reads a line from the console and returns a pointer to a null-terminated string. +The string is valid only until next read from the console. + +Available for: Commodore 64 with `c64_basic` module. + +#### `word readword()` + +Reads a 16-bit unsigned integer from the console. + +Available for: Commodore 64 with `c64_basic` module. + #### `void bell()` Beeps. diff --git a/docs/stdlib/other.md b/docs/stdlib/other.md index c66f3114..2186335a 100644 --- a/docs/stdlib/other.md +++ b/docs/stdlib/other.md @@ -2,7 +2,7 @@ ## stdio -The `stdio` module automatically imports the `string` module. +The `stdio` module automatically imports the `string` and `err` modules. It requires an implementation of `void putchar(byte a)` and therefore works only on targets with console output. #### `void putstr(pointer str, byte len)` @@ -14,9 +14,13 @@ Prints a string of length `len` located at address `str`. Prints a null-terminated string located at address `str`. If the string is longer than 255 bytes, then the behaviour is undefined (might even crash). -## string -#### `byte strzlen(pointer str)` +## err -Calculates the length of a null-terminated string. -If the string is longer than 255 bytes, then the behaviour is undefined (might even crash). +#### `enum error_number` + +Standard error codes. All codes other than `err_ok` suggest that the last operation failed. + +#### `error_number errno` + +The result of the last operation. diff --git a/docs/stdlib/string.md b/docs/stdlib/string.md index e69de29b..2d72ef7f 100644 --- a/docs/stdlib/string.md +++ b/docs/stdlib/string.md @@ -0,0 +1,25 @@ +[< back to index](../index.md) + +## string + +The `string` module automatically imports the `err` module. + +#### `byte strzlen(pointer str)` + +Calculates the length of a null-terminated string. +If the string is longer than 255 bytes, then the behaviour is undefined (might even crash). + +#### `sbyte strzcmp(pointer str1, pointer str2)` + +Compares two strings. Returns 0 if equal, non-0 if not equal. +If any of the strings is longer than 255 bytes, then the behaviour is undefined (might even crash). + +#### `void strzcopy(pointer dest, pointer src)` + +Copies the source null-terminated string into the destination buffer. +If the source string is longer than 255 bytes, then the behaviour is undefined (might even crash). + +#### `word strz2word(pointer str)` + +Converts a null-terminated string to a number. +Sets `errno`. diff --git a/examples/c64/calculator.mfk b/examples/c64/calculator.mfk index 62dbc9e6..a8878cef 100644 --- a/examples/c64/calculator.mfk +++ b/examples/c64/calculator.mfk @@ -5,22 +5,25 @@ void main() { word a word b - putstrz("enter first number:{n}"z) + putstrz("enter first number:"z) + new_line() a = readword() - while readword_err != 0 { - putstrz("that wasn't a number, try again:{n}"z) + while errno != err_ok { + putstrz("that wasn't a number, try again:"z) + new_line() a = readword() } putstrz("enter second number:{n}"z) b = readword() - while readword_err != 0 { - putstrz("that wasn't a number, try again:{n}"z) + while errno != err_ok { + putstrz("that wasn't a number, try again:"z) + new_line() b = readword() } - putstrz("the sum is:{n}"z) - a += b - putword(a) - putchar(13) + putstrz("the sum is:"z) + new_line() + putword(a + b) + new_line() } diff --git a/include/bbcmicro.ini b/include/bbcmicro.ini index 0e65afb9..292e8d6a 100644 --- a/include/bbcmicro.ini +++ b/include/bbcmicro.ini @@ -20,6 +20,7 @@ KEYBOARD=1 ; TODO: ? JOYSTICKS=1 HAS_BITMAP_MODE=1 +PAL=1 [output] style=single diff --git a/include/c64_basic.mfk b/include/c64_basic.mfk index bef806dd..5cd3634a 100644 --- a/include/c64_basic.mfk +++ b/include/c64_basic.mfk @@ -5,41 +5,26 @@ #endif import c64_kernal +import err // print a 16-bit number on the standard output -asm void putword(word xa) @$BDCD extern -asm void readline() @$A560 extern +asm void putword_basic(word xa) @$BDCD extern + +//alias putword = putword_basic! + +asm void __readline_basic() @$A560 extern + +pointer readline_basic() { + __readline_basic() + return readline_out +} + +alias readline = readline_basic! + const pointer readline_out = $200 -byte readword_err - -word readword() { - readline() - readword_err = 0 - word result - word four - result = 0 - byte char - byte i - i = 0 - while true { - char = readline_out[i] - if char == 0 { - if i == 0 { - readword_err = 1 - } - return result - } - if 48 <= char <= 48+9 { - four = result - four <<= 2 - result += four - result <<= 1 - result += char - 48 - } else { - readword_err = 1 - return result - } - i += 1 - } +inline word readword_basic() { + return strz2word(readline_basic()) } + +alias readword = readword_basic! diff --git a/include/err.mfk b/include/err.mfk new file mode 100644 index 00000000..fb478040 --- /dev/null +++ b/include/err.mfk @@ -0,0 +1,11 @@ +enum error_number { + err_ok + err_fail + err_numberformat + err_outofmemory + err_domain + err_range +} + + +error_number errno diff --git a/include/pc88.ini b/include/pc88.ini index a8305f17..3dc71942 100644 --- a/include/pc88.ini +++ b/include/pc88.ini @@ -19,6 +19,7 @@ KEYBOARD=1 ; TODO: JOYSTICKS=1 HAS_BITMAP_MODE=1 +NTSC=1 [output] style=single diff --git a/include/stdio.mfk b/include/stdio.mfk index d3958453..ff5d084b 100644 --- a/include/stdio.mfk +++ b/include/stdio.mfk @@ -27,3 +27,28 @@ void putstrz(pointer str) { #endif +void putword(word w) { + byte digits + byte lastdigit + digits = 0 + word mask + for mask:[40000,4000,400,40,4] { + lastdigit = 0 + while w >= mask { + w -= mask + lastdigit += 4 + } + mask >>= 2 + while w >= mask { + w -= mask + lastdigit += 1 + } + if digits != 0 || lastdigit != 0 { + putchar('0' + lastdigit) + digits += 1 + } + } + if digits == 0 { + putchar('0') + } +} diff --git a/include/stdlib.mfk b/include/stdlib.mfk index 29a8b16b..53b64ab5 100644 --- a/include/stdlib.mfk +++ b/include/stdlib.mfk @@ -7,3 +7,7 @@ import stdlib_i80 #else #warn Unsupported architecture #endif + +#if PAL && NTSC +#warn PAL and NTSC enabled simultaneously +#endif diff --git a/include/stdlib_6502.mfk b/include/stdlib_6502.mfk index 5173b7e7..73efc8dd 100644 --- a/include/stdlib_6502.mfk +++ b/include/stdlib_6502.mfk @@ -29,7 +29,7 @@ asm byte hi_nibble_to_hex(byte a) { LSR LSR LSR - JMP lo_nibble_to_hex + ? JMP lo_nibble_to_hex } asm byte lo_nibble_to_hex(byte a) { @@ -40,7 +40,7 @@ asm byte lo_nibble_to_hex(byte a) { BCC _lo_nibble_to_hex_lbl ADC #$6 // carry is set _lo_nibble_to_hex_lbl: - RTS + ? RTS } macro asm void panic() { diff --git a/include/string.mfk b/include/string.mfk index 69b5de45..b2783d36 100644 --- a/include/string.mfk +++ b/include/string.mfk @@ -1,23 +1,39 @@ +import err #if ARCH_I80 - -byte strzlen(pointer str) { - pointer end - end = str - while end[0] != 0 { - end += 1 - } - return lo(end - str) -} - +import string_fastpointers #else +import string_fastindices +#endif -byte strzlen(pointer str) { - byte index - index = 0 - while str[index] != 0 { - index += 1 + +word strz2word(pointer str) { + byte i + byte char + word next + word result + result = 0 + i = 0 + errno = err_ok + while true { + char = str[i] + if char == 0 { + if i == 0 { + errno = err_numberformat + } + return result + } + if '0' <= char <= '0' + 9 { + next = result * 10 + next += char - '0' + if next < result { + errno = err_range + } + result = next + } else { + errno = err_numberformat + return result + } + i += 1 } - return index } -#endif \ No newline at end of file diff --git a/include/string_fastindices.mfk b/include/string_fastindices.mfk new file mode 100644 index 00000000..28bcba8f --- /dev/null +++ b/include/string_fastindices.mfk @@ -0,0 +1,37 @@ +byte strzlen(pointer str) { + byte index + index = 0 + while str[index] != 0 { + index += 1 + } + return index +} + +sbyte strzcmp(pointer str1, pointer str2) { + byte i1 + byte i2 + i1 = 0 + i2 = 0 + while true { + if str1[i1] != str2[i2] { + if str1[i1] < str2[i2] { return -1 } + return 1 + } + if str1[i1] == 0 { + return 0 + } + i1 += 1 + i2 += 1 + } +} + +void strzcopy(pointer dest, pointer src) { + byte i + byte c + i = 0 + do { + c = src[i] + dest[i] = c + i += 1 + } while c != 0 +} diff --git a/include/string_fastpointers.mfk b/include/string_fastpointers.mfk new file mode 100644 index 00000000..87047bd7 --- /dev/null +++ b/include/string_fastpointers.mfk @@ -0,0 +1,37 @@ +#pragma zilog_syntax + +byte strzlen(pointer str) { + pointer end + end = str + while end[0] != 0 { + end += 1 + } + return lo(end - str) +} + +sbyte strzcmp(pointer str1, pointer str2) { + while true { + if str1[0] == 0 { + if str2[0] == 0 { + return 0 + } else { + return -1 + } + } else if str1[0] != str2[0] { + if str1[0] < str2[0] { return -1 } + return 1 + } + str1 += 1 + str2 += 1 + } +} + +void strzcopy(pointer dest, pointer src) { + byte c + do { + c = src[0] + dest[0] = c + src += 1 + dest += 1 + } while c != 0 +} diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index dc6ad32e..09417537 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -353,7 +353,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa addThing(ConstantThing("true", NumericConstant(1, 0), trueType), None) addThing(ConstantThing("false", NumericConstant(0, 0), falseType), None) addThing(ConstantThing("__zeropage_usage", UnexpandedConstant("__zeropage_usage", 1), b), None) - addThing(ConstantThing("__heap_start", UnexpandedConstant("__heap_start", 1), b), None) + addThing(ConstantThing("__heap_start", UnexpandedConstant("__heap_start", 2), p), None) addThing(ConstantThing("$0000", NumericConstant(0, 2), p), None) addThing(FlagBooleanType("set_carry", BranchingOpcodeMapping(Opcode.BCS, IfFlagSet(ZFlag.C)),