From 0b4135698e26f3cc872f2cdf773a54dc5ea78b61 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 6 Sep 2018 01:35:26 +0200 Subject: [PATCH] reorder statments to please the compiler later --- docs/source/programming.rst | 2 ++ il65/examples/test.ill | 5 +-- il65/il65.sh | 2 +- il65/src/il65/Main.kt | 5 ++- il65/src/il65/ast/StmtReorderer.kt | 51 ++++++++++++++++++++++++++++++ il65/src/il65/compiler/Compiler.kt | 11 ++----- 6 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 il65/src/il65/ast/StmtReorderer.kt diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 2029f8ceb..9a7331ce4 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -115,6 +115,8 @@ A block is also a *scope* in your program so the symbols in the block don't clas symbols of the same name defined elsewhere in the same file or in another file. You can refer to the symbols in a particular block by using a *dotted name*: ``blockname.symbolname``. Labels inside a subroutine are appended again to that; ``blockname.subroutinename.label``. +A symbol name that's not a dotted name is searched for in the current scope, if it's not found there, +one scope higher, and so on until it is found. Every symbol is 'public' and can be accessed from elsewhere given its dotted name. diff --git a/il65/examples/test.ill b/il65/examples/test.ill index 3199244b2..f431ab8f7 100644 --- a/il65/examples/test.ill +++ b/il65/examples/test.ill @@ -124,8 +124,9 @@ sub start () -> () { word dinges = 0 - dinges=round(blerp1) - A=round(blerp1) + word blerp1 =99 + dinges=blerp1 + A=blerp1 return } diff --git a/il65/il65.sh b/il65/il65.sh index 777016001..6cbc115b7 100755 --- a/il65/il65.sh +++ b/il65/il65.sh @@ -2,6 +2,6 @@ IL65_LIBDIR=../lib65 IL65CLASSPATH=out/production/il65 -LIBJARS=/opt/irmen/idea-2018/plugins/Kotlin/lib/kotlin-stdlib.jar:antlr/lib/antlr-runtime-4.7.1.jar +LIBJARS=/opt/irmen/idea-2018/plugins/Kotlin/lib/kotlin-stdlib.jar:/opt/irmen/idea-2018/plugins/Kotlin/lib/kotlin-reflect.jar:antlr/lib/antlr-runtime-4.7.1.jar java -Dil65.libdir=${IL65_LIBDIR} -cp ${IL65CLASSPATH}:${LIBJARS} il65.MainKt $* diff --git a/il65/src/il65/Main.kt b/il65/src/il65/Main.kt index e8ab1a622..3d4e09507 100644 --- a/il65/src/il65/Main.kt +++ b/il65/src/il65/Main.kt @@ -51,15 +51,14 @@ fun main(args: Array) { moduleAst.checkValid(globalNameSpaceBeforeOptimization, compilerOptions) // check if tree is valid val allScopedSymbolDefinitions = moduleAst.checkIdentifiers() moduleAst.optimizeStatements(globalNameSpaceBeforeOptimization, allScopedSymbolDefinitions) - val globalNamespaceAfterOptimize = moduleAst.definingScope() // it could have changed in the meantime + StatementReorderer().process(moduleAst) // reorder statements to please the compiler later + val globalNamespaceAfterOptimize = moduleAst.definingScope() // create it again, it could have changed in the meantime moduleAst.checkValid(globalNamespaceAfterOptimize, compilerOptions) // check if final tree is valid moduleAst.checkRecursion() // check if there are recursive subroutine calls // globalNamespaceAfterOptimize.debugPrint() - // compile the syntax tree into intermediate form, and optimize that - val compiler = Compiler(compilerOptions) val intermediate = compiler.compile(moduleAst) intermediate.optimize() diff --git a/il65/src/il65/ast/StmtReorderer.kt b/il65/src/il65/ast/StmtReorderer.kt new file mode 100644 index 000000000..63035a714 --- /dev/null +++ b/il65/src/il65/ast/StmtReorderer.kt @@ -0,0 +1,51 @@ +package il65.ast + +class StatementReorderer: IAstProcessor { + // Reorders the statements in a way the compiler needs. + // - 'main' block must be the very first statement. + // - in every scope: + // -- the directives '%output', '%launcher', '%zeropage', '%address' and '%option' will come first. + // -- all vardecls then follow. + // -- the remaining statements then follow in their original order. + // - the 'start' subroutine in the 'main' block will be moved to the top immediately following the directives. + + val directivesToMove = setOf("%output", "%launcher", "%zeropage", "%address", "%option") + + override fun process(node: Module) { + val mainBlock = node.statements.single { it is Block && it.name=="main" } + node.statements.remove(mainBlock) + node.statements.add(0, mainBlock) + val varDecls = node.statements.filter { it is VarDecl } + node.statements.removeAll(varDecls) + node.statements.addAll(0, varDecls) + val directives = node.statements.filter {it is Directive && directivesToMove.contains(it.directive)} + node.statements.removeAll(directives) + node.statements.addAll(0, directives) + super.process(node) + } + + override fun process(node: Block): IStatement { + val startSub = node.statements.singleOrNull {it is Subroutine && it.name=="start"} + if(startSub!=null) { + node.statements.remove(startSub) + node.statements.add(0, startSub) + } + val varDecls = node.statements.filter { it is VarDecl } + node.statements.removeAll(varDecls) + node.statements.addAll(0, varDecls) + val directives = node.statements.filter {it is Directive && directivesToMove.contains(it.directive)} + node.statements.removeAll(directives) + node.statements.addAll(0, directives) + return super.process(node) + } + + override fun process(node: Subroutine): IStatement { + val varDecls = node.statements.filter { it is VarDecl } + node.statements.removeAll(varDecls) + node.statements.addAll(0, varDecls) + val directives = node.statements.filter {it is Directive && directivesToMove.contains(it.directive)} + node.statements.removeAll(directives) + node.statements.addAll(0, directives) + return super.process(node) + } +} diff --git a/il65/src/il65/compiler/Compiler.kt b/il65/src/il65/compiler/Compiler.kt index 95525adfe..20645897b 100644 --- a/il65/src/il65/compiler/Compiler.kt +++ b/il65/src/il65/compiler/Compiler.kt @@ -1,8 +1,6 @@ package il65.compiler -import il65.ast.Block -import il65.ast.INameScope -import il65.ast.Module +import il65.ast.* import kotlin.experimental.and import kotlin.math.absoluteValue import kotlin.math.pow @@ -92,14 +90,9 @@ class Compiler(private val options: CompilationOptions) { fun compile(module: Module) : IntermediateForm { println("\nCompiling parsed source code to intermediate code...") - // make sure the 'main' block is the first block. Statement even. - val mainBlock = module.statements.single { it is Block && it.name=="main" } - module.statements.remove(mainBlock) - module.statements.add(0, mainBlock) - val namespace = module.definingScope() - // todo + val namespace = module.definingScope() namespace.debugPrint() module.statements.filter { it is Block }.map {