refactoring

This commit is contained in:
Irmen de Jong 2020-10-22 23:41:16 +02:00
parent 2ba6c9ccbe
commit ff3f985658
11 changed files with 64 additions and 67 deletions

View File

@ -151,8 +151,7 @@ io_error:
filename[0] = 'r' filename[0] = 'r'
filename[1] = ':' filename[1] = ':'
memcopy(newfileptr, &filename+2, flen_new) memcopy(newfileptr, &filename+2, flen_new)
ubyte fis_ix = flen_new+2 ; TODO is temp var for array indexing filename[flen_new+2] = '='
filename[fis_ix] = '='
memcopy(oldfileptr, &filename+3+flen_new, flen_old+1) memcopy(oldfileptr, &filename+3+flen_new, flen_old+1)
c64.SETNAM(3+flen_new+flen_old, filename) c64.SETNAM(3+flen_new+flen_old, filename)
c64.SETLFS(1, drivenumber, 15) c64.SETLFS(1, drivenumber, 15)

View File

@ -1 +1 @@
4.6 4.7-SNAPSHOT

View File

@ -250,19 +250,19 @@ internal class AstChecker(private val program: Program,
err("parameter '${param.first.name}' should be ubyte") err("parameter '${param.first.name}' should be ubyte")
} }
} }
for(ret in subroutine.returntypes.withIndex().zip(subroutine.asmReturnvaluesRegisters)) { subroutine.returntypes.zip(subroutine.asmReturnvaluesRegisters).forEachIndexed { index, pair ->
if(ret.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { if(pair.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) {
if (ret.first.value != DataType.UBYTE && ret.first.value != DataType.BYTE) if (pair.first != DataType.UBYTE && pair.first != DataType.BYTE)
err("return value #${ret.first.index + 1} should be (u)byte") err("return value #${index + 1} should be (u)byte")
} }
else if(ret.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { else if(pair.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
if (ret.first.value != DataType.UWORD && ret.first.value != DataType.WORD if (pair.first != DataType.UWORD && pair.first != DataType.WORD
&& ret.first.value != DataType.STR && ret.first.value !in ArrayDatatypes && ret.first.value != DataType.FLOAT) && pair.first != DataType.STR && pair.first !in ArrayDatatypes && pair.first != DataType.FLOAT)
err("return value #${ret.first.index + 1} should be (u)word/address") err("return value #${index + 1} should be (u)word/address")
} }
else if(ret.second.statusflag!=null) { else if(pair.second.statusflag!=null) {
if (ret.first.value != DataType.UBYTE) if (pair.first != DataType.UBYTE)
err("return value #${ret.first.index + 1} should be ubyte") err("return value #${index + 1} should be ubyte")
} }
} }
@ -984,8 +984,8 @@ internal class AstChecker(private val program: Program,
if(target.regXasResult()) if(target.regXasResult())
errors.warn("subroutine call return value in X register is discarded and replaced by 0", position) errors.warn("subroutine call return value in X register is discarded and replaced by 0", position)
if(target.isAsmSubroutine) { if(target.isAsmSubroutine) {
for (arg in args.withIndex().zip(target.parameters)) { for (arg in args.zip(target.parameters)) {
val argIDt = arg.first.value.inferType(program) val argIDt = arg.first.inferType(program)
if (!argIDt.isKnown) if (!argIDt.isKnown)
return return
} }

View File

@ -279,7 +279,7 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte
} }
// TODO use a pointer loop instead of individual assignments // TODO use a pointer loop instead of individual assignments
return alv.value.withIndex().map { (index, value)-> return alv.value.mapIndexed { index, value ->
val idx = ArrayIndexedExpression(identifier, ArrayIndex(NumericLiteralValue(DataType.UBYTE, index, position), position), position) val idx = ArrayIndexedExpression(identifier, ArrayIndex(NumericLiteralValue(DataType.UBYTE, index, position), position), position)
Assignment(AssignTarget(null, idx, null, position), value, value.position) Assignment(AssignTarget(null, idx, null, position), value, value.position)
} }

View File

@ -116,30 +116,30 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
when(val sub = call.target.targetStatement(scope)) { when(val sub = call.target.targetStatement(scope)) {
is Subroutine -> { is Subroutine -> {
for(arg in sub.parameters.zip(call.args.withIndex())) { sub.parameters.zip(call.args).forEachIndexed { index, pair ->
val argItype = arg.second.value.inferType(program) val argItype = pair.second.inferType(program)
if(argItype.isKnown) { if(argItype.isKnown) {
val argtype = argItype.typeOrElse(DataType.STRUCT) val argtype = argItype.typeOrElse(DataType.STRUCT)
val requiredType = arg.first.type val requiredType = pair.first.type
if (requiredType != argtype) { if (requiredType != argtype) {
if (argtype isAssignableTo requiredType) { if (argtype isAssignableTo requiredType) {
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
call.args[arg.second.index], call.args[index],
TypecastExpression(arg.second.value, requiredType, true, arg.second.value.position), TypecastExpression(pair.second, requiredType, true, pair.second.position),
call as Node) call as Node)
} else if(requiredType == DataType.UWORD && argtype in PassByReferenceDatatypes) { } else if(requiredType == DataType.UWORD && argtype in PassByReferenceDatatypes) {
// we allow STR/ARRAY values in place of UWORD parameters. Take their address instead. // we allow STR/ARRAY values in place of UWORD parameters. Take their address instead.
if(arg.second.value is IdentifierReference) { if(pair.second is IdentifierReference) {
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
call.args[arg.second.index], call.args[index],
AddressOf(arg.second.value as IdentifierReference, arg.second.value.position), AddressOf(pair.second as IdentifierReference, pair.second.position),
call as Node) call as Node)
} }
} else if(arg.second.value is NumericLiteralValue) { } else if(pair.second is NumericLiteralValue) {
val cast = (arg.second.value as NumericLiteralValue).cast(requiredType) val cast = (pair.second as NumericLiteralValue).cast(requiredType)
if(cast.isValid) if(cast.isValid)
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
call.args[arg.second.index], call.args[index],
cast.valueOrZero(), cast.valueOrZero(),
call as Node) call as Node)
} }
@ -149,19 +149,19 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
} }
is BuiltinFunctionStatementPlaceholder -> { is BuiltinFunctionStatementPlaceholder -> {
val func = BuiltinFunctions.getValue(sub.name) val func = BuiltinFunctions.getValue(sub.name)
for (arg in func.parameters.zip(call.args.withIndex())) { func.parameters.zip(call.args).forEachIndexed { index, pair ->
val argItype = arg.second.value.inferType(program) val argItype = pair.second.inferType(program)
if (argItype.isKnown) { if (argItype.isKnown) {
val argtype = argItype.typeOrElse(DataType.STRUCT) val argtype = argItype.typeOrElse(DataType.STRUCT)
if (arg.first.possibleDatatypes.any { argtype == it }) if (pair.first.possibleDatatypes.all { argtype != it }) {
continue for (possibleType in pair.first.possibleDatatypes) {
for (possibleType in arg.first.possibleDatatypes) { if (argtype isAssignableTo possibleType) {
if (argtype isAssignableTo possibleType) { modifications += IAstModification.ReplaceNode(
modifications += IAstModification.ReplaceNode( call.args[index],
call.args[arg.second.index], TypecastExpression(pair.second, possibleType, true, pair.second.position),
TypecastExpression(arg.second.value, possibleType, true, arg.second.value.position), call as Node)
call as Node) break
break }
} }
} }
} }

View File

@ -67,12 +67,12 @@ class VerifyFunctionArgTypes(val program: Program) : IAstVisitor {
if(call.args.size != func.parameters.size) if(call.args.size != func.parameters.size)
return "invalid number of arguments" return "invalid number of arguments"
val paramtypes = func.parameters.map { it.possibleDatatypes } val paramtypes = func.parameters.map { it.possibleDatatypes }
for (x in argtypes.zip(paramtypes).withIndex()) { argtypes.zip(paramtypes).forEachIndexed { index, pair ->
val anyCompatible = x.value.second.any { argTypeCompatible(x.value.first, it) } val anyCompatible = pair.second.any { argTypeCompatible(pair.first, it) }
if (!anyCompatible) { if (!anyCompatible) {
val actual = x.value.first.toString() val actual = pair.first.toString()
val expected = x.value.second.toString() val expected = pair.second.toString()
return "argument ${x.index + 1} type mismatch, was: $actual expected: $expected" return "argument ${index + 1} type mismatch, was: $actual expected: $expected"
} }
} }
} }

View File

@ -252,9 +252,9 @@ open class VarDecl(val type: VarDeclType,
} }
fun flattenStructMembers(): MutableList<Statement> { fun flattenStructMembers(): MutableList<Statement> {
val result = struct!!.statements.withIndex().map { val result = struct!!.statements.mapIndexed { index, statement ->
val member = it.value as VarDecl val member = statement as VarDecl
val initvalue = if(value!=null) (value as ArrayLiteralValue).value[it.index] else null val initvalue = if(value!=null) (value as ArrayLiteralValue).value[index] else null
VarDecl( VarDecl(
VarDeclType.VAR, VarDeclType.VAR,
member.datatype, member.datatype,

View File

@ -33,7 +33,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
// via registers // via registers
if(sub.parameters.size==1) { if(sub.parameters.size==1) {
// just a single parameter, no risk of clobbering registers // just a single parameter, no risk of clobbering registers
argumentViaRegister(sub, sub.parameters.withIndex().single(), stmt.args[0]) argumentViaRegister(sub, IndexedValue(0, sub.parameters.single()), stmt.args[0])
} else { } else {
// multiple register arguments, risk of register clobbering. // multiple register arguments, risk of register clobbering.
// evaluate arguments onto the stack, and load the registers from the evaluated values on the stack. // evaluate arguments onto the stack, and load the registers from the evaluated values on the stack.

View File

@ -775,8 +775,8 @@ memcopy(from, to, numbytes)
memset(address, numbytes, bytevalue) memset(address, numbytes, bytevalue)
Efficiently set a part of memory to the given (u)byte value. Efficiently set a part of memory to the given (u)byte value.
But the most efficient will always be to write a specialized fill routine in assembly yourself! But the most efficient will always be to write a specialized fill routine in assembly yourself!
Note that for clearing the character screen, very fast specialized subroutines are Note that for clearing the screen, very fast specialized subroutines are
available in the ``txt`` block (part of the ``textio`` module) available in the ``textio`` and ``graphics`` library modules.
memsetw(address, numwords, wordvalue) memsetw(address, numwords, wordvalue)
Efficiently set a part of memory to the given (u)word value. Efficiently set a part of memory to the given (u)word value.

View File

@ -2,14 +2,17 @@
TODO TODO
==== ====
- get rid of all other TODO's in the code ;-) - make memset(w) and memcopy able to work with >256 bytes
- implement @stack for asmsub parameters - make memset and memcopy use the ROM routines on the CX16
- calling convention for builtin functions no longer via stack but via statically allocated vars inside the subroutine proc (just as normal subroutines)
- get rid of @stack in asmsub altogether (because all subroutines are no longer using this calling convention anymore)
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_' - make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging) - option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)
- see if we can group some errors together for instance the (now single) errors about unidentified symbols - see if we can group some errors together for instance the (now single) errors about unidentified symbols
- use VIC banking to move up the graphics bitmap memory location. Don't move it under the ROM though as that would require IRQ disabling and memory bank swapping for every bitmap manipulation - use VIC banking to move up the graphics bitmap memory location. Don't move it under the ROM though as that would require IRQ disabling and memory bank swapping for every bitmap manipulation
- add some primitives/subroutines/examples for using custom char sets, copying the default charset. - add some primitives/subroutines/examples for using custom char sets, copying the default charset.
- recursive subroutines? via %option recursive, allocate all params and local vars on estack, don't allow nested subroutines, can begin by first not allowing any local variables just fixing the parameters - some better handling of recursive subroutines? via %option recursive?: allocate all params and local vars on estack, don't allow nested subroutines, can begin by first not allowing any local variables just fixing the parameters
- get rid of all other TODO's in the code ;-)
More optimizations More optimizations
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^

View File

@ -1,26 +1,21 @@
%import textio %import textio
%import conv %import diskio
%import floats
%zeropage basicsafe %zeropage basicsafe
main { main {
sub start() { sub start() {
memcopy($aaaa, $bbbb, 200)
uword[] array = [1, 2, 3] mcp($aaaa, $bbbb, 200)
ubyte ii = 0
ubyte ii2 = ii+2
array[ii+1] = array[ii2] ; TODO fix overwriting the single array index autovar
uword xx
for xx in array {
txt.print_uw(xx)
txt.chrout('\n')
}
testX() testX()
} }
sub mcp(uword from, uword dest, ubyte length) {
txt.print_uw(from)
txt.print_uw(dest)
txt.print_ub(length)
}
asmsub testX() { asmsub testX() {
%asm {{ %asm {{
stx _saveX stx _saveX