mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
auto converting string literals to variables and asm generation
This commit is contained in:
parent
6c8354aef0
commit
849bfde515
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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, "")
|
||||
}
|
||||
|
||||
|
@ -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,11 +101,12 @@ 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) {
|
||||
if(subroutine.asmParameterRegisters.isEmpty()) {
|
||||
subroutine.parameters
|
||||
.filter { !definedNames.containsKey(it.name) }
|
||||
.forEach {
|
||||
@ -100,6 +116,7 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
heap.allEntries().forEach {
|
||||
when {
|
||||
it.value.str!=null ->
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} \"${escape(it.value.str!!)}\"")
|
||||
}
|
||||
heap.allArrays().forEach {
|
||||
it.value.array!=null ->
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}")
|
||||
}
|
||||
heap.allDoubleArrays().forEach {
|
||||
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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user