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:
parent
30d18fba01
commit
05884f2c7b
@ -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)
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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 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()
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
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:
|
; TODO:
|
||||||
JOYSTICKS=1
|
JOYSTICKS=1
|
||||||
HAS_BITMAP_MODE=1
|
HAS_BITMAP_MODE=1
|
||||||
|
NTSC=1
|
||||||
|
|
||||||
[output]
|
[output]
|
||||||
style=single
|
style=single
|
||||||
|
@ -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')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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() {
|
||||||
|
@ -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
|
|
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("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)),
|
||||||
|
Loading…
Reference in New Issue
Block a user