1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-07 21:28:59 +00:00

Standard library improvements

This commit is contained in:
Karol Stasiak 2018-12-19 19:01:53 +01:00
parent 30d18fba01
commit 05884f2c7b
17 changed files with 236 additions and 68 deletions

View File

@ -39,9 +39,11 @@
* [`stdlib` module](stdlib/stdlib.md) * [`stdlib` module](stdlib/stdlib.md)
* [`string` module](stdlib/string.md)
* [Modules for reading input devices](stdlib/input.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) * [Definitions available on only some platforms](stdlib/frequent.md)

View File

@ -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 * `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 ### Built-in preprocessor functions and operators
The `defined` function returns 1 if the feature is defined, 0 otherwise. The `defined` function returns 1 if the feature is defined, 0 otherwise.

View File

@ -16,6 +16,19 @@ Moves the cursor to the next line.
Available for: all computer targets. 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()` #### `void bell()`
Beeps. Beeps.

View File

@ -2,7 +2,7 @@
## stdio ## 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. It requires an implementation of `void putchar(byte a)` and therefore works only on targets with console output.
#### `void putstr(pointer str, byte len)` #### `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`. 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). 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. #### `enum error_number`
If the string is longer than 255 bytes, then the behaviour is undefined (might even crash).
Standard error codes. All codes other than `err_ok` suggest that the last operation failed.
#### `error_number errno`
The result of the last operation.

View File

@ -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`.

View File

@ -5,22 +5,25 @@ void main() {
word a word a
word b word b
putstrz("enter first number:{n}"z) putstrz("enter first number:"z)
new_line()
a = readword() a = readword()
while readword_err != 0 { while errno != err_ok {
putstrz("that wasn't a number, try again:{n}"z) putstrz("that wasn't a number, try again:"z)
new_line()
a = readword() a = readword()
} }
putstrz("enter second number:{n}"z) putstrz("enter second number:{n}"z)
b = readword() b = readword()
while readword_err != 0 { while errno != err_ok {
putstrz("that wasn't a number, try again:{n}"z) putstrz("that wasn't a number, try again:"z)
new_line()
b = readword() b = readword()
} }
putstrz("the sum is:{n}"z) putstrz("the sum is:"z)
a += b new_line()
putword(a) putword(a + b)
putchar(13) new_line()
} }

View File

@ -20,6 +20,7 @@ KEYBOARD=1
; TODO: ? ; TODO: ?
JOYSTICKS=1 JOYSTICKS=1
HAS_BITMAP_MODE=1 HAS_BITMAP_MODE=1
PAL=1
[output] [output]
style=single style=single

View File

@ -5,41 +5,26 @@
#endif #endif
import c64_kernal import c64_kernal
import err
// print a 16-bit number on the standard output // print a 16-bit number on the standard output
asm void putword(word xa) @$BDCD extern asm void putword_basic(word xa) @$BDCD extern
asm void readline() @$A560 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 const pointer readline_out = $200
byte readword_err inline word readword_basic() {
return strz2word(readline_basic())
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
}
} }
alias readword = readword_basic!

11
include/err.mfk Normal file
View File

@ -0,0 +1,11 @@
enum error_number {
err_ok
err_fail
err_numberformat
err_outofmemory
err_domain
err_range
}
error_number errno

View File

@ -19,6 +19,7 @@ KEYBOARD=1
; TODO: ; TODO:
JOYSTICKS=1 JOYSTICKS=1
HAS_BITMAP_MODE=1 HAS_BITMAP_MODE=1
NTSC=1
[output] [output]
style=single style=single

View File

@ -27,3 +27,28 @@ void putstrz(pointer str) {
#endif #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')
}
}

View File

@ -7,3 +7,7 @@ import stdlib_i80
#else #else
#warn Unsupported architecture #warn Unsupported architecture
#endif #endif
#if PAL && NTSC
#warn PAL and NTSC enabled simultaneously
#endif

View File

@ -29,7 +29,7 @@ asm byte hi_nibble_to_hex(byte a) {
LSR LSR
LSR LSR
LSR LSR
JMP lo_nibble_to_hex ? JMP lo_nibble_to_hex
} }
asm byte lo_nibble_to_hex(byte a) { 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 BCC _lo_nibble_to_hex_lbl
ADC #$6 // carry is set ADC #$6 // carry is set
_lo_nibble_to_hex_lbl: _lo_nibble_to_hex_lbl:
RTS ? RTS
} }
macro asm void panic() { macro asm void panic() {

View File

@ -1,23 +1,39 @@
import err
#if ARCH_I80 #if ARCH_I80
import string_fastpointers
byte strzlen(pointer str) {
pointer end
end = str
while end[0] != 0 {
end += 1
}
return lo(end - str)
}
#else #else
import string_fastindices
#endif
byte strzlen(pointer str) {
byte index word strz2word(pointer str) {
index = 0 byte i
while str[index] != 0 { byte char
index += 1 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

View File

@ -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
}

View File

@ -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
}

View File

@ -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("true", NumericConstant(1, 0), trueType), None)
addThing(ConstantThing("false", NumericConstant(0, 0), falseType), None) addThing(ConstantThing("false", NumericConstant(0, 0), falseType), None)
addThing(ConstantThing("__zeropage_usage", UnexpandedConstant("__zeropage_usage", 1), b), 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(ConstantThing("$0000", NumericConstant(0, 2), p), None)
addThing(FlagBooleanType("set_carry", addThing(FlagBooleanType("set_carry",
BranchingOpcodeMapping(Opcode.BCS, IfFlagSet(ZFlag.C)), BranchingOpcodeMapping(Opcode.BCS, IfFlagSet(ZFlag.C)),