mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +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
|
ubyte secretnumber = 0
|
||||||
memory uword freadstr_arg = $22 ; argument for FREADSTR
|
memory uword freadstr_arg = $22 ; argument for FREADSTR
|
||||||
uword testword
|
uword testword
|
||||||
ubyte char1 = "@"
|
ubyte char1 = "@" ; @todo don't put this on the heap
|
||||||
ubyte char2 = "\n"
|
ubyte char2 = "\n"; @todo don't put this on the heap
|
||||||
ubyte char3 = "\r"
|
ubyte char3 = "\r"; @todo don't put this on the heap
|
||||||
ubyte char1b = '@'
|
ubyte char1b = '@'
|
||||||
ubyte char2b = '\n'
|
ubyte char2b = '\n'
|
||||||
ubyte char3b = '\r'
|
ubyte char3b = '\r'
|
||||||
@ -45,10 +45,12 @@ sub start() {
|
|||||||
wordarray[b1] = wordarray
|
wordarray[b1] = wordarray
|
||||||
wordarray[mb1] = stringvar
|
wordarray[mb1] = stringvar
|
||||||
wordarray[mb1] = wordarray
|
wordarray[mb1] = wordarray
|
||||||
; testword = "stringstring" ; @todo asmgen for this
|
testword = "stringstring" ; @todo asmgen for this
|
||||||
; freadstr_arg = "stringstring" ; @todo asmgen for this
|
freadstr_arg = "stringstring" ; @todo asmgen for this
|
||||||
; freadstr_arg = "stringstring2222" ; @todo asmgen for this
|
freadstr_arg = "stringstring2222" ; @todo asmgen for this
|
||||||
; wordarray[1] = "stringstring" ; @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
|
// perform initial syntax checks and constant folding
|
||||||
val heap = HeapValues()
|
val heap = HeapValues()
|
||||||
moduleAst.checkIdentifiers()
|
moduleAst.checkIdentifiers(heap)
|
||||||
moduleAst.constantFold(namespace, heap)
|
moduleAst.constantFold(namespace, heap)
|
||||||
StatementReorderer(namespace, heap).process(moduleAst) // reorder statements to please the compiler later
|
StatementReorderer(namespace, heap).process(moduleAst) // reorder statements to please the compiler later
|
||||||
moduleAst.checkValid(namespace, compilerOptions, heap) // check if tree is valid
|
moduleAst.checkValid(namespace, compilerOptions, heap) // check if tree is valid
|
||||||
|
|
||||||
// optimize the parse tree
|
// optimize the parse tree
|
||||||
println("Optimizing...")
|
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) {
|
while(true) {
|
||||||
// keep optimizing expressions and statements until no more steps remain
|
// keep optimizing expressions and statements until no more steps remain
|
||||||
val optsDone1 = moduleAst.simplifyExpressions(namespace, heap)
|
val optsDone1 = moduleAst.simplifyExpressions(namespace, heap)
|
||||||
|
@ -47,7 +47,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
private val checkResult: MutableList<AstException> = mutableListOf()
|
private val checkResult: MutableList<AstException> = mutableListOf()
|
||||||
private val heapStringSentinel: Int
|
private val heapStringSentinel: Int
|
||||||
init {
|
init {
|
||||||
val stringSentinel = heap.allStrings().firstOrNull {it.value.str==""}
|
val stringSentinel = heap.allEntries().firstOrNull {it.value.str==""}
|
||||||
heapStringSentinel = stringSentinel?.index ?: heap.add(DataType.STR, "")
|
heapStringSentinel = stringSentinel?.index ?: heap.add(DataType.STR, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package prog8.ast
|
package prog8.ast
|
||||||
|
|
||||||
|
import prog8.compiler.HeapValues
|
||||||
import prog8.functions.BuiltinFunctions
|
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.
|
* Finally, it also makes sure the datatype of all Var decls and sub Return values is set correctly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fun Module.checkIdentifiers(): MutableMap<String, IStatement> {
|
fun Module.checkIdentifiers(heap: HeapValues): MutableMap<String, IStatement> {
|
||||||
val checker = AstIdentifiersChecker()
|
val checker = AstIdentifiersChecker(heap)
|
||||||
this.process(checker)
|
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)
|
printErrors(checker.result(), name)
|
||||||
return checker.symbols
|
return checker.symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AstIdentifiersChecker : IAstProcessor {
|
class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
|
||||||
private val checkResult: MutableList<AstException> = mutableListOf()
|
private val checkResult: MutableList<AstException> = mutableListOf()
|
||||||
|
|
||||||
var symbols: MutableMap<String, IStatement> = mutableMapOf()
|
var symbols: MutableMap<String, IStatement> = mutableMapOf()
|
||||||
@ -86,18 +101,20 @@ class AstIdentifiersChecker : IAstProcessor {
|
|||||||
nameError(name.key, name.value.position, subroutine)
|
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:
|
// NOTE:
|
||||||
// - numeric types BYTE and WORD and FLOAT are passed by value;
|
// - 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)
|
// - strings, arrays, matrices are passed by reference (their 16-bit address is passed as an uword parameter)
|
||||||
if(subroutine.asmAddress==null) {
|
if(subroutine.asmAddress==null) {
|
||||||
subroutine.parameters
|
if(subroutine.asmParameterRegisters.isEmpty()) {
|
||||||
.filter { !definedNames.containsKey(it.name) }
|
subroutine.parameters
|
||||||
.forEach {
|
.filter { !definedNames.containsKey(it.name) }
|
||||||
val vardecl = VarDecl(VarDeclType.VAR, it.type, null, it.name, null, subroutine.position)
|
.forEach {
|
||||||
vardecl.linkParents(subroutine)
|
val vardecl = VarDecl(VarDeclType.VAR, it.type, null, it.name, null, subroutine.position)
|
||||||
subroutine.statements.add(0, vardecl)
|
vardecl.linkParents(subroutine)
|
||||||
}
|
subroutine.statements.add(0, vardecl)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.process(subroutine)
|
return super.process(subroutine)
|
||||||
@ -173,4 +190,17 @@ class AstIdentifiersChecker : IAstProcessor {
|
|||||||
}
|
}
|
||||||
return super.process(returnStmt)
|
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 get(heapId: Int): HeapValue = heap[heapId]
|
||||||
|
|
||||||
fun allStrings() = heap.asSequence().withIndex().filter { it.value.str!=null }.toList()
|
fun allEntries() = heap.withIndex().toList()
|
||||||
fun allArrays() = heap.asSequence().withIndex().filter { it.value.array!=null }.toList()
|
|
||||||
fun allDoubleArrays() = heap.asSequence().withIndex().filter { it.value.doubleArray!=null }.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("; stackVM program code for '$name'")
|
||||||
out.println("%memory")
|
out.println("%memory")
|
||||||
if(memory.isNotEmpty()) {
|
if(memory.isNotEmpty()) {
|
||||||
TODO("print out initial memory load")
|
TODO("output initial memory values")
|
||||||
}
|
}
|
||||||
out.println("%end_memory")
|
out.println("%end_memory")
|
||||||
out.println("%heap")
|
out.println("%heap")
|
||||||
heap.allStrings().forEach {
|
heap.allEntries().forEach {
|
||||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} \"${escape(it.value.str!!)}\"")
|
when {
|
||||||
}
|
it.value.str!=null ->
|
||||||
heap.allArrays().forEach {
|
out.println("${it.index} ${it.value.type.toString().toLowerCase()} \"${escape(it.value.str!!)}\"")
|
||||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}")
|
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()}")
|
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.doubleArray!!.toList()}")
|
||||||
|
else -> throw CompilerException("invalid heap entry $it")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.println("%end_heap")
|
out.println("%end_heap")
|
||||||
for(blk in blocks) {
|
for(blk in blocks) {
|
||||||
|
@ -12,7 +12,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
private var byteval: Short? = null
|
private var byteval: Short? = null
|
||||||
private var wordval: Int? = null
|
private var wordval: Int? = null
|
||||||
private var floatval: Double? = null
|
private var floatval: Double? = null
|
||||||
var heapId: Int = 0
|
var heapId: Int = -1
|
||||||
private set
|
private set
|
||||||
val asBooleanValue: Boolean
|
val asBooleanValue: Boolean
|
||||||
|
|
||||||
@ -47,8 +47,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
asBooleanValue = floatval != 0.0
|
asBooleanValue = floatval != 0.0
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
if(numericvalueOrHeapId !is Int)
|
if(numericvalueOrHeapId !is Int || numericvalueOrHeapId<0)
|
||||||
throw VmExecutionException("for non-numeric types, the value should be an integer heapId")
|
throw VmExecutionException("for non-numeric types, the value should be a integer heapId >= 0")
|
||||||
heapId = numericvalueOrHeapId
|
heapId = numericvalueOrHeapId
|
||||||
asBooleanValue=true
|
asBooleanValue=true
|
||||||
}
|
}
|
||||||
@ -392,4 +392,4 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
else -> throw VmExecutionException("not can only work on byte/word")
|
else -> throw VmExecutionException("not can only work on byte/word")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1325,13 +1325,13 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
Opcode.INLINE_ASSEMBLY -> throw VmExecutionException("stackVm doesn't support executing inline assembly code")
|
Opcode.INLINE_ASSEMBLY -> throw VmExecutionException("stackVm doesn't support executing inline assembly code")
|
||||||
Opcode.PUSH_ADDR_HEAPVAR -> {
|
Opcode.PUSH_ADDR_HEAPVAR -> {
|
||||||
val heapId = variables[ins.callLabel]!!.heapId
|
val heapId = variables[ins.callLabel]!!.heapId
|
||||||
if(heapId<=0)
|
if(heapId<0)
|
||||||
throw VmExecutionException("expected variable on heap")
|
throw VmExecutionException("expected variable on heap")
|
||||||
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string or array variable
|
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string or array variable
|
||||||
}
|
}
|
||||||
Opcode.PUSH_ADDR_STR -> {
|
Opcode.PUSH_ADDR_STR -> {
|
||||||
val heapId = ins.arg!!.heapId
|
val heapId = ins.arg!!.heapId
|
||||||
if(heapId<=0)
|
if(heapId<0)
|
||||||
throw VmExecutionException("expected string to be on heap")
|
throw VmExecutionException("expected string to be on heap")
|
||||||
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string
|
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user