no more duplicate auto heap vars, attempt at automatic insertion of & expression for subroutine params

This commit is contained in:
Irmen de Jong 2019-04-05 13:14:19 +02:00
parent b200f9945f
commit 87446028e0
5 changed files with 54 additions and 49 deletions

View File

@ -814,8 +814,11 @@ private class AstChecker(private val namespace: INameScope,
else {
for (arg in args.withIndex().zip(target.parameters)) {
val argDt = arg.first.value.resultingDatatype(namespace, heap)
if(argDt!=null && !argDt.assignableTo(arg.second.type))
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} has invalid type $argDt, expected ${arg.second.type}", position))
if(argDt!=null && !argDt.assignableTo(arg.second.type)) {
// for asm subroutines having STR param it's okay to provide a UWORD too (pointer value)
if(!(target.isAsmSubroutine && arg.second.type in StringDatatypes && argDt==DataType.UWORD))
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index + 1} has invalid type $argDt, expected ${arg.second.type}", position))
}
if(target.isAsmSubroutine) {
if (target.asmParameterRegisters[arg.first.index].registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.XY, RegisterOrPair.X)) {

View File

@ -14,13 +14,13 @@ fun Module.checkIdentifiers(namespace: INameScope) {
// add any anonymous variables for heap values that are used,
// and replace an iterable literalvalue by identifierref to new local variable
for (variable in checker.anonymousVariablesFromHeap) {
for (variable in checker.anonymousVariablesFromHeap.values) {
val scope = variable.first.definingScope()
scope.statements.add(variable.second)
val parent = variable.first.parent
when {
parent is Assignment && parent.value === variable.first -> {
val idref = IdentifierReference(listOf("$autoHeapValuePrefix${variable.first.heapId}"), variable.first.position)
val idref = IdentifierReference(listOf("$${variable.first.heapId}"), variable.first.position)
idref.linkParents(parent)
parent.value = idref
}
@ -217,7 +217,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro
}
internal val anonymousVariablesFromHeap = mutableSetOf<Pair<LiteralValue, VarDecl>>()
internal val anonymousVariablesFromHeap = mutableMapOf<String, Pair<LiteralValue, VarDecl>>()
override fun process(literalValue: LiteralValue): LiteralValue {
@ -225,10 +225,10 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro
// a literal value that's not declared as a variable, which refers to something on the heap.
// we need to introduce an auto-generated variable for this to be able to refer to the value!
val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, "$autoHeapValuePrefix${literalValue.heapId}", literalValue, literalValue.position)
anonymousVariablesFromHeap.add(Pair(literalValue, variable))
anonymousVariablesFromHeap[variable.name] = Pair(literalValue, variable)
}
return super.process(literalValue)
}
}
private const val autoHeapValuePrefix = "auto_heap_value_"
internal const val autoHeapValuePrefix = "auto_heap_value_"

View File

@ -3,7 +3,7 @@ package prog8.ast
import prog8.compiler.HeapValues
fun Module.reorderStatements(namespace: INameScope, heap: HeapValues) {
val initvalueCreator = VarInitValueCreator()
val initvalueCreator = VarInitValueAndPointerOfCreator(namespace)
this.process(initvalueCreator)
val checker = StatementReorderer(namespace, heap)
@ -203,7 +203,7 @@ private class StatementReorderer(private val namespace: INameScope, private val
}
private class VarInitValueCreator: IAstProcessor {
private class VarInitValueAndPointerOfCreator(private val namespace: INameScope): IAstProcessor {
// Replace the var decl with an assignment and add a new vardecl with the default constant value.
// This makes sure the variables get reset to the intended value on a next run of the program.
// Variable decls without a value don't get this treatment, which means they retain the last
@ -211,6 +211,9 @@ private class VarInitValueCreator: IAstProcessor {
// This is done in a separate step because it interferes with the namespace lookup of symbols
// in other ast processors.
// Also takes care to insert PointerOf (&) expression where required (string params to a UWORD function param etc).
private val vardeclsToAdd = mutableMapOf<INameScope, MutableList<VarDecl>>()
override fun process(module: Module) {
@ -252,4 +255,33 @@ private class VarInitValueCreator: IAstProcessor {
return decl
}
override fun process(functionCall: FunctionCall): IExpression {
val targetStatement = functionCall.target.targetStatement(namespace) as? Subroutine
if(targetStatement!=null)
addPointerToIfNeeded(targetStatement, functionCall.arglist, functionCall)
return functionCall
}
override fun process(functionCallStatement: FunctionCallStatement): IStatement {
val targetStatement = functionCallStatement.target.targetStatement(namespace) as? Subroutine
if(targetStatement!=null)
addPointerToIfNeeded(targetStatement, functionCallStatement.arglist, functionCallStatement)
return functionCallStatement
}
private fun addPointerToIfNeeded(subroutine: Subroutine, arglist: MutableList<IExpression>, parent: Node) {
// functions that accept UWORD and are given an array type, or string, will receive the Pointer (memory location) of that value instead.
for(argparam in subroutine.parameters.withIndex().zip(arglist)) {
if(argparam.first.value.type==DataType.UWORD || argparam.first.value.type in StringDatatypes) {
val strvalue = argparam.second as? LiteralValue
if(strvalue!=null && strvalue.isString) {
val idref = IdentifierReference(listOf("$autoHeapValuePrefix${strvalue.heapId}"), strvalue.position) // TODO why does this result later in "pointer-of operand must be the name of a heap variable"
val pointerExpr = PointerOf(idref, strvalue.position)
pointerExpr.linkParents(arglist[argparam.first.index].parent)
arglist[argparam.first.index] = pointerExpr
}
}
}
}
}

View File

@ -1089,19 +1089,7 @@ internal class Compiler(private val rootModule: Module,
translate(arg.first)
prog.instr(Opcode.POP_REGAX_WORD)
}
// TODO auto-converting str/float/array to their pointer value should be done by explicitly rewriting the Ast into a pointer-of expression, once that is available
DataType.STR, DataType.STR_S -> {
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGAX_WORD)
}
DataType.FLOAT -> {
pushFloatAddress(arg.first)
prog.instr(Opcode.POP_REGAX_WORD)
}
in ArrayDatatypes -> {
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGAX_WORD)
}
in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition")
else -> TODO("pass parameter of type $paramDt in registers AX at $callPosition")
}
}
@ -1124,19 +1112,7 @@ internal class Compiler(private val rootModule: Module,
translate(arg.first)
prog.instr(Opcode.POP_REGAY_WORD)
}
// TODO auto-converting str/float/array to their pointer value should be done by explicitly rewriting the Ast into a pointer-of expression, once that is available
DataType.STR, DataType.STR_S -> {
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGAY_WORD)
}
DataType.FLOAT -> {
pushFloatAddress(arg.first)
prog.instr(Opcode.POP_REGAY_WORD)
}
in ArrayDatatypes -> {
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGAY_WORD)
}
in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition")
else -> TODO("pass parameter of type $paramDt in registers AY at $callPosition")
}
}
@ -1163,19 +1139,7 @@ internal class Compiler(private val rootModule: Module,
translate(arg.first)
prog.instr(Opcode.POP_REGXY_WORD)
}
// TODO auto-converting str/float/array to their pointer value should be done by explicitly rewriting the Ast into a pointer-of expression, once that is available
DataType.STR, DataType.STR_S -> {
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGXY_WORD)
}
DataType.FLOAT -> {
pushFloatAddress(arg.first)
prog.instr(Opcode.POP_REGXY_WORD)
}
in ArrayDatatypes -> {
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGXY_WORD)
}
in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition")
else -> TODO("pass parameter of type $paramDt in registers XY at $callPosition")
}
}

View File

@ -106,9 +106,15 @@
;uword[4] pointers = [&array1, &array2, &string1, &string2] ; @todo make it possible to initialize array with pointers
;ptrsubasm("moet werken") ; @todo rewrite ast into pointer-of expression (and remove special cases from Compiler)
;pointersub("moet werken") ; @todo rewrite ast into pointer-of expression (and remove special cases from Compiler)
;myprintasm("moet werken3") ; @todo rewrite ast into pointer-of expression (and remove special cases from Compiler)
myprintasm("moet werken3")
myprintasm("moet werken3")
myprintasm("moet werken4")
c64.CHROUT('\n')
ptrsubasm(&array1)
ptrsubasm(&array2)