mirror of
https://github.com/KarolS/millfork.git
synced 2025-03-06 00:29:49 +00:00
Standard library improvements
This commit is contained in:
parent
30d18fba01
commit
05884f2c7b
@ -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)
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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`.
|
@ -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()
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ KEYBOARD=1
|
||||
; TODO: ?
|
||||
JOYSTICKS=1
|
||||
HAS_BITMAP_MODE=1
|
||||
PAL=1
|
||||
|
||||
[output]
|
||||
style=single
|
||||
|
@ -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!
|
||||
|
11
include/err.mfk
Normal file
11
include/err.mfk
Normal file
@ -0,0 +1,11 @@
|
||||
enum error_number {
|
||||
err_ok
|
||||
err_fail
|
||||
err_numberformat
|
||||
err_outofmemory
|
||||
err_domain
|
||||
err_range
|
||||
}
|
||||
|
||||
|
||||
error_number errno
|
@ -19,6 +19,7 @@ KEYBOARD=1
|
||||
; TODO:
|
||||
JOYSTICKS=1
|
||||
HAS_BITMAP_MODE=1
|
||||
NTSC=1
|
||||
|
||||
[output]
|
||||
style=single
|
||||
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
@ -7,3 +7,7 @@ import stdlib_i80
|
||||
#else
|
||||
#warn Unsupported architecture
|
||||
#endif
|
||||
|
||||
#if PAL && NTSC
|
||||
#warn PAL and NTSC enabled simultaneously
|
||||
#endif
|
||||
|
@ -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() {
|
||||
|
@ -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
|
37
include/string_fastindices.mfk
Normal file
37
include/string_fastindices.mfk
Normal 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
|
||||
}
|
37
include/string_fastpointers.mfk
Normal file
37
include/string_fastpointers.mfk
Normal 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
|
||||
}
|
@ -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)),
|
||||
|
Loading…
x
Reference in New Issue
Block a user