mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
strlen and strings with zeros in them should terminate at the zero
This commit is contained in:
parent
f49eefad6f
commit
060e05c868
@ -3,6 +3,7 @@ package prog8.astvm
|
|||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.compiler.RuntimeValue
|
||||||
import prog8.compiler.RuntimeValueRange
|
import prog8.compiler.RuntimeValueRange
|
||||||
|
import prog8.compiler.target.c64.Petscii
|
||||||
import java.awt.EventQueue
|
import java.awt.EventQueue
|
||||||
|
|
||||||
|
|
||||||
@ -217,9 +218,24 @@ class AstVm(val program: Program) {
|
|||||||
if(value.type!=DataType.FLOAT)
|
if(value.type!=DataType.FLOAT)
|
||||||
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
|
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}")
|
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 -> {
|
target.register!=null -> {
|
||||||
runtimeVariables.set(program.namespace, target.register.name, value)
|
runtimeVariables.set(program.namespace, target.register.name, value)
|
||||||
|
@ -14,6 +14,15 @@ class BuiltinFunctions {
|
|||||||
"rnd" -> RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255)
|
"rnd" -> RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255)
|
||||||
"rndw" -> RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535)
|
"rndw" -> RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535)
|
||||||
"rndf" -> RuntimeValue(DataType.FLOAT, rnd.nextDouble())
|
"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" -> {
|
"memset" -> {
|
||||||
val target = args[0].array!!
|
val target = args[0].array!!
|
||||||
val amount = args[1].integerValue()
|
val amount = args[1].integerValue()
|
||||||
|
@ -61,7 +61,8 @@ class BitmapScreenPanel : KeyListener, JPanel() {
|
|||||||
g2d.drawLine(x1, y1, x2, y2)
|
g2d.drawLine(x1, y1, x2, y2)
|
||||||
}
|
}
|
||||||
fun printText(text: String, color: Int, lowercase: Boolean) {
|
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()) {
|
for(line in lines.withIndex()) {
|
||||||
printTextSingleLine(line.value, color, lowercase)
|
printTextSingleLine(line.value, color, lowercase)
|
||||||
if(line.index<lines.size-1) {
|
if(line.index<lines.size-1) {
|
||||||
@ -124,6 +125,8 @@ class BitmapScreenPanel : KeyListener, JPanel() {
|
|||||||
g2d.clearRect(8*clearx, 8*y, 8, 8)
|
g2d.clearRect(8*clearx, 8*y, 8, 8)
|
||||||
}
|
}
|
||||||
for(sc in Petscii.encodeScreencode(text, lowercase)) {
|
for(sc in Petscii.encodeScreencode(text, lowercase)) {
|
||||||
|
if(sc==0.toShort())
|
||||||
|
break
|
||||||
setChar(xx++, y, sc)
|
setChar(xx++, y, sc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,12 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v
|
|||||||
override fun process(program: Program) {
|
override fun process(program: Program) {
|
||||||
// define the three registers as global variables
|
// define the three registers as global variables
|
||||||
runtimeVariables.define(program.namespace, Register.A.name, RuntimeValue(DataType.UBYTE, 0))
|
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))
|
runtimeVariables.define(program.namespace, Register.Y.name, RuntimeValue(DataType.UBYTE, 0))
|
||||||
|
|
||||||
val globalpos = Position("<<global>>", 0, 0, 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 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)
|
val vdY = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.Y.name, LiteralValue.optimalInteger(0, globalpos), globalpos)
|
||||||
vdA.linkParents(program.namespace)
|
vdA.linkParents(program.namespace)
|
||||||
vdX.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 {
|
override fun process(decl: VarDecl): IStatement {
|
||||||
if(decl.type==VarDeclType.VAR) {
|
when(decl.type) {
|
||||||
val value = when (decl.datatype) {
|
VarDeclType.VAR -> {
|
||||||
in NumericDatatypes -> {
|
val value = when (decl.datatype) {
|
||||||
if(decl.value !is LiteralValue) {
|
in NumericDatatypes -> {
|
||||||
TODO("evaluate vardecl expression $decl")
|
if(decl.value !is LiteralValue) {
|
||||||
//RuntimeValue(decl.datatype, num = evaluate(decl.value!!, program, runtimeVariables, executeSubroutine).numericValue())
|
TODO("evaluate vardecl expression $decl")
|
||||||
} else {
|
//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)
|
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 -> {
|
runtimeVariables.define(decl.definingScope(), decl.name, value)
|
||||||
RuntimeValue.from(decl.value as LiteralValue, heap)
|
}
|
||||||
}
|
VarDeclType.MEMORY -> {
|
||||||
in ArrayDatatypes -> {
|
// TODO register memory mapped vars?
|
||||||
RuntimeValue.from(decl.value as LiteralValue, heap)
|
}
|
||||||
}
|
VarDeclType.CONST -> {
|
||||||
else -> throw VmExecutionException("weird type ${decl.datatype}")
|
// consts should have been const-folded away
|
||||||
}
|
}
|
||||||
runtimeVariables.define(decl.definingScope(), decl.name, value)
|
|
||||||
}
|
}
|
||||||
return super.process(decl)
|
return super.process(decl)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ class Petscii {
|
|||||||
// character tables used from https://github.com/dj51d/cbmcodecs
|
// character tables used from https://github.com/dj51d/cbmcodecs
|
||||||
|
|
||||||
private val decodingPetsciiLowercase = arrayOf(
|
private val decodingPetsciiLowercase = arrayOf(
|
||||||
'\ufffe', // 0x00 -> UNDEFINED
|
'\u0000', // 0x00 -> \u0000
|
||||||
'\ufffe', // 0x01 -> UNDEFINED
|
'\ufffe', // 0x01 -> UNDEFINED
|
||||||
'\ufffe', // 0x02 -> UNDEFINED
|
'\ufffe', // 0x02 -> UNDEFINED
|
||||||
'\ufffe', // 0x03 -> UNDEFINED
|
'\ufffe', // 0x03 -> UNDEFINED
|
||||||
@ -268,7 +268,7 @@ class Petscii {
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val decodingPetsciiUppercase = arrayOf(
|
private val decodingPetsciiUppercase = arrayOf(
|
||||||
'\ufffe', // 0x00 -> UNDEFINED
|
'\u0000', // 0x00 -> \u0000
|
||||||
'\ufffe', // 0x01 -> UNDEFINED
|
'\ufffe', // 0x01 -> UNDEFINED
|
||||||
'\ufffe', // 0x02 -> UNDEFINED
|
'\ufffe', // 0x02 -> UNDEFINED
|
||||||
'\ufffe', // 0x03 -> UNDEFINED
|
'\ufffe', // 0x03 -> UNDEFINED
|
||||||
|
@ -268,6 +268,14 @@ class TestZeropage {
|
|||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
class TestPetscii {
|
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
|
@Test
|
||||||
fun testLowercase() {
|
fun testLowercase() {
|
||||||
assertThat(Petscii.encodePetscii("hello WORLD 123 @!£", true), equalTo(
|
assertThat(Petscii.encodePetscii("hello WORLD 123 @!£", true), equalTo(
|
||||||
|
@ -6,39 +6,20 @@
|
|||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
c64scr.print_ub(rnd())
|
uword uw = $ab34
|
||||||
|
str name = "irmen de jong"
|
||||||
|
|
||||||
|
c64scr.print_ub(len(name))
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
c64scr.print_ub(rnd())
|
c64scr.print_ub(strlen(name))
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
c64scr.print_ub(rnd())
|
c64scr.print(name)
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
c64scr.print_uw(rndw())
|
name[6] = 0
|
||||||
c64.CHROUT('\n')
|
c64scr.print_ub(strlen(name))
|
||||||
c64scr.print_uw(rndw())
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64flt.print_f(rndf())
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64flt.print_f(rndf())
|
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
|
c64scr.print(name)
|
||||||
c64.CHROUT('\n')
|
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')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user