mirror of
https://github.com/irmen/prog8.git
synced 2025-02-02 19:32:21 +00:00
implemented strlen() function
This commit is contained in:
parent
f2397527f1
commit
d9d83248fe
@ -916,7 +916,7 @@ asmsub print_w (word value @ AY) -> clobbers(A,Y) -> () {
|
||||
}
|
||||
|
||||
asmsub input_chars (uword buffer @ AY) -> clobbers(A) -> (ubyte @ Y) {
|
||||
; ---- Input a string (max. 80 chars) from the keyboard. Returns length in Y.
|
||||
; ---- Input a string (max. 80 chars) from the keyboard. Returns length in Y. (string is terminated with a 0 byte as well)
|
||||
; It assumes the keyboard is selected as I/O channel!
|
||||
|
||||
%asm {{
|
||||
|
@ -1112,8 +1112,7 @@ _gtequ dey
|
||||
_result_minw .word 0
|
||||
.pend
|
||||
|
||||
|
||||
func_len_str .proc
|
||||
func_strlen .proc
|
||||
; -- push length of 0-terminated string on stack
|
||||
jsr peek_address
|
||||
ldy #0
|
||||
@ -1126,15 +1125,6 @@ func_len_str .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_len_strp .proc
|
||||
; -- push length of pascal-string on stack
|
||||
jsr peek_address
|
||||
ldy #0
|
||||
lda (c64.SCRATCH_ZPWORD1),y ; first byte is length
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_rnd .proc
|
||||
; -- put a random ubyte on the estack
|
||||
jsr math.randbyte
|
||||
|
@ -296,7 +296,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
DataType.STR, DataType.STR_S -> {
|
||||
val rawStr = heap.get(v.second.heapId).str!!
|
||||
val bytes = encodeStr(rawStr, v.second.type).map { "$" + it.toString(16).padStart(2, '0') }
|
||||
out("${v.first}\t; ${v.second.type} \"${escape(rawStr)}\"")
|
||||
out("${v.first}\t; ${v.second.type} \"${escape(rawStr).replace("\u0000", "<NULL>")}\"")
|
||||
for (chunk in bytes.chunked(16))
|
||||
out(" .byte " + chunk.joinToString())
|
||||
}
|
||||
|
@ -1055,11 +1055,12 @@ class Petscii {
|
||||
val lookup = if(lowercase) encodingPetsciiLowercase else encodingPetsciiUppercase
|
||||
return text.map {
|
||||
val petscii = lookup[it]
|
||||
if(petscii==null) {
|
||||
val case = if(lowercase) "lower" else "upper"
|
||||
petscii?.toShort() ?: if(it=='\u0000')
|
||||
0.toShort()
|
||||
else {
|
||||
val case = if (lowercase) "lower" else "upper"
|
||||
throw CharConversionException("no ${case}case Petscii character for '$it'")
|
||||
}
|
||||
petscii.toShort()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1072,11 +1073,12 @@ class Petscii {
|
||||
val lookup = if(lowercase) encodingScreencodeLowercase else encodingScreencodeUppercase
|
||||
return text.map{
|
||||
val screencode = lookup[it]
|
||||
if(screencode==null) {
|
||||
val case = if(lowercase) "lower" else "upper"
|
||||
screencode?.toShort() ?: if(it=='\u0000')
|
||||
0.toShort()
|
||||
else {
|
||||
val case = if (lowercase) "lower" else "upper"
|
||||
throw CharConversionException("no ${case}Screencode character for '$it'")
|
||||
}
|
||||
screencode.toShort()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,7 @@ val BuiltinFunctions = mapOf(
|
||||
BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)),
|
||||
BuiltinFunctionParam("numwords", setOf(DataType.UWORD)),
|
||||
BuiltinFunctionParam("wordvalue", setOf(DataType.UWORD, DataType.WORD))), null),
|
||||
"strlen" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.UBYTE, ::builtinStrlen),
|
||||
"vm_write_memchr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", setOf(DataType.UWORD))), null),
|
||||
"vm_write_memstr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", setOf(DataType.UWORD))), null),
|
||||
"vm_write_num" to FunctionSignature(false, listOf(BuiltinFunctionParam("number", NumericDatatypes)), null),
|
||||
@ -302,6 +303,20 @@ private fun builtinAvg(args: List<IExpression>, position: Position, namespace:IN
|
||||
return numericLiteral(result, args[0].position)
|
||||
}
|
||||
|
||||
private fun builtinStrlen(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue {
|
||||
if (args.size != 1)
|
||||
throw SyntaxError("strlen requires one argument", position)
|
||||
val argument = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException()
|
||||
if(argument.type !in StringDatatypes)
|
||||
throw SyntaxError("strlen must have string argument", position)
|
||||
val string = argument.strvalue(heap)
|
||||
val zeroIdx = string.indexOf('\u0000')
|
||||
return if(zeroIdx>=0)
|
||||
LiteralValue.optimalInteger(zeroIdx, position=position)
|
||||
else
|
||||
LiteralValue.optimalInteger(string.length, position=position)
|
||||
}
|
||||
|
||||
private fun builtinLen(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue {
|
||||
// note: in some cases the length is > 255 and then we have to return a UWORD type instead of a UBYTE.
|
||||
if(args.size!=1)
|
||||
|
@ -51,6 +51,7 @@ enum class Syscall(val callNr: Short) {
|
||||
FUNC_RNDF(91), // push a random float on the stack (between 0.0 and 1.0)
|
||||
FUNC_LEN_STR(105),
|
||||
FUNC_LEN_STRS(106),
|
||||
FUNC_STRLEN(107),
|
||||
FUNC_ANY_B(109),
|
||||
FUNC_ANY_W(110),
|
||||
FUNC_ANY_F(111),
|
||||
@ -1736,7 +1737,11 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
DataType.ARRAY_B -> array.array!![index] = value.integerValue()
|
||||
DataType.STR, DataType.STR_S -> {
|
||||
val chars = array.str!!.toCharArray()
|
||||
chars[index] = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0]
|
||||
val ps = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0]
|
||||
if(ps=='\ufffe') // undefined
|
||||
chars[index] = '\u0000'
|
||||
else
|
||||
chars[index] = ps
|
||||
heap.update(variable.heapId, chars.joinToString(""))
|
||||
}
|
||||
else -> throw VmExecutionException("not a proper array/string var with byte elements")
|
||||
@ -1994,6 +1999,13 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val text = heap.get(strPtr).str!!
|
||||
evalstack.push(Value(DataType.UBYTE, text.length))
|
||||
}
|
||||
Syscall.FUNC_STRLEN -> {
|
||||
val strPtr = evalstack.pop().integerValue()
|
||||
val text = heap.get(strPtr).str!!
|
||||
val zeroIdx = text.indexOf('\u0000')
|
||||
val len = if(zeroIdx>=0) zeroIdx else text.length
|
||||
evalstack.push(Value(DataType.UBYTE, len))
|
||||
}
|
||||
Syscall.FUNC_READ_FLAGS -> {
|
||||
val carry = if(P_carry) 1 else 0
|
||||
val zero = if(P_zero) 2 else 0
|
||||
|
@ -639,6 +639,11 @@ len(x)
|
||||
Note: this can be different from the number of *bytes* in memory if the datatype isn't a byte.
|
||||
Note: lengths of strings and arrays are determined at compile-time! If your program modifies the actual
|
||||
length of the string during execution, the value of len(string) may no longer be correct!
|
||||
(use strlen function if you want to dynamically determine the length)
|
||||
|
||||
strlen(str)
|
||||
Number of bytes in the string. This value is determined during runtime and counts upto
|
||||
the first terminating 0 byte in the string, regardless of the size of the string during compilation time.
|
||||
|
||||
lsb(x)
|
||||
Get the least significant byte of the word x. Equivalent to the cast "x as ubyte".
|
||||
|
@ -32,7 +32,6 @@
|
||||
float minutes = floor(clock_seconds / 60)
|
||||
clock_seconds = floor(clock_seconds - minutes * 60.0)
|
||||
|
||||
; @todo implement strcpy/strcat/strlen?
|
||||
c64scr.print("system time in ti$ is ")
|
||||
c64flt.print_f(hours)
|
||||
c64.CHROUT(':')
|
||||
|
@ -8,6 +8,27 @@
|
||||
|
||||
sub start() {
|
||||
|
||||
c64.CLEARSCR() ; @todo empty stack exception in vm
|
||||
str s1 = "hello\u0000abcd12345"
|
||||
str_s s2 = "hellothere\u0000bcde"
|
||||
|
||||
c64scr.print(s1)
|
||||
c64.CHROUT('\n')
|
||||
c64scr.print_ub(len(s1))
|
||||
c64.CHROUT('\n')
|
||||
c64scr.print_ub(strlen(s1))
|
||||
c64.CHROUT('\n')
|
||||
s1[2]=0
|
||||
c64scr.print_ub(strlen(s1))
|
||||
c64.CHROUT('\n')
|
||||
c64.CHROUT('\n')
|
||||
|
||||
c64scr.print_ub(len(s2))
|
||||
c64.CHROUT('\n')
|
||||
c64scr.print_ub(strlen(s2))
|
||||
c64.CHROUT('\n')
|
||||
s2[7]=0
|
||||
c64scr.print_ub(strlen(s2))
|
||||
c64.CHROUT('\n')
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user