strlen and strings with zeros in them should terminate at the zero

This commit is contained in:
Irmen de Jong 2019-06-26 02:34:43 +02:00
parent f49eefad6f
commit 060e05c868
7 changed files with 74 additions and 49 deletions

View File

@ -3,6 +3,7 @@ package prog8.astvm
import prog8.ast.*
import prog8.compiler.RuntimeValue
import prog8.compiler.RuntimeValueRange
import prog8.compiler.target.c64.Petscii
import java.awt.EventQueue
@ -217,9 +218,24 @@ class AstVm(val program: Program) {
if(value.type!=DataType.FLOAT)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
DataType.STR, DataType.STR_S -> {
if(value.type !in ByteDatatypes)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
else -> throw VmExecutionException("strange array type ${array.type}")
}
array.array!![index.integerValue()] = value.numericValue()
if(array.type in ArrayDatatypes)
array.array!![index.integerValue()] = value.numericValue()
else if(array.type in StringDatatypes) {
val index = index.integerValue()
val newchr = Petscii.decodePetscii(listOf(value.numericValue().toShort()), true)
val newstr = array.str!!.replaceRange(index, index+1, newchr)
val ident = stmt.definingScope().lookup(target.arrayindexed.identifier.nameInSource, stmt) as? VarDecl
?: throw VmExecutionException("can't find assignment target ${target.identifier}")
val identScope = ident.definingScope()
program.heap.update(array.heapId!!, newstr)
runtimeVariables.set(identScope, ident.name, RuntimeValue(array.type, str=newstr, heapId=array.heapId))
}
}
target.register!=null -> {
runtimeVariables.set(program.namespace, target.register.name, value)

View File

@ -14,6 +14,15 @@ class BuiltinFunctions {
"rnd" -> RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255)
"rndw" -> RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535)
"rndf" -> RuntimeValue(DataType.FLOAT, rnd.nextDouble())
"lsb" -> RuntimeValue(DataType.UBYTE, args[0].integerValue() and 255)
"msb" -> RuntimeValue(DataType.UBYTE, (args[0].integerValue() ushr 8) and 255)
"strlen" -> {
val zeroIndex = args[0].str!!.indexOf(0.toChar())
if(zeroIndex>=0)
RuntimeValue(DataType.UBYTE, zeroIndex)
else
RuntimeValue(DataType.UBYTE, args[0].str!!.length)
}
"memset" -> {
val target = args[0].array!!
val amount = args[1].integerValue()

View File

@ -61,7 +61,8 @@ class BitmapScreenPanel : KeyListener, JPanel() {
g2d.drawLine(x1, y1, x2, y2)
}
fun printText(text: String, color: Int, lowercase: Boolean) {
val lines = text.split('\n')
val t2 = text.substringBefore(0.toChar())
val lines = t2.split('\n')
for(line in lines.withIndex()) {
printTextSingleLine(line.value, color, lowercase)
if(line.index<lines.size-1) {
@ -124,6 +125,8 @@ class BitmapScreenPanel : KeyListener, JPanel() {
g2d.clearRect(8*clearx, 8*y, 8, 8)
}
for(sc in Petscii.encodeScreencode(text, lowercase)) {
if(sc==0.toShort())
break
setChar(xx++, y, sc)
}
}

View File

@ -9,12 +9,12 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v
override fun process(program: Program) {
// define the three registers as global variables
runtimeVariables.define(program.namespace, Register.A.name, RuntimeValue(DataType.UBYTE, 0))
runtimeVariables.define(program.namespace, Register.X.name, RuntimeValue(DataType.UBYTE, 0))
runtimeVariables.define(program.namespace, Register.X.name, RuntimeValue(DataType.UBYTE, 255))
runtimeVariables.define(program.namespace, Register.Y.name, RuntimeValue(DataType.UBYTE, 0))
val globalpos = Position("<<global>>", 0, 0, 0)
val vdA = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.A.name, LiteralValue.optimalInteger(0, globalpos), globalpos)
val vdX = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.X.name, LiteralValue.optimalInteger(0, globalpos), globalpos)
val vdX = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.X.name, LiteralValue.optimalInteger(255, globalpos), globalpos)
val vdY = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.Y.name, LiteralValue.optimalInteger(0, globalpos), globalpos)
vdA.linkParents(program.namespace)
vdX.linkParents(program.namespace)
@ -27,25 +27,33 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v
}
override fun process(decl: VarDecl): IStatement {
if(decl.type==VarDeclType.VAR) {
val value = when (decl.datatype) {
in NumericDatatypes -> {
if(decl.value !is LiteralValue) {
TODO("evaluate vardecl expression $decl")
//RuntimeValue(decl.datatype, num = evaluate(decl.value!!, program, runtimeVariables, executeSubroutine).numericValue())
} else {
when(decl.type) {
VarDeclType.VAR -> {
val value = when (decl.datatype) {
in NumericDatatypes -> {
if(decl.value !is LiteralValue) {
TODO("evaluate vardecl expression $decl")
//RuntimeValue(decl.datatype, num = evaluate(decl.value!!, program, runtimeVariables, executeSubroutine).numericValue())
} else {
RuntimeValue.from(decl.value as LiteralValue, heap)
}
}
in StringDatatypes -> {
RuntimeValue.from(decl.value as LiteralValue, heap)
}
in ArrayDatatypes -> {
RuntimeValue.from(decl.value as LiteralValue, heap)
}
else -> throw VmExecutionException("weird type ${decl.datatype}")
}
in StringDatatypes -> {
RuntimeValue.from(decl.value as LiteralValue, heap)
}
in ArrayDatatypes -> {
RuntimeValue.from(decl.value as LiteralValue, heap)
}
else -> throw VmExecutionException("weird type ${decl.datatype}")
runtimeVariables.define(decl.definingScope(), decl.name, value)
}
VarDeclType.MEMORY -> {
// TODO register memory mapped vars?
}
VarDeclType.CONST -> {
// consts should have been const-folded away
}
runtimeVariables.define(decl.definingScope(), decl.name, value)
}
return super.process(decl)
}

View File

@ -9,7 +9,7 @@ class Petscii {
// character tables used from https://github.com/dj51d/cbmcodecs
private val decodingPetsciiLowercase = arrayOf(
'\ufffe', // 0x00 -> UNDEFINED
'\u0000', // 0x00 -> \u0000
'\ufffe', // 0x01 -> UNDEFINED
'\ufffe', // 0x02 -> UNDEFINED
'\ufffe', // 0x03 -> UNDEFINED
@ -268,7 +268,7 @@ class Petscii {
)
private val decodingPetsciiUppercase = arrayOf(
'\ufffe', // 0x00 -> UNDEFINED
'\u0000', // 0x00 -> \u0000
'\ufffe', // 0x01 -> UNDEFINED
'\ufffe', // 0x02 -> UNDEFINED
'\ufffe', // 0x03 -> UNDEFINED

View File

@ -268,6 +268,14 @@ class TestZeropage {
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestPetscii {
@Test
fun testZero() {
assertThat(Petscii.encodePetscii("\u0000", true), equalTo(listOf<Short>(0)))
assertThat(Petscii.encodePetscii("\u0000", false), equalTo(listOf<Short>(0)))
assertThat(Petscii.decodePetscii(listOf(0), true), equalTo("\u0000"))
assertThat(Petscii.decodePetscii(listOf(0), false), equalTo("\u0000"))
}
@Test
fun testLowercase() {
assertThat(Petscii.encodePetscii("hello WORLD 123 @!£", true), equalTo(

View File

@ -6,39 +6,20 @@
~ main {
sub start() {
c64scr.print_ub(rnd())
uword uw = $ab34
str name = "irmen de jong"
c64scr.print_ub(len(name))
c64.CHROUT('\n')
c64scr.print_ub(rnd())
c64scr.print_ub(strlen(name))
c64.CHROUT('\n')
c64scr.print_ub(rnd())
c64scr.print(name)
c64.CHROUT('\n')
c64scr.print_uw(rndw())
c64.CHROUT('\n')
c64scr.print_uw(rndw())
c64.CHROUT('\n')
c64flt.print_f(rndf())
c64.CHROUT('\n')
c64flt.print_f(rndf())
name[6] = 0
c64scr.print_ub(strlen(name))
c64.CHROUT('\n')
c64scr.print(name)
c64.CHROUT('\n')
A=rnd()
c64scr.print_ub(A)
c64.CHROUT('\n')
A=rnd()
c64scr.print_ub(A)
c64.CHROUT('\n')
A=rnd()
c64scr.print_ub(A)
c64.CHROUT('\n')
A=rnd()
c64scr.print_ub(A)
c64.CHROUT('\n')
A=rnd()
c64scr.print_ub(A)
c64.CHROUT('\n')
A=rnd()
c64scr.print_ub(A)
c64.CHROUT('\n')
}
}