fix function arguments

This commit is contained in:
Irmen de Jong 2019-08-07 02:02:34 +02:00
parent 7ddc01f883
commit 2f0c0f6fcd
9 changed files with 90 additions and 79 deletions

View File

@ -4,10 +4,12 @@ import prog8.ast.base.AstException
import prog8.compiler.CompilationResult import prog8.compiler.CompilationResult
import prog8.compiler.compileProgram import prog8.compiler.compileProgram
import prog8.parser.ParsingFailedError import prog8.parser.ParsingFailedError
import prog8.vm.astvm.AstVm
import prog8.repl.Repl import prog8.repl.Repl
import java.lang.Exception import prog8.vm.astvm.AstVm
import java.nio.file.* import java.nio.file.FileSystems
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardWatchEventKinds
import java.util.* import java.util.*
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -103,12 +105,15 @@ private fun compileMain(args: Array<String>) {
try { try {
compilationResult = compileProgram(filepath, optimize, optimizeInlining, writeAssembly) compilationResult = compileProgram(filepath, optimize, optimizeInlining, writeAssembly)
if(!compilationResult.success)
exitProcess(1)
} catch (x: ParsingFailedError) { } catch (x: ParsingFailedError) {
exitProcess(1) exitProcess(1)
} catch (x: AstException) { } catch (x: AstException) {
exitProcess(1) exitProcess(1)
} }
println("LAUNCH VM!@")
if (launchAstVm) { if (launchAstVm) {
println("\nLaunching AST-based vm...") println("\nLaunching AST-based vm...")
val vm = AstVm(compilationResult.programAst) val vm = AstVm(compilationResult.programAst)

View File

@ -37,7 +37,7 @@ internal fun Program.anonscopeVarsCleanup() {
internal fun Program.reorderStatements() { internal fun Program.reorderStatements() {
val initvalueCreator = VarInitValueAndAddressOfCreator(namespace, heap) val initvalueCreator = VarInitValueAndAddressOfCreator(this)
initvalueCreator.visit(this) initvalueCreator.visit(this)
val checker = StatementReorderer(this) val checker = StatementReorderer(this)

View File

@ -240,7 +240,7 @@ data class AddressOf(var identifier: IdentifierReference, override val position:
identifier.parent=this 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 constValue(program: Program): NumericLiteralValue? = null
override fun referencesIdentifiers(vararg name: String) = false override fun referencesIdentifiers(vararg name: String) = false
override fun inferType(program: Program) = DataType.UWORD override fun inferType(program: Program) = DataType.UWORD

View File

@ -3,13 +3,16 @@ package prog8.ast.processing
import prog8.ast.INameScope import prog8.ast.INameScope
import prog8.ast.Module import prog8.ast.Module
import prog8.ast.Node import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* 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: // For VarDecls that declare an initialization value:
// Replace the vardecl with an assignment (to set the initial 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. // 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, val array = ReferenceLiteralValue(decl.datatype, null,
Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) }, Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) },
null, decl.position) null, decl.position)
array.addToHeap(heap) array.addToHeap(program.heap)
decl.value = array decl.value = array
} }
@ -73,20 +76,29 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope
} }
override fun visit(functionCall: FunctionCall): Expression { 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) { if(targetStatement!=null) {
var node: Node = functionCall addAddressOfExprIfNeeded(targetStatement, functionCall.arglist, parentStatement)
while(node !is Statement) } else {
node=node.parent val builtinFunc = BuiltinFunctions[functionCall.target.nameInSource.joinToString (".")]
addAddressOfExprIfNeeded(targetStatement, functionCall.arglist, node) if(builtinFunc!=null)
addAddressOfExprIfNeededForBuiltinFuncs(builtinFunc, functionCall.arglist, parentStatement)
} }
return functionCall return functionCall
} }
override fun visit(functionCallStatement: FunctionCallStatement): Statement { override fun visit(functionCallStatement: FunctionCallStatement): Statement {
val targetStatement = functionCallStatement.target.targetSubroutine(namespace) val targetStatement = functionCallStatement.target.targetSubroutine(program.namespace)
if(targetStatement!=null) if(targetStatement!=null) {
addAddressOfExprIfNeeded(targetStatement, functionCallStatement.arglist, functionCallStatement) addAddressOfExprIfNeeded(targetStatement, functionCallStatement.arglist, functionCallStatement)
} else {
val builtinFunc = BuiltinFunctions[functionCallStatement.target.nameInSource.joinToString (".")]
if(builtinFunc!=null)
addAddressOfExprIfNeededForBuiltinFuncs(builtinFunc, functionCallStatement.arglist, functionCallStatement)
}
return functionCallStatement return functionCallStatement
} }
@ -99,7 +111,7 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope
val idref = argparam.second as? IdentifierReference val idref = argparam.second as? IdentifierReference
val strvalue = argparam.second as? ReferenceLiteralValue val strvalue = argparam.second as? ReferenceLiteralValue
if(idref!=null) { 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)) { if(variable!=null && (variable.datatype in StringDatatypes || variable.datatype in ArrayDatatypes)) {
val pointerExpr = AddressOf(idref, idref.position) val pointerExpr = AddressOf(idref, idref.position)
pointerExpr.scopedname = parent.makeScopedName(idref.nameInSource.single()) pointerExpr.scopedname = parent.makeScopedName(idref.nameInSource.single())
@ -110,7 +122,7 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope
else if(strvalue!=null) { else if(strvalue!=null) {
if(strvalue.isString) { if(strvalue.isString) {
// add a vardecl so that the autovar can be resolved in later lookups // 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) addVarDecl(strvalue.definingScope(), variable)
// replace the argument with &autovar // replace the argument with &autovar
val autoHeapvarRef = IdentifierReference(listOf(variable.name), strvalue.position) 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<Expression>, 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) { private fun addVarDecl(scope: INameScope, variable: VarDecl) {
if(scope !in vardeclsToAdd) if(scope !in vardeclsToAdd)
vardeclsToAdd[scope] = mutableListOf() vardeclsToAdd[scope] = mutableListOf()

View File

@ -1,5 +1,6 @@
package prog8.compiler package prog8.compiler
import com.sun.org.apache.xpath.internal.functions.FuncFalse
import prog8.ast.AstToSourceCode import prog8.ast.AstToSourceCode
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
@ -17,7 +18,10 @@ import java.nio.file.Path
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
class CompilationResult(val programAst: Program, val programName: String, val importedFiles: List<Path>) class CompilationResult(val success: Boolean,
val programAst: Program,
val programName: String,
val importedFiles: List<Path>)
fun compileProgram(filepath: Path, fun compileProgram(filepath: Path,
@ -27,6 +31,7 @@ fun compileProgram(filepath: Path,
var programName: String? = null var programName: String? = null
var importedFiles: List<Path> = emptyList() var importedFiles: List<Path> = emptyList()
var success=false
try { try {
val totalTime = measureTimeMillis { val totalTime = measureTimeMillis {
@ -65,11 +70,6 @@ fun compileProgram(filepath: Path,
//println(" time2: $time2") //println(" time2: $time2")
val time3 = measureTimeMillis { val time3 = measureTimeMillis {
programAst.removeNopsFlattenAnonScopes() 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 programAst.reorderStatements() // reorder statements and add type casts, to please the compiler later
} }
//println(" time3: $time3") //println(" time3: $time3")
@ -95,7 +95,7 @@ fun compileProgram(filepath: Path,
programAst.checkValid(compilerOptions) // check if final tree is valid programAst.checkValid(compilerOptions) // check if final tree is valid
programAst.checkRecursion() // check if there are recursive subroutine calls programAst.checkRecursion() // check if there are recursive subroutine calls
//printAst(programAst) printAst(programAst)
if(writeAssembly) { if(writeAssembly) {
// asm generation directly from the Ast, no need for intermediate code // asm generation directly from the Ast, no need for intermediate code
@ -105,6 +105,7 @@ fun compileProgram(filepath: Path,
assembly.assemble(compilerOptions) assembly.assemble(compilerOptions)
programName = assembly.name programName = assembly.name
} }
success = true
} }
println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.") println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.")
@ -129,7 +130,7 @@ fun compileProgram(filepath: Path,
System.out.flush() System.out.flush()
throw x throw x
} }
return CompilationResult(programAst, programName ?: "", importedFiles) return CompilationResult(success, programAst, programName ?: "", importedFiles)
} }
fun printAst(programAst: Program) { fun printAst(programAst: Program) {

View File

@ -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 out(" ldx c64.SCRATCH_ZPREGX") // restore X again
} }
private fun translateSubroutineArgument(arg: IndexedValue<SubroutineParameter>, value: Expression, sub: Subroutine) { fun translateSubroutineArgument(arg: IndexedValue<SubroutineParameter>, value: Expression, sub: Subroutine) {
val sourceDt = value.inferType(program)!! val sourceDt = value.inferType(program)!!
if(!argumentTypeCompatible(sourceDt, arg.value.type)) if(!argumentTypeCompatible(sourceDt, arg.value.type))
throw AssemblyError("argument type incompatible") throw AssemblyError("argument type incompatible")

View File

@ -54,11 +54,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
} }
} }
"mkword" -> { "mkword" -> {
translateFunctionArguments(fcall.arglist) translateFunctionArguments(fcall.arglist, func)
asmgen.out(" inx | lda $ESTACK_LO_HEX,x | sta $ESTACK_HI_PLUS1_HEX,x") asmgen.out(" inx | lda $ESTACK_LO_HEX,x | sta $ESTACK_HI_PLUS1_HEX,x")
} }
"abs" -> { "abs" -> {
translateFunctionArguments(fcall.arglist) translateFunctionArguments(fcall.arglist, func)
val dt = fcall.arglist.single().inferType(program)!! val dt = fcall.arglist.single().inferType(program)!!
when (dt) { when (dt) {
in ByteDatatypes -> asmgen.out(" jsr prog8_lib.abs_b") in ByteDatatypes -> asmgen.out(" jsr prog8_lib.abs_b")
@ -72,7 +72,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
"ln", "log2", "sqrt", "rad", "ln", "log2", "sqrt", "rad",
"deg", "round", "floor", "ceil", "deg", "round", "floor", "ceil",
"rdnf" -> { "rdnf" -> {
translateFunctionArguments(fcall.arglist) translateFunctionArguments(fcall.arglist, func)
asmgen.out(" jsr c64flt.func_$functionName") asmgen.out(" jsr c64flt.func_$functionName")
} }
/* /*
@ -224,14 +224,16 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
} }
} }
else -> { else -> {
translateFunctionArguments(fcall.arglist) translateFunctionArguments(fcall.arglist, func)
asmgen.out(" jsr prog8_lib.func_$functionName") asmgen.out(" jsr prog8_lib.func_$functionName")
} }
} }
} }
private fun translateFunctionArguments(args: MutableList<Expression>) { private fun translateFunctionArguments(args: MutableList<Expression>, signature: FunctionSignature) {
args.forEach { asmgen.translateExpression(it) } args.forEach {
asmgen.translateExpression(it)
}
} }
} }

View File

@ -7,6 +7,7 @@ import prog8.ast.expressions.Expression
import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.IntegerOrAddressOf
import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import prog8.vm.RuntimeValue import prog8.vm.RuntimeValue
@ -877,27 +878,31 @@ class AstVm(val program: Program) {
RuntimeValue(DataType.UBYTE, args[0].str!!.length) RuntimeValue(DataType.UBYTE, args[0].str!!.length)
} }
"memset" -> { "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 amount = args[1].integerValue()
val value = args[2].integerValue() val value = args[2].integerValue()
for (i in 0 until amount) { for (i in 0 until amount) {
target[i] = value target[i] = IntegerOrAddressOf(value, null)
} }
null null
} }
"memsetw" -> { "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 amount = args[1].integerValue()
val value = args[2].integerValue() val value = args[2].integerValue()
for (i in 0 until amount step 2) { for (i in 0 until amount step 2) {
target[i * 2] = value and 255 target[i * 2] = IntegerOrAddressOf(value and 255, null)
target[i * 2 + 1] = value ushr 8 target[i * 2 + 1] = IntegerOrAddressOf(value ushr 8, null)
} }
null null
} }
"memcopy" -> { "memcopy" -> {
val source = args[0].array!! val sourceHeapId = args[0].wordval!!
val dest = args[1].array!! val destHeapId = args[1].wordval!!
val source = program.heap.get(sourceHeapId).array!!
val dest = program.heap.get(destHeapId).array!!
val amount = args[2].integerValue() val amount = args[2].integerValue()
for(i in 0 until amount) { for(i in 0 until amount) {
dest[i] = source[i] dest[i] = source[i]

View File

@ -1,45 +1,20 @@
%import c64utils %import c64utils
%zeropage basicsafe %import c64lib
main { main {
ubyte[256] sieve
ubyte candidate_prime = 2
sub start() { 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') sub ending() {
c64scr.print("number of primes (expected 54): ") if A
c64scr.print_ub(amount) c64scr.print("bla")
c64.CHROUT('\n') else {
c64scr.print("bla")
c64scr.print("bla")
} }
c64scr.print("bla")
sub find_next_prime() -> ubyte {
while sieve[candidate_prime] {
candidate_prime++
if candidate_prime==0
return 0
}
sieve[candidate_prime] = true
uword multiple = candidate_prime
while multiple < len(sieve) {
sieve[lsb(multiple)] = true
multiple += candidate_prime
}
return candidate_prime
} }
} }