registers

This commit is contained in:
Irmen de Jong 2019-06-25 22:48:40 +02:00
parent 343978d164
commit d68360461b
11 changed files with 102 additions and 92 deletions

View File

@ -335,6 +335,8 @@ interface Node {
if(this is Label && this.name.startsWith("builtin::")) {
return BuiltinFunctionScopePlaceholder
}
if(this is GlobalNamespace)
return this
throw FatalAstException("scope missing from $this")
}
}
@ -527,14 +529,10 @@ class Module(override val name: String,
val importedBy = mutableListOf<Module>()
val imports = mutableSetOf<Module>()
override fun linkParents(parent: Node) {
this.parent=parent
}
var loadAddress: Int = 0 // can be set with the %address directive
fun linkParents() {
parent = ParentSentinel
override fun linkParents(parent: Node) {
this.parent = parent
statements.forEach {it.linkParents(this)}
}
@ -544,14 +542,14 @@ class Module(override val name: String,
}
class GlobalNamespace(val modules: List<Module>): INameScope {
class GlobalNamespace(val modules: List<Module>): Node, INameScope {
override val name = "<<<global>>>"
override val position = Position("<<<global>>>", 0, 0, 0)
override val statements = mutableListOf<IStatement>()
override val parent: Node = ParentSentinel
override var parent: Node = ParentSentinel
override fun linkParents(parent: Node) {
modules.forEach { it.linkParents(ParentSentinel) }
modules.forEach { it.linkParents(this) }
}
override fun lookup(scopedName: List<String>, localContext: Node): IStatement? {

View File

@ -163,7 +163,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro
// additional interation count variable in their scope.
if(forLoop.loopRegister!=null) {
if(forLoop.decltype!=null)
checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position))
checkResult.add(SyntaxError("register loop variables have a fixed implicit datatype", forLoop.position))
if(forLoop.loopRegister == Register.X)
printWarning("writing to the X register is dangerous, because it's used as an internal pointer", forLoop.position)
} else if(forLoop.loopVar!=null) {

View File

@ -6,7 +6,6 @@ package prog8.ast
*/
internal fun Module.checkImportedValid() {
this.linkParents()
val checker = ImportedAstChecker()
checker.process(this)
printErrors(checker.result(), name)

View File

@ -169,7 +169,7 @@ class AstVm(val program: Program) {
}
}
is BuiltinFunctionStatementPlaceholder -> {
TODO("$stmt")
TODO("builtinfun $stmt")
}
is Return -> throw LoopControlReturn(stmt.values.map { evaluate(it, program, runtimeVariables, ::executeSubroutine) })
is Continue -> throw LoopControlContinue()
@ -181,13 +181,14 @@ class AstVm(val program: Program) {
if(target!=null) {
when {
target.identifier!=null -> {
val ident = stmt.definingScope().lookup(target.identifier.nameInSource, stmt) as VarDecl
val ident = stmt.definingScope().lookup(target.identifier.nameInSource, stmt) as? VarDecl
?: throw VmExecutionException("can't find assignment target ${target.identifier}")
val value = evaluate(stmt.value, program, runtimeVariables, ::executeSubroutine)
val identScope = ident.definingScope()
runtimeVariables.set(identScope, ident.name, value)
}
target.memoryAddress!=null -> {
TODO("$stmt")
TODO("assign memory $stmt")
}
target.arrayindexed!=null -> {
val array = evaluate(target.arrayindexed.identifier, program, runtimeVariables, ::executeSubroutine)
@ -220,7 +221,7 @@ class AstVm(val program: Program) {
}
}
}
else TODO("$stmt")
else TODO("assign multitarget $stmt")
}
is PostIncrDecr -> {
when {
@ -236,15 +237,15 @@ class AstVm(val program: Program) {
runtimeVariables.set(identScope, ident.name, value)
}
stmt.target.memoryAddress!=null -> {
TODO("$stmt")
TODO("postincrdecr memory $stmt")
}
stmt.target.arrayindexed!=null -> {
TODO("$stmt")
TODO("postincrdecr array $stmt")
}
}
}
is Jump -> {
TODO("$stmt")
TODO("jump $stmt")
}
is InlineAssembly -> {
throw VmExecutionException("can't execute inline assembly in $sub")
@ -258,40 +259,32 @@ class AstVm(val program: Program) {
executeAnonymousScope(stmt.elsepart)
}
is BranchStatement -> {
TODO("$stmt")
TODO("branch $stmt")
}
is ForLoop -> {
val iterable = evaluate(stmt.iterable, program, runtimeVariables, ::executeSubroutine)
if (iterable.type !in IterableDatatypes && iterable !is RuntimeValueRange)
throw VmExecutionException("can only iterate over an iterable value: $stmt")
val iterator: Iterator<Any> = iterable.iterator()
if(stmt.loopRegister!=null)
TODO("for with register")
else if(stmt.loopVar!=null) {
for(v in iterator) {
try {
val value: LiteralValue =
when(stmt.loopVar.resultingDatatype(program)!!) {
DataType.UBYTE -> LiteralValue(DataType.UBYTE, (v as Number).toShort(), position=stmt.position)
DataType.BYTE -> LiteralValue(DataType.BYTE, (v as Number).toShort(), position=stmt.position)
DataType.UWORD -> LiteralValue(DataType.UWORD, wordvalue = (v as Int), position=stmt.position)
DataType.WORD -> LiteralValue(DataType.WORD, wordvalue = (v as Int), position=stmt.position)
DataType.FLOAT -> LiteralValue(DataType.FLOAT, floatvalue = (v as Double), position=stmt.position)
DataType.STR, DataType.STR_S -> LiteralValue(DataType.UBYTE, (v as Char).toShort(), position=stmt.position)
else -> TODO("weird loopvar type")
}
val assignment = Assignment(listOf(AssignTarget(null, stmt.loopVar, null, null,
position=stmt.loopVar.position)), null, value, stmt.iterable.position)
assignment.linkParents(stmt.body)
executeStatement(stmt.body, assignment) // assign the new loop value to the loopvar
executeAnonymousScope(stmt.body) // and run the code
} catch (b: LoopControlBreak) {
break
} catch (c: LoopControlContinue) {
continue
}
val loopvarDt: DataType
val loopvar: IdentifierReference
if(stmt.loopRegister!=null) {
loopvarDt = DataType.UBYTE
loopvar = IdentifierReference(listOf(stmt.loopRegister.name), stmt.position)
}
else {
loopvarDt = stmt.loopVar!!.resultingDatatype(program)!!
loopvar = stmt.loopVar
}
val iterator = iterable.iterator()
for(loopvalue in iterator) {
try {
oneForCycle(stmt, loopvarDt, loopvalue, loopvar)
} catch (b: LoopControlBreak) {
break
} catch (c: LoopControlContinue) {
continue
}
} else TODO("strange for $stmt")
}
}
is WhileLoop -> {
var condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine)
@ -324,6 +317,23 @@ class AstVm(val program: Program) {
}
}
private fun oneForCycle(stmt: ForLoop, loopvarDt: DataType, loopValue: Number, loopVar: IdentifierReference) {
val value: LiteralValue =
when (loopvarDt) {
DataType.UBYTE -> LiteralValue(DataType.UBYTE, loopValue.toShort(), position = stmt.position)
DataType.BYTE -> LiteralValue(DataType.BYTE, loopValue.toShort(), position = stmt.position)
DataType.UWORD -> LiteralValue(DataType.UWORD, wordvalue = (loopValue as Int), position = stmt.position)
DataType.WORD -> LiteralValue(DataType.WORD, wordvalue = (loopValue as Int), position = stmt.position)
DataType.FLOAT -> LiteralValue(DataType.FLOAT, floatvalue = (loopValue as Double), position = stmt.position)
else -> TODO("weird loopvar type $loopvarDt")
}
val assignment = Assignment(listOf(AssignTarget(null, loopVar, null, null,
position = loopVar.position)), null, value, stmt.iterable.position)
assignment.linkParents(stmt.body)
executeStatement(stmt.body, assignment) // assign the new loop value to the loopvar
executeAnonymousScope(stmt.body) // and run the code
}
private fun evaluate(args: List<IExpression>): List<RuntimeValue> = args.map { evaluate(it, program, runtimeVariables, ::executeSubroutine) }
private fun performBuiltinFunction(name: String, args: List<RuntimeValue>) {

View File

@ -16,7 +16,7 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
return RuntimeValue.from(expr, program.heap)
}
is PrefixExpression -> {
TODO("$expr")
TODO("prefixexpr $expr")
}
is BinaryExpression -> {
val left = evaluate(expr.left, program, runtimeVars, executeSubroutine)
@ -61,14 +61,12 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
return RuntimeValue(DataType.UWORD, heapId)
}
is DirectMemoryRead -> {
TODO("$expr")
TODO("memoryread $expr")
}
is DirectMemoryWrite -> {
TODO("$expr")
}
is RegisterExpr -> {
TODO("$expr")
TODO("memorywrite $expr")
}
is RegisterExpr -> return runtimeVars.get(program.namespace, expr.register.name)
is IdentifierReference -> {
val scope = expr.definingScope()
val variable = scope.lookup(expr.nameInSource, expr)
@ -76,7 +74,7 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
val stmt = scope.lookup(listOf(variable.name), expr)!!
return runtimeVars.get(stmt.definingScope(), variable.name)
} else
TODO("$variable")
TODO("weird ref $variable")
}
is FunctionCall -> {
val sub = expr.target.targetStatement(program.namespace)

View File

@ -6,6 +6,26 @@ import prog8.compiler.RuntimeValue
class VariablesCreator(private val runtimeVariables: RuntimeVariables, private val heap: HeapValues) : IAstProcessor {
override fun process(program: Program) {
// define the three registers as global variables
runtimeVariables.define(program.namespace, Register.A.name, RuntimeValue(DataType.UBYTE, 0))
runtimeVariables.define(program.namespace, Register.X.name, RuntimeValue(DataType.UBYTE, 0))
runtimeVariables.define(program.namespace, Register.Y.name, RuntimeValue(DataType.UBYTE, 0))
val globalpos = Position("<<global>>", 0, 0, 0)
val vdA = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.A.name, LiteralValue.optimalInteger(0, globalpos), globalpos)
val vdX = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.X.name, LiteralValue.optimalInteger(0, globalpos), globalpos)
val vdY = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.Y.name, LiteralValue.optimalInteger(0, globalpos), globalpos)
vdA.linkParents(program.namespace)
vdX.linkParents(program.namespace)
vdY.linkParents(program.namespace)
program.namespace.statements.add(vdA)
program.namespace.statements.add(vdX)
program.namespace.statements.add(vdY)
super.process(program)
}
override fun process(decl: VarDecl): IStatement {
if(decl.type==VarDeclType.VAR) {
val value = when (decl.datatype) {

View File

@ -502,7 +502,7 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
}
}
open fun iterator(): Iterator<Any> {
open fun iterator(): Iterator<Number> {
return when (type) {
in StringDatatypes -> {
Petscii.encodePetscii(str!!, true).iterator()
@ -517,7 +517,7 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
class RuntimeValueRange(type: DataType, val range: IntProgression): RuntimeValue(type, 0) {
override fun iterator(): Iterator<Any> {
override fun iterator(): Iterator<Number> {
return range.iterator()
}
}

View File

@ -533,7 +533,7 @@ class ConstantFolding(private val program: Program) : IAstProcessor {
val rangeTo = iterableRange.to as? LiteralValue
if(rangeFrom==null || rangeTo==null) return resultStmt
val loopvar = resultStmt.loopVar!!.targetVarDecl(program.namespace)
val loopvar = resultStmt.loopVar?.targetVarDecl(program.namespace)
if(loopvar!=null) {
val stepLiteral = iterableRange.step as? LiteralValue
when(loopvar.datatype) {

View File

@ -21,7 +21,7 @@ internal fun Program.constantFold() {
optimizer.errors.forEach { System.err.println(it) }
throw ParsingFailedError("There are ${optimizer.errors.size} errors.")
} else {
modules.forEach { it.linkParents() } // re-link in final configuration
modules.forEach { it.linkParents(namespace) } // re-link in final configuration
}
}
@ -37,7 +37,7 @@ internal fun Program.optimizeStatements(optimizeInlining: Boolean): Int {
namescope.statements.addAll(idx, scope.statements)
}
}
modules.forEach { it.linkParents() } // re-link in final configuration
modules.forEach { it.linkParents(this.namespace) } // re-link in final configuration
return optimizer.optimizationsDone
}

View File

@ -66,9 +66,9 @@ internal fun importModule(program: Program, stream: CharStream, modulePath: Path
// tokens.commentTokens().forEach { println(it) }
// convert to Ast
val moduleAst = parseTree.toAst(moduleName.toString(), isLibrary, modulePath)
val moduleAst = parseTree.toAst(moduleName, isLibrary, modulePath)
moduleAst.program = program
moduleAst.linkParents()
moduleAst.linkParents(program.namespace)
program.modules.add(moduleAst)
// process additional imports

View File

@ -4,38 +4,23 @@
~ main {
sub start() {
ubyte i=99
for ubyte j in 20 to 40 step 5 {
c64scr.print_ub(j)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for uword j in 200 to 400 step 5 {
c64scr.print_uw(j)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for i in 200 to 50 step -20 {
c64scr.print_ub(i)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for i in "hello" {
c64scr.print_ub(i)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for i in [1,2,3,4,5] {
c64scr.print_ub(i)
c64.CHROUT(',')
}
c64.CHROUT('\n')
Y=99
A=200
Y=A
ubyte r = subt()
c64scr.print_ub(r)
c64.CHROUT('\n')
}
sub subt() -> ubyte {
for Y in 20 to 50 step 5 {
c64scr.print_ub(Y)
c64.CHROUT(',')
if Y>40
return 99
}
c64.CHROUT('\n')
return 10
}
}