From 2f0c0f6fcdff546e6a18cca65220986b49231e29 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 7 Aug 2019 02:02:34 +0200 Subject: [PATCH] fix function arguments --- compiler/src/prog8/CompilerMain.kt | 11 ++-- compiler/src/prog8/ast/base/Extensions.kt | 2 +- .../prog8/ast/expressions/AstExpressions.kt | 2 +- .../VarInitValueAndAddressOfCreator.kt | 52 ++++++++++++++----- compiler/src/prog8/compiler/Main.kt | 17 +++--- .../compiler/target/c64/codegen2/AsmGen2.kt | 7 +-- .../c64/codegen2/BuiltinFunctionsAsmGen.kt | 14 ++--- compiler/src/prog8/vm/astvm/AstVm.kt | 19 ++++--- examples/test.p8 | 45 ++++------------ 9 files changed, 90 insertions(+), 79 deletions(-) diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index d172ee50c..0dec273a1 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -4,10 +4,12 @@ import prog8.ast.base.AstException import prog8.compiler.CompilationResult import prog8.compiler.compileProgram import prog8.parser.ParsingFailedError -import prog8.vm.astvm.AstVm import prog8.repl.Repl -import java.lang.Exception -import java.nio.file.* +import prog8.vm.astvm.AstVm +import java.nio.file.FileSystems +import java.nio.file.Path +import java.nio.file.Paths +import java.nio.file.StandardWatchEventKinds import java.util.* import kotlin.system.exitProcess @@ -103,12 +105,15 @@ private fun compileMain(args: Array) { try { compilationResult = compileProgram(filepath, optimize, optimizeInlining, writeAssembly) + if(!compilationResult.success) + exitProcess(1) } catch (x: ParsingFailedError) { exitProcess(1) } catch (x: AstException) { exitProcess(1) } + println("LAUNCH VM!@") if (launchAstVm) { println("\nLaunching AST-based vm...") val vm = AstVm(compilationResult.programAst) diff --git a/compiler/src/prog8/ast/base/Extensions.kt b/compiler/src/prog8/ast/base/Extensions.kt index 794ccfb29..bb186c8fe 100644 --- a/compiler/src/prog8/ast/base/Extensions.kt +++ b/compiler/src/prog8/ast/base/Extensions.kt @@ -37,7 +37,7 @@ internal fun Program.anonscopeVarsCleanup() { internal fun Program.reorderStatements() { - val initvalueCreator = VarInitValueAndAddressOfCreator(namespace, heap) + val initvalueCreator = VarInitValueAndAddressOfCreator(this) initvalueCreator.visit(this) val checker = StatementReorderer(this) diff --git a/compiler/src/prog8/ast/expressions/AstExpressions.kt b/compiler/src/prog8/ast/expressions/AstExpressions.kt index 45f0c375b..891f90cd3 100644 --- a/compiler/src/prog8/ast/expressions/AstExpressions.kt +++ b/compiler/src/prog8/ast/expressions/AstExpressions.kt @@ -240,7 +240,7 @@ data class AddressOf(var identifier: IdentifierReference, override val position: identifier.parent=this } - var scopedname: String? = null // will be set in a later state by the compiler + var scopedname: String? = null // will be set in a later state by the compiler // TODO get rid of this?? override fun constValue(program: Program): NumericLiteralValue? = null override fun referencesIdentifiers(vararg name: String) = false override fun inferType(program: Program) = DataType.UWORD diff --git a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt b/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt index 2c75aca0c..c67d45875 100644 --- a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt +++ b/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt @@ -3,13 +3,16 @@ package prog8.ast.processing import prog8.ast.INameScope import prog8.ast.Module import prog8.ast.Node +import prog8.ast.Program import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* -import prog8.compiler.HeapValues +import prog8.compiler.CompilerException +import prog8.functions.BuiltinFunctions +import prog8.functions.FunctionSignature -internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope, private val heap: HeapValues): IAstModifyingVisitor { +internal class VarInitValueAndAddressOfCreator(private val program: Program): IAstModifyingVisitor { // For VarDecls that declare an initialization value: // Replace the vardecl with an assignment (to set the initial value), // and add a new vardecl with the default constant value of that type (usually zero) to the scope. @@ -42,7 +45,7 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope val array = ReferenceLiteralValue(decl.datatype, null, Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) }, null, decl.position) - array.addToHeap(heap) + array.addToHeap(program.heap) decl.value = array } @@ -73,20 +76,29 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope } override fun visit(functionCall: FunctionCall): Expression { - val targetStatement = functionCall.target.targetSubroutine(namespace) + var parentStatement: Node = functionCall + while(parentStatement !is Statement) + parentStatement = parentStatement.parent + val targetStatement = functionCall.target.targetSubroutine(program.namespace) if(targetStatement!=null) { - var node: Node = functionCall - while(node !is Statement) - node=node.parent - addAddressOfExprIfNeeded(targetStatement, functionCall.arglist, node) + addAddressOfExprIfNeeded(targetStatement, functionCall.arglist, parentStatement) + } else { + val builtinFunc = BuiltinFunctions[functionCall.target.nameInSource.joinToString (".")] + if(builtinFunc!=null) + addAddressOfExprIfNeededForBuiltinFuncs(builtinFunc, functionCall.arglist, parentStatement) } return functionCall } override fun visit(functionCallStatement: FunctionCallStatement): Statement { - val targetStatement = functionCallStatement.target.targetSubroutine(namespace) - if(targetStatement!=null) + val targetStatement = functionCallStatement.target.targetSubroutine(program.namespace) + if(targetStatement!=null) { addAddressOfExprIfNeeded(targetStatement, functionCallStatement.arglist, functionCallStatement) + } else { + val builtinFunc = BuiltinFunctions[functionCallStatement.target.nameInSource.joinToString (".")] + if(builtinFunc!=null) + addAddressOfExprIfNeededForBuiltinFuncs(builtinFunc, functionCallStatement.arglist, functionCallStatement) + } return functionCallStatement } @@ -99,7 +111,7 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope val idref = argparam.second as? IdentifierReference val strvalue = argparam.second as? ReferenceLiteralValue if(idref!=null) { - val variable = idref.targetVarDecl(namespace) + val variable = idref.targetVarDecl(program.namespace) if(variable!=null && (variable.datatype in StringDatatypes || variable.datatype in ArrayDatatypes)) { val pointerExpr = AddressOf(idref, idref.position) pointerExpr.scopedname = parent.makeScopedName(idref.nameInSource.single()) @@ -110,7 +122,7 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope else if(strvalue!=null) { if(strvalue.isString) { // add a vardecl so that the autovar can be resolved in later lookups - val variable = VarDecl.createAuto(strvalue, heap) + val variable = VarDecl.createAuto(strvalue, program.heap) addVarDecl(strvalue.definingScope(), variable) // replace the argument with &autovar val autoHeapvarRef = IdentifierReference(listOf(variable.name), strvalue.position) @@ -124,6 +136,22 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope } } + private fun addAddressOfExprIfNeededForBuiltinFuncs(signature: FunctionSignature, args: MutableList, parent: Statement) { + for(arg in args.withIndex().zip(signature.parameters)) { + val argvalue = arg.first.value + val argDt = argvalue.inferType(program) + if(DataType.UWORD in arg.second.possibleDatatypes && argDt in PassByReferenceDatatypes) { + if(argvalue !is IdentifierReference) + throw CompilerException("pass-by-reference parameter isn't an identifier? $argvalue") + val addrOf = AddressOf(argvalue, argvalue.position) + args[arg.first.index] = addrOf + addrOf.scopedname = parent.makeScopedName(argvalue.nameInSource.single()) + addrOf.linkParents(parent) + } + } + } + + private fun addVarDecl(scope: INameScope, variable: VarDecl) { if(scope !in vardeclsToAdd) vardeclsToAdd[scope] = mutableListOf() diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index 4cbee751d..8dbe11b9d 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -1,5 +1,6 @@ package prog8.compiler +import com.sun.org.apache.xpath.internal.functions.FuncFalse import prog8.ast.AstToSourceCode import prog8.ast.Program import prog8.ast.base.* @@ -17,7 +18,10 @@ import java.nio.file.Path import kotlin.system.measureTimeMillis -class CompilationResult(val programAst: Program, val programName: String, val importedFiles: List) +class CompilationResult(val success: Boolean, + val programAst: Program, + val programName: String, + val importedFiles: List) fun compileProgram(filepath: Path, @@ -27,6 +31,7 @@ fun compileProgram(filepath: Path, var programName: String? = null var importedFiles: List = emptyList() + var success=false try { val totalTime = measureTimeMillis { @@ -65,11 +70,6 @@ fun compileProgram(filepath: Path, //println(" time2: $time2") val time3 = measureTimeMillis { programAst.removeNopsFlattenAnonScopes() - - // if you want to print the AST, do it before shuffling the statements around below - //printAst(programAst) - - programAst.reorderStatements() // reorder statements and add type casts, to please the compiler later } //println(" time3: $time3") @@ -95,7 +95,7 @@ fun compileProgram(filepath: Path, programAst.checkValid(compilerOptions) // check if final tree is valid programAst.checkRecursion() // check if there are recursive subroutine calls - //printAst(programAst) + printAst(programAst) if(writeAssembly) { // asm generation directly from the Ast, no need for intermediate code @@ -105,6 +105,7 @@ fun compileProgram(filepath: Path, assembly.assemble(compilerOptions) programName = assembly.name } + success = true } println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.") @@ -129,7 +130,7 @@ fun compileProgram(filepath: Path, System.out.flush() throw x } - return CompilationResult(programAst, programName ?: "", importedFiles) + return CompilationResult(success, programAst, programName ?: "", importedFiles) } fun printAst(programAst: Program) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt index d445fdd4b..33de1e891 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt @@ -238,11 +238,6 @@ internal class AsmGen2(val program: Program, } } } - else { - throw AssemblyError("huh, var is already in zp $fullName") - // it was already allocated on the zp, what to do? - // out("${variable.name} = ${zpVar.first}\t; zp ${zpVar.second}") - } } } @@ -647,7 +642,7 @@ internal class AsmGen2(val program: Program, out(" ldx c64.SCRATCH_ZPREGX") // restore X again } - private fun translateSubroutineArgument(arg: IndexedValue, value: Expression, sub: Subroutine) { + fun translateSubroutineArgument(arg: IndexedValue, value: Expression, sub: Subroutine) { val sourceDt = value.inferType(program)!! if(!argumentTypeCompatible(sourceDt, arg.value.type)) throw AssemblyError("argument type incompatible") diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt index ad1851e60..7a9b8d5c9 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt @@ -54,11 +54,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } "mkword" -> { - translateFunctionArguments(fcall.arglist) + translateFunctionArguments(fcall.arglist, func) asmgen.out(" inx | lda $ESTACK_LO_HEX,x | sta $ESTACK_HI_PLUS1_HEX,x") } "abs" -> { - translateFunctionArguments(fcall.arglist) + translateFunctionArguments(fcall.arglist, func) val dt = fcall.arglist.single().inferType(program)!! when (dt) { in ByteDatatypes -> asmgen.out(" jsr prog8_lib.abs_b") @@ -72,7 +72,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, "ln", "log2", "sqrt", "rad", "deg", "round", "floor", "ceil", "rdnf" -> { - translateFunctionArguments(fcall.arglist) + translateFunctionArguments(fcall.arglist, func) asmgen.out(" jsr c64flt.func_$functionName") } /* @@ -224,14 +224,16 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } else -> { - translateFunctionArguments(fcall.arglist) + translateFunctionArguments(fcall.arglist, func) asmgen.out(" jsr prog8_lib.func_$functionName") } } } - private fun translateFunctionArguments(args: MutableList) { - args.forEach { asmgen.translateExpression(it) } + private fun translateFunctionArguments(args: MutableList, signature: FunctionSignature) { + args.forEach { + asmgen.translateExpression(it) + } } } diff --git a/compiler/src/prog8/vm/astvm/AstVm.kt b/compiler/src/prog8/vm/astvm/AstVm.kt index 731c73162..1c4ae1906 100644 --- a/compiler/src/prog8/vm/astvm/AstVm.kt +++ b/compiler/src/prog8/vm/astvm/AstVm.kt @@ -7,6 +7,7 @@ import prog8.ast.expressions.Expression import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteralValue import prog8.ast.statements.* +import prog8.compiler.IntegerOrAddressOf import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.c64.Petscii import prog8.vm.RuntimeValue @@ -877,27 +878,31 @@ class AstVm(val program: Program) { RuntimeValue(DataType.UBYTE, args[0].str!!.length) } "memset" -> { - val target = args[0].array!! + val heapId = args[0].wordval!! + val target = program.heap.get(heapId).array ?: throw VmExecutionException("memset target is not an array") val amount = args[1].integerValue() val value = args[2].integerValue() for (i in 0 until amount) { - target[i] = value + target[i] = IntegerOrAddressOf(value, null) } null } "memsetw" -> { - val target = args[0].array!! + val heapId = args[0].wordval!! + val target = program.heap.get(heapId).array ?: throw VmExecutionException("memset target is not an array") val amount = args[1].integerValue() val value = args[2].integerValue() for (i in 0 until amount step 2) { - target[i * 2] = value and 255 - target[i * 2 + 1] = value ushr 8 + target[i * 2] = IntegerOrAddressOf(value and 255, null) + target[i * 2 + 1] = IntegerOrAddressOf(value ushr 8, null) } null } "memcopy" -> { - val source = args[0].array!! - val dest = args[1].array!! + val sourceHeapId = args[0].wordval!! + val destHeapId = args[1].wordval!! + val source = program.heap.get(sourceHeapId).array!! + val dest = program.heap.get(destHeapId).array!! val amount = args[2].integerValue() for(i in 0 until amount) { dest[i] = source[i] diff --git a/examples/test.p8 b/examples/test.p8 index 2ba94d442..22f52bf88 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,45 +1,20 @@ %import c64utils -%zeropage basicsafe +%import c64lib + main { - ubyte[256] sieve - ubyte candidate_prime = 2 - sub start() { - memset(sieve, 256, false) + ending() - c64scr.print("prime numbers up to 255:\n\n") - ubyte amount=0 - while true { - ubyte prime = find_next_prime() - if prime==0 - break - c64scr.print_ub(prime) - c64scr.print(", ") - amount++ - } - c64.CHROUT('\n') - c64scr.print("number of primes (expected 54): ") - c64scr.print_ub(amount) - c64.CHROUT('\n') } - - - sub find_next_prime() -> ubyte { - - while sieve[candidate_prime] { - candidate_prime++ - if candidate_prime==0 - return 0 + sub ending() { + if A + c64scr.print("bla") + else { + c64scr.print("bla") + c64scr.print("bla") } - - sieve[candidate_prime] = true - uword multiple = candidate_prime - while multiple < len(sieve) { - sieve[lsb(multiple)] = true - multiple += candidate_prime - } - return candidate_prime + c64scr.print("bla") } }