auto converting string literals to variables and asm generation

This commit is contained in:
Irmen de Jong 2018-11-24 03:25:59 +01:00
parent 6c8354aef0
commit 849bfde515
8 changed files with 71 additions and 39 deletions

View File

@ -21,9 +21,9 @@ sub start() {
ubyte secretnumber = 0
memory uword freadstr_arg = $22 ; argument for FREADSTR
uword testword
ubyte char1 = "@"
ubyte char2 = "\n"
ubyte char3 = "\r"
ubyte char1 = "@" ; @todo don't put this on the heap
ubyte char2 = "\n"; @todo don't put this on the heap
ubyte char3 = "\r"; @todo don't put this on the heap
ubyte char1b = '@'
ubyte char2b = '\n'
ubyte char3b = '\r'
@ -45,10 +45,12 @@ sub start() {
wordarray[b1] = wordarray
wordarray[mb1] = stringvar
wordarray[mb1] = wordarray
; testword = "stringstring" ; @todo asmgen for this
; freadstr_arg = "stringstring" ; @todo asmgen for this
; freadstr_arg = "stringstring2222" ; @todo asmgen for this
; wordarray[1] = "stringstring" ; @todo asmgen for this
testword = "stringstring" ; @todo asmgen for this
freadstr_arg = "stringstring" ; @todo asmgen for this
freadstr_arg = "stringstring2222" ; @todo asmgen for this
wordarray[1] = "stringstring" ; @todo asmgen for this
wordarray[b1] = "stringstring" ; @todo asmgen for this
wordarray[mb1] = "stringstring" ; @todo asmgen for this

View File

@ -87,14 +87,14 @@ fun main(args: Array<String>) {
// perform initial syntax checks and constant folding
val heap = HeapValues()
moduleAst.checkIdentifiers()
moduleAst.checkIdentifiers(heap)
moduleAst.constantFold(namespace, heap)
StatementReorderer(namespace, heap).process(moduleAst) // reorder statements to please the compiler later
moduleAst.checkValid(namespace, compilerOptions, heap) // check if tree is valid
// optimize the parse tree
println("Optimizing...")
val allScopedSymbolDefinitions = moduleAst.checkIdentifiers() // useful for checking symbol usage later?
val allScopedSymbolDefinitions = moduleAst.checkIdentifiers(heap) // useful for checking symbol usage later?
while(true) {
// keep optimizing expressions and statements until no more steps remain
val optsDone1 = moduleAst.simplifyExpressions(namespace, heap)

View File

@ -47,7 +47,7 @@ class AstChecker(private val namespace: INameScope,
private val checkResult: MutableList<AstException> = mutableListOf()
private val heapStringSentinel: Int
init {
val stringSentinel = heap.allStrings().firstOrNull {it.value.str==""}
val stringSentinel = heap.allEntries().firstOrNull {it.value.str==""}
heapStringSentinel = stringSentinel?.index ?: heap.add(DataType.STR, "")
}

View File

@ -1,5 +1,6 @@
package prog8.ast
import prog8.compiler.HeapValues
import prog8.functions.BuiltinFunctions
/**
@ -9,15 +10,29 @@ import prog8.functions.BuiltinFunctions
* Finally, it also makes sure the datatype of all Var decls and sub Return values is set correctly.
*/
fun Module.checkIdentifiers(): MutableMap<String, IStatement> {
val checker = AstIdentifiersChecker()
fun Module.checkIdentifiers(heap: HeapValues): MutableMap<String, IStatement> {
val checker = AstIdentifiersChecker(heap)
this.process(checker)
// add any anonymous variables for heap values that are used, and replace literalvalue by identifierref
for (variable in checker.anonymousVariablesFromHeap) {
val scope = variable.first.definingScope()
scope.statements.add(variable.second)
val parent = variable.first.parent
when {
parent is Assignment && parent.value === variable.first -> {
parent.value = IdentifierReference(listOf("auto_heap_value_${variable.first.heapId}"), variable.first.position)
}
else -> TODO("replace literalvalue by identifierref $variable")
}
}
printErrors(checker.result(), name)
return checker.symbols
}
class AstIdentifiersChecker : IAstProcessor {
class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
private val checkResult: MutableList<AstException> = mutableListOf()
var symbols: MutableMap<String, IStatement> = mutableMapOf()
@ -86,18 +101,20 @@ class AstIdentifiersChecker : IAstProcessor {
nameError(name.key, name.value.position, subroutine)
}
// inject subroutine params as local variables (if they're not there yet) (for non-kernel subroutines)
// inject subroutine params as local variables (if they're not there yet) (for non-kernel subroutines and non-asm parameters)
// NOTE:
// - numeric types BYTE and WORD and FLOAT are passed by value;
// - strings, arrays, matrices are passed by reference (their 16-bit address is passed as an uword parameter)
if(subroutine.asmAddress==null) {
subroutine.parameters
.filter { !definedNames.containsKey(it.name) }
.forEach {
val vardecl = VarDecl(VarDeclType.VAR, it.type, null, it.name, null, subroutine.position)
vardecl.linkParents(subroutine)
subroutine.statements.add(0, vardecl)
}
if(subroutine.asmParameterRegisters.isEmpty()) {
subroutine.parameters
.filter { !definedNames.containsKey(it.name) }
.forEach {
val vardecl = VarDecl(VarDeclType.VAR, it.type, null, it.name, null, subroutine.position)
vardecl.linkParents(subroutine)
subroutine.statements.add(0, vardecl)
}
}
}
}
return super.process(subroutine)
@ -173,4 +190,17 @@ class AstIdentifiersChecker : IAstProcessor {
}
return super.process(returnStmt)
}
internal val anonymousVariablesFromHeap = mutableSetOf<Pair<LiteralValue, VarDecl>>()
override fun process(literalValue: LiteralValue): LiteralValue {
if(literalValue.heapId!=null && literalValue.parent !is VarDecl) {
// 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, null, "auto_heap_value_${literalValue.heapId}", literalValue, literalValue.position)
anonymousVariablesFromHeap.add(Pair(literalValue, variable))
}
return super.process(literalValue)
}
}

View File

@ -99,9 +99,7 @@ class HeapValues {
fun get(heapId: Int): HeapValue = heap[heapId]
fun allStrings() = heap.asSequence().withIndex().filter { it.value.str!=null }.toList()
fun allArrays() = heap.asSequence().withIndex().filter { it.value.array!=null }.toList()
fun allDoubleArrays() = heap.asSequence().withIndex().filter { it.value.doubleArray!=null }.toList()
fun allEntries() = heap.withIndex().toList()
}

View File

@ -312,18 +312,20 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
out.println("; stackVM program code for '$name'")
out.println("%memory")
if(memory.isNotEmpty()) {
TODO("print out initial memory load")
TODO("output initial memory values")
}
out.println("%end_memory")
out.println("%heap")
heap.allStrings().forEach {
out.println("${it.index} ${it.value.type.toString().toLowerCase()} \"${escape(it.value.str!!)}\"")
}
heap.allArrays().forEach {
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}")
}
heap.allDoubleArrays().forEach {
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.doubleArray!!.toList()}")
heap.allEntries().forEach {
when {
it.value.str!=null ->
out.println("${it.index} ${it.value.type.toString().toLowerCase()} \"${escape(it.value.str!!)}\"")
it.value.array!=null ->
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}")
it.value.doubleArray!=null ->
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.doubleArray!!.toList()}")
else -> throw CompilerException("invalid heap entry $it")
}
}
out.println("%end_heap")
for(blk in blocks) {

View File

@ -12,7 +12,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
private var byteval: Short? = null
private var wordval: Int? = null
private var floatval: Double? = null
var heapId: Int = 0
var heapId: Int = -1
private set
val asBooleanValue: Boolean
@ -47,8 +47,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
asBooleanValue = floatval != 0.0
}
else -> {
if(numericvalueOrHeapId !is Int)
throw VmExecutionException("for non-numeric types, the value should be an integer heapId")
if(numericvalueOrHeapId !is Int || numericvalueOrHeapId<0)
throw VmExecutionException("for non-numeric types, the value should be a integer heapId >= 0")
heapId = numericvalueOrHeapId
asBooleanValue=true
}
@ -392,4 +392,4 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
else -> throw VmExecutionException("not can only work on byte/word")
}
}
}
}

View File

@ -1325,13 +1325,13 @@ class StackVm(private var traceOutputFile: String?) {
Opcode.INLINE_ASSEMBLY -> throw VmExecutionException("stackVm doesn't support executing inline assembly code")
Opcode.PUSH_ADDR_HEAPVAR -> {
val heapId = variables[ins.callLabel]!!.heapId
if(heapId<=0)
if(heapId<0)
throw VmExecutionException("expected variable on heap")
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string or array variable
}
Opcode.PUSH_ADDR_STR -> {
val heapId = ins.arg!!.heapId
if(heapId<=0)
if(heapId<0)
throw VmExecutionException("expected string to be on heap")
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string
}