mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 03:54:27 +00:00
no more duplicate auto heap vars, attempt at automatic insertion of & expression for subroutine params
This commit is contained in:
parent
b200f9945f
commit
87446028e0
@ -814,8 +814,11 @@ private class AstChecker(private val namespace: INameScope,
|
|||||||
else {
|
else {
|
||||||
for (arg in args.withIndex().zip(target.parameters)) {
|
for (arg in args.withIndex().zip(target.parameters)) {
|
||||||
val argDt = arg.first.value.resultingDatatype(namespace, heap)
|
val argDt = arg.first.value.resultingDatatype(namespace, heap)
|
||||||
if(argDt!=null && !argDt.assignableTo(arg.second.type))
|
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))
|
// 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.isAsmSubroutine) {
|
||||||
if (target.asmParameterRegisters[arg.first.index].registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.XY, RegisterOrPair.X)) {
|
if (target.asmParameterRegisters[arg.first.index].registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.XY, RegisterOrPair.X)) {
|
||||||
|
@ -14,13 +14,13 @@ fun Module.checkIdentifiers(namespace: INameScope) {
|
|||||||
|
|
||||||
// add any anonymous variables for heap values that are used,
|
// add any anonymous variables for heap values that are used,
|
||||||
// and replace an iterable literalvalue by identifierref to new local variable
|
// 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()
|
val scope = variable.first.definingScope()
|
||||||
scope.statements.add(variable.second)
|
scope.statements.add(variable.second)
|
||||||
val parent = variable.first.parent
|
val parent = variable.first.parent
|
||||||
when {
|
when {
|
||||||
parent is Assignment && parent.value === variable.first -> {
|
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)
|
idref.linkParents(parent)
|
||||||
parent.value = idref
|
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 {
|
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.
|
// 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!
|
// 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)
|
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)
|
return super.process(literalValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val autoHeapValuePrefix = "auto_heap_value_"
|
internal const val autoHeapValuePrefix = "auto_heap_value_"
|
||||||
|
@ -3,7 +3,7 @@ package prog8.ast
|
|||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
|
|
||||||
fun Module.reorderStatements(namespace: INameScope, heap: HeapValues) {
|
fun Module.reorderStatements(namespace: INameScope, heap: HeapValues) {
|
||||||
val initvalueCreator = VarInitValueCreator()
|
val initvalueCreator = VarInitValueAndPointerOfCreator(namespace)
|
||||||
this.process(initvalueCreator)
|
this.process(initvalueCreator)
|
||||||
|
|
||||||
val checker = StatementReorderer(namespace, heap)
|
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.
|
// 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.
|
// 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
|
// 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
|
// This is done in a separate step because it interferes with the namespace lookup of symbols
|
||||||
// in other ast processors.
|
// 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>>()
|
private val vardeclsToAdd = mutableMapOf<INameScope, MutableList<VarDecl>>()
|
||||||
|
|
||||||
override fun process(module: Module) {
|
override fun process(module: Module) {
|
||||||
@ -252,4 +255,33 @@ private class VarInitValueCreator: IAstProcessor {
|
|||||||
return decl
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1089,19 +1089,7 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
translate(arg.first)
|
translate(arg.first)
|
||||||
prog.instr(Opcode.POP_REGAX_WORD)
|
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
|
in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition")
|
||||||
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)
|
|
||||||
}
|
|
||||||
else -> TODO("pass parameter of type $paramDt in registers AX at $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)
|
translate(arg.first)
|
||||||
prog.instr(Opcode.POP_REGAY_WORD)
|
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
|
in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition")
|
||||||
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)
|
|
||||||
}
|
|
||||||
else -> TODO("pass parameter of type $paramDt in registers AY at $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)
|
translate(arg.first)
|
||||||
prog.instr(Opcode.POP_REGXY_WORD)
|
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
|
in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition")
|
||||||
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)
|
|
||||||
}
|
|
||||||
else -> TODO("pass parameter of type $paramDt in registers XY at $callPosition")
|
else -> TODO("pass parameter of type $paramDt in registers XY at $callPosition")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,9 +106,15 @@
|
|||||||
|
|
||||||
;uword[4] pointers = [&array1, &array2, &string1, &string2] ; @todo make it possible to initialize array with pointers
|
;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)
|
;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)
|
;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(&array1)
|
||||||
ptrsubasm(&array2)
|
ptrsubasm(&array2)
|
||||||
|
Loading…
Reference in New Issue
Block a user