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.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<String>) {
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)

View File

@ -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)

View File

@ -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

View File

@ -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<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) {
if(scope !in vardeclsToAdd)
vardeclsToAdd[scope] = mutableListOf()

View File

@ -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<Path>)
class CompilationResult(val success: Boolean,
val programAst: Program,
val programName: String,
val importedFiles: List<Path>)
fun compileProgram(filepath: Path,
@ -27,6 +31,7 @@ fun compileProgram(filepath: Path,
var programName: String? = null
var importedFiles: List<Path> = 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) {

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

View File

@ -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<Expression>) {
args.forEach { asmgen.translateExpression(it) }
private fun translateFunctionArguments(args: MutableList<Expression>, signature: FunctionSignature) {
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.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]

View File

@ -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")
}
}