diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 275485368..2f6035c0c 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -10,6 +10,7 @@ import prog8.optimizing.simplifyExpressions import prog8.parser.ParsingFailedError import prog8.parser.importLibraryModule import prog8.parser.importModule +import prog8.parser.moduleName import java.io.File import java.io.PrintStream import java.lang.Exception @@ -73,7 +74,7 @@ private fun compileMain(args: Array) { val totalTime = measureTimeMillis { // import main module and everything it needs println("Parsing...") - val programAst = Program(filepath.fileName.toString(), mutableListOf()) + val programAst = Program(moduleName(filepath.fileName), mutableListOf()) importModule(programAst, filepath) val compilerOptions = determineCompilationOptions(programAst) @@ -187,17 +188,17 @@ private fun compileMain(args: Array) { fun determineCompilationOptions(program: Program): CompilationOptions { - val moduleAst = program.modules.first() - val options = moduleAst.statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.toSet() - val outputType = (moduleAst.statements.singleOrNull { it is Directive && it.directive == "%output" } + val mainModule = program.modules.first() + val outputType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" } as? Directive)?.args?.single()?.name?.toUpperCase() - val launcherType = (moduleAst.statements.singleOrNull { it is Directive && it.directive == "%launcher" } + val launcherType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" } as? Directive)?.args?.single()?.name?.toUpperCase() - moduleAst.loadAddress = (moduleAst.statements.singleOrNull { it is Directive && it.directive == "%address" } + mainModule.loadAddress = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%address" } as? Directive)?.args?.single()?.int ?: 0 - val zpoption: String? = (moduleAst.statements.singleOrNull { it is Directive && it.directive == "%zeropage" } + val zpoption: String? = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%zeropage" } as? Directive)?.args?.single()?.name?.toUpperCase() - val floatsEnabled = options.any { it.name == "enable_floats" } + val allOptions = program.modules.flatMap { it.statements }.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.toSet() + val floatsEnabled = allOptions.any { it.name == "enable_floats" } val zpType: ZeropageType = if (zpoption == null) if(floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE @@ -208,7 +209,7 @@ fun determineCompilationOptions(program: Program): CompilationOptions { ZeropageType.KERNALSAFE // error will be printed by the astchecker } - val zpReserved = moduleAst.statements + val zpReserved = mainModule.statements .asSequence() .filter { it is Directive && it.directive == "%zpreserved" } .map { (it as Directive).args } diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index efed132da..416d31684 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -298,6 +298,10 @@ interface IAstProcessor { process(addressOf.identifier) return addressOf } + + fun process(inlineAssembly: InlineAssembly): IStatement { + return inlineAssembly + } } @@ -312,6 +316,8 @@ interface Node { return findParentNode(this)!! } + fun definingSubroutine(): Subroutine? = findParentNode(this) + fun definingScope(): INameScope { val scope = findParentNode(this) if(scope!=null) { @@ -384,12 +390,12 @@ interface INameScope { is WhileLoop -> subscopes[stmt.body.name] = stmt.body is BranchStatement -> { subscopes[stmt.truepart.name] = stmt.truepart - if(stmt.elsepart.isNotEmpty()) + if(stmt.elsepart.containsCodeOrVars()) subscopes[stmt.elsepart.name] = stmt.elsepart } is IfStatement -> { subscopes[stmt.truepart.name] = stmt.truepart - if(stmt.elsepart.isNotEmpty()) + if(stmt.elsepart.containsCodeOrVars()) subscopes[stmt.elsepart.name] = stmt.elsepart } } @@ -445,8 +451,8 @@ interface INameScope { } } - fun isEmpty() = statements.isEmpty() - fun isNotEmpty() = statements.isNotEmpty() + fun containsCodeOrVars() = statements.any { it !is Directive || it.directive == "%asminclude" || it.directive == "%asm"} + fun containsNoCodeNorVars() = !containsCodeOrVars() fun remove(stmt: IStatement) { val removed = statements.remove(stmt) @@ -486,6 +492,17 @@ class Program(val name: String, val modules: MutableList) { val loadAddress: Int get() = modules.first().loadAddress + + fun entrypoint(): Subroutine? { + val mainBlocks = modules.flatMap { it.statements }.filter { b -> b is Block && b.name=="main" }.map { it as Block } + if(mainBlocks.size > 1) + throw FatalAstException("more than one 'main' block") + return if(mainBlocks.isEmpty()) { + null + } else { + mainBlocks[0].subScopes()["start"] as Subroutine? + } + } } @@ -617,19 +634,6 @@ open class Return(var values: List, override val position: Position override fun toString(): String { return "Return(values: $values, pos=$position)" } - - fun definingSubroutine(): Subroutine? { - var scope = definingScope() - while(scope !is GlobalNamespace) { - if(scope is Subroutine) - return scope - val parent = scope.parent - if(parent is Subroutine) - return parent - scope = parent.definingScope() - } - return null - } } @@ -1639,7 +1643,7 @@ class InlineAssembly(val assembly: String, override val position: Position) : IS this.parent = parent } - override fun process(processor: IAstProcessor) = this + override fun process(processor: IAstProcessor) = processor.process(this) } @@ -1692,7 +1696,7 @@ class Subroutine(override val name: String, override var statements: MutableList, override val position: Position) : IStatement, INameScope { override lateinit var parent: Node - val calledBy = mutableSetOf() + val calledBy = mutableSetOf() val calls = mutableSetOf() val scopedname: String by lazy { makeScopedName(name) } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 9960b32da..16d7c2b05 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -148,7 +148,7 @@ private class AstChecker(private val program: Program, } override fun process(forLoop: ForLoop): IStatement { - if(forLoop.body.isEmpty()) + if(forLoop.body.containsNoCodeNorVars()) printWarning("for loop body is empty", forLoop.position) if(!forLoop.iterable.isIterable(program)) { diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index 074149ed8..3a2a276b6 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -170,7 +170,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro } else if(forLoop.loopVar!=null) { val varName = forLoop.loopVar.nameInSource.last() if(forLoop.decltype!=null) { - val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first()) + val existing = if(forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first()) if(existing==null) { // create the local scoped for loop variable itself val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, true, null, false, varName, null, forLoop.loopVar.position) @@ -182,7 +182,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro } if(forLoop.iterable !is RangeExpr) { - val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(listOf(ForLoop.iteratorLoopcounterVarname), forLoop.body.statements.first()) + val existing = if(forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(listOf(ForLoop.iteratorLoopcounterVarname), forLoop.body.statements.first()) if(existing==null) { // create loop iteration counter variable (without value, to avoid an assignment) val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, true, null, false, ForLoop.iteratorLoopcounterVarname, null, forLoop.loopVar.position) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 12a44d613..2d30dc37f 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -191,7 +191,7 @@ internal class Compiler(private val program: Program): IAstProcessor { return r } else { // asmsub - if(subroutine.isNotEmpty()) + if(subroutine.containsCodeOrVars()) throw CompilerException("kernel subroutines (with memory address) can't have a body: $subroutine") prog.memoryPointer(subroutine.scopedname, subroutine.asmAddress, DataType.UBYTE) // the datatype is a bit of a dummy in this case @@ -426,7 +426,7 @@ internal class Compiler(private val program: Program): IAstProcessor { * if the branch statement just contains jumps, more efficient code is generated. * (just the appropriate branching instruction is outputted!) */ - if(branch.elsepart.isEmpty() && branch.truepart.isEmpty()) + if(branch.elsepart.containsNoCodeNorVars() && branch.truepart.containsNoCodeNorVars()) return fun branchOpcode(branch: BranchStatement, complement: Boolean) = @@ -470,7 +470,7 @@ internal class Compiler(private val program: Program): IAstProcessor { val labelElse = makeLabel(branch, "else") val labelEnd = makeLabel(branch, "end") val opcode = branchOpcode(branch, true) - if (branch.elsepart.isEmpty()) { + if (branch.elsepart.containsNoCodeNorVars()) { prog.instr(opcode, callLabel = labelEnd) translate(branch.truepart) prog.label(labelEnd) @@ -535,7 +535,7 @@ internal class Compiler(private val program: Program): IAstProcessor { else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt") } val labelEnd = makeLabel(stmt, "end") - if(stmt.elsepart.isEmpty()) { + if(stmt.elsepart.containsNoCodeNorVars()) { prog.instr(conditionJumpOpcode, callLabel = labelEnd) translate(stmt.truepart) prog.label(labelEnd) @@ -1620,7 +1620,7 @@ internal class Compiler(private val program: Program): IAstProcessor { } private fun translate(loop: ForLoop) { - if(loop.body.isEmpty()) return + if(loop.body.containsNoCodeNorVars()) return prog.line(loop.position) val loopVarName: String val loopVarDt: DataType @@ -2154,18 +2154,7 @@ internal class Compiler(private val program: Program): IAstProcessor { val scopeprefix = if(args[1].str!!.isNotBlank()) "${args[1].str}\t.proc\n" else "" val scopeprefixEnd = if(args[1].str!!.isNotBlank()) "\t.pend\n" else "" val filename=args[0].str!! - val sourcecode = - if(filename.startsWith("library:")) { - val resource = tryGetEmbeddedResource(filename.substring(8)) ?: throw IllegalArgumentException("library file '$filename' not found") - resource.bufferedReader().use { it.readText() } - } else { - // first try in the same folder as where the containing file was imported from - val sib = source.resolveSibling(filename) - if(sib.toFile().isFile) - sib.toFile().readText() - else - File(filename).readText() - } + val sourcecode = loadAsmIncludeFile(filename, source) prog.instr(Opcode.INLINE_ASSEMBLY, callLabel=null, callLabel2=scopeprefix+sourcecode+scopeprefixEnd) } @@ -2179,3 +2168,19 @@ internal class Compiler(private val program: Program): IAstProcessor { } } + + +fun loadAsmIncludeFile(filename: String, source: Path): String { + return if (filename.startsWith("library:")) { + val resource = tryGetEmbeddedResource(filename.substring(8)) + ?: throw IllegalArgumentException("library file '$filename' not found") + resource.bufferedReader().use { it.readText() } + } else { + // first try in the same folder as where the containing file was imported from + val sib = source.resolveSibling(filename) + if (sib.toFile().isFile) + sib.toFile().readText() + else + File(filename).readText() + } +} diff --git a/compiler/src/prog8/optimizing/CallGraphBuilder.kt b/compiler/src/prog8/optimizing/CallGraphBuilder.kt index 07d09bae4..382c1b0e5 100644 --- a/compiler/src/prog8/optimizing/CallGraphBuilder.kt +++ b/compiler/src/prog8/optimizing/CallGraphBuilder.kt @@ -1,16 +1,17 @@ package prog8.optimizing import prog8.ast.* +import prog8.compiler.loadAsmIncludeFile class CallGraphBuilder(private val program: Program): IAstProcessor { private val modulesImporting = mutableMapOf>().withDefault { mutableSetOf() } private val modulesImportedBy = mutableMapOf>().withDefault { mutableSetOf() } - private val subroutinesCalling = mutableMapOf>().withDefault { mutableSetOf() } - private val subroutinesCalledBy = mutableMapOf>().withDefault { mutableSetOf() } + private val subroutinesCalling = mutableMapOf>().withDefault { mutableSetOf() } + private val subroutinesCalledBy = mutableMapOf>().withDefault { mutableSetOf() } - private fun forAllSubroutines(scope: INameScope, sub: (s: Subroutine) -> Unit) { + fun forAllSubroutines(scope: INameScope, sub: (s: Subroutine) -> Unit) { fun findSubs(scope: INameScope) { scope.statements.forEach { if(it is Subroutine) @@ -32,9 +33,6 @@ class CallGraphBuilder(private val program: Program): IAstProcessor { it.importedBy.addAll(modulesImportedBy.getValue(it)) it.imports.addAll(modulesImporting.getValue(it)) - if(it.isLibraryModule && it.importedBy.isEmpty()) - it.importedBy.add(it) // don't discard auto-imported library module - forAllSubroutines(it) { sub -> sub.calledBy.clear() sub.calls.clear() @@ -42,6 +40,7 @@ class CallGraphBuilder(private val program: Program): IAstProcessor { sub.calledBy.addAll(subroutinesCalledBy.getValue(sub)) sub.calls.addAll(subroutinesCalling.getValue(sub)) } + } val rootmodule = program.modules.first() @@ -49,21 +48,27 @@ class CallGraphBuilder(private val program: Program): IAstProcessor { } override fun process(directive: Directive): IStatement { + val thisModule = directive.definingModule() if(directive.directive=="%import") { val importedModule: Module = program.modules.single { it.name==directive.args[0].name } - val thisModule = directive.definingModule() modulesImporting[thisModule] = modulesImporting.getValue(thisModule).plus(importedModule) modulesImportedBy[importedModule] = modulesImportedBy.getValue(importedModule).plus(thisModule) + } else if (directive.directive=="%asminclude") { + val asm = loadAsmIncludeFile(directive.args[0].str!!, thisModule.source) + val scope = directive.definingScope() + scanAssemblyCode(asm, directive, scope) } + return super.process(directive) } override fun process(functionCall: FunctionCall): IExpression { val otherSub = functionCall.target.targetSubroutine(program.namespace) if(otherSub!=null) { - val thisSub = functionCall.definingScope() as Subroutine - subroutinesCalling[thisSub] = subroutinesCalling.getValue(thisSub).plus(otherSub) - subroutinesCalledBy[otherSub] = subroutinesCalledBy.getValue(otherSub).plus(thisSub) + functionCall.definingSubroutine()?.let { thisSub -> + subroutinesCalling[thisSub] = subroutinesCalling.getValue(thisSub).plus(otherSub) + subroutinesCalledBy[otherSub] = subroutinesCalledBy.getValue(otherSub).plus(thisSub) + } } return super.process(functionCall) } @@ -71,9 +76,10 @@ class CallGraphBuilder(private val program: Program): IAstProcessor { override fun process(functionCallStatement: FunctionCallStatement): IStatement { val otherSub = functionCallStatement.target.targetSubroutine(program.namespace) if(otherSub!=null) { - val thisSub = functionCallStatement.definingScope() as Subroutine - subroutinesCalling[thisSub] = subroutinesCalling.getValue(thisSub).plus(otherSub) - subroutinesCalledBy[otherSub] = subroutinesCalledBy.getValue(otherSub).plus(thisSub) + functionCallStatement.definingSubroutine()?.let { thisSub -> + subroutinesCalling[thisSub] = subroutinesCalling.getValue(thisSub).plus(otherSub) + subroutinesCalledBy[otherSub] = subroutinesCalledBy.getValue(otherSub).plus(thisSub) + } } return super.process(functionCallStatement) } @@ -81,10 +87,55 @@ class CallGraphBuilder(private val program: Program): IAstProcessor { override fun process(jump: Jump): IStatement { val otherSub = jump.identifier?.targetSubroutine(program.namespace) if(otherSub!=null) { - val thisSub = jump.definingScope() as Subroutine - subroutinesCalling[thisSub] = subroutinesCalling.getValue(thisSub).plus(otherSub) - subroutinesCalledBy[otherSub] = subroutinesCalledBy.getValue(otherSub).plus(thisSub) + jump.definingSubroutine()?.let { thisSub -> + subroutinesCalling[thisSub] = subroutinesCalling.getValue(thisSub).plus(otherSub) + subroutinesCalledBy[otherSub] = subroutinesCalledBy.getValue(otherSub).plus(thisSub) + } } return super.process(jump) } + + override fun process(inlineAssembly: InlineAssembly): IStatement { + // parse inline asm for subroutine calls (jmp, jsr) + val scope = inlineAssembly.definingScope() + scanAssemblyCode(inlineAssembly.assembly, inlineAssembly, scope) + return super.process(inlineAssembly) + } + + private fun scanAssemblyCode(asm: String, context: Node, scope: INameScope) { + val asmJumpRx = Regex("""[\-+a-zA-Z0-9_ \t]+(jmp|jsr)[ \t]+(\S+).*""", RegexOption.IGNORE_CASE) + val asmRefRx = Regex("""[\-+a-zA-Z0-9_ \t]+(...)[ \t]+(\S+).*""", RegexOption.IGNORE_CASE) + asm.lines().forEach { line -> + val matches = asmJumpRx.matchEntire(line) + if (matches != null) { + val jumptarget = matches.groups[2]?.value + if (jumptarget != null && (jumptarget[0].isLetter() || jumptarget[0] == '_')) { + val node = program.namespace.lookup(jumptarget.split('.'), context) + if (node is Subroutine) { + subroutinesCalling[scope] = subroutinesCalling.getValue(scope).plus(node) + subroutinesCalledBy[node] = subroutinesCalledBy.getValue(node).plus(scope) + } else if(jumptarget.contains('.')) { + // maybe only the first part already refers to a subroutine + val node2 = program.namespace.lookup(listOf(jumptarget.substringBefore('.')), context) + if (node2 is Subroutine) { + subroutinesCalling[scope] = subroutinesCalling.getValue(scope).plus(node2) + subroutinesCalledBy[node2] = subroutinesCalledBy.getValue(node2).plus(scope) + } + } + } + } else { + val matches2 = asmRefRx.matchEntire(line) + if (matches2 != null) { + val target= matches2.groups[2]?.value + if (target != null && (target[0].isLetter() || target[0] == '_')) { + val node = program.namespace.lookup(listOf(target.substringBefore('.')), context) + if (node is Subroutine) { + subroutinesCalling[scope] = subroutinesCalling.getValue(scope).plus(node) + subroutinesCalledBy[node] = subroutinesCalledBy.getValue(node).plus(scope) + } + } + } + } + } + } } diff --git a/compiler/src/prog8/optimizing/StatementOptimizer.kt b/compiler/src/prog8/optimizing/StatementOptimizer.kt index 9e272316c..180fd05c3 100644 --- a/compiler/src/prog8/optimizing/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizing/StatementOptimizer.kt @@ -7,18 +7,18 @@ import kotlin.math.floor /* + TODO FIX THE OPTIMIZER: RESULTS IN WRONG CODE FOR THE primes.p8 EXAMPLE + + todo: subroutines with 1 or 2 byte args or 1 word arg can be converted to asm sub calling convention (args in registers) + todo: implement usage counters for variables (locals and heap), blocks. Remove if count is zero. - todo: implement usage counters for blocks, variables, subroutines, heap variables. Then: - todo remove unused: subroutines, blocks (in this order) - todo remove unused: variable declarations - todo remove unused strings and arrays from the heap - todo inline subroutines that are called exactly once (regardless of their size) - todo inline subroutines that are only called a few times (max 3?) - todo inline subroutines that are "sufficiently small" (0-3 statements) + todo inline subroutines that are called exactly once (regardless of their size) + todo inline subroutines that are only called a few times (max 3?) (if < 20 statements) + todo inline all subroutines that are "very small" (0-3 statements) - todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to) + todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to) + print warning about this */ class StatementOptimizer(private val program: Program) : IAstProcessor { @@ -33,22 +33,50 @@ class StatementOptimizer(private val program: Program) : IAstProcessor { val callgraph = CallGraphBuilder(program) callgraph.process(program) + // TODO remove unused variables (local and global) + + // remove all subroutines that aren't called, or are empty + val removeSubroutines = mutableSetOf() + val entrypoint = program.entrypoint() + program.modules.forEach { + callgraph.forAllSubroutines(it) { sub -> + if(sub !== entrypoint && (sub.calledBy.isEmpty() || (sub.containsNoCodeNorVars() && !sub.isAsmSubroutine))) + removeSubroutines.add(sub) + } + } + + if(removeSubroutines.isNotEmpty()) { + removeSubroutines.forEach { it.definingScope().statements.remove(it) } + } + + val removeBlocks = mutableSetOf() + // TODO remove blocks that have no incoming references + program.modules.flatMap { it.statements }.filterIsInstance().forEach { block -> + if (block.containsNoCodeNorVars()) + removeBlocks.add(block) + } + + if(removeBlocks.isNotEmpty()) { + removeBlocks.forEach { it.definingScope().statements.remove(it) } + } + // remove modules that are not imported, or are empty val removeModules = mutableSetOf() program.modules.forEach { - if(it.importedBy.isEmpty() || it.isEmpty()) { - printWarning("discarding empty or unused module: ${it.name}") + if (!it.isLibraryModule && (it.importedBy.isEmpty() || it.containsNoCodeNorVars())) removeModules.add(it) - } } - program.modules.removeAll(removeModules) + + if(removeModules.isNotEmpty()) { + println("[debug] removing ${removeModules.size} empty/unused modules") + program.modules.removeAll(removeModules) + } super.process(program) } override fun process(block: Block): IStatement { - if(block.statements.isEmpty()) { - // remove empty block + if(block.containsNoCodeNorVars()) { optimizationsDone++ statementsToRemove.add(block) } @@ -56,12 +84,10 @@ class StatementOptimizer(private val program: Program) : IAstProcessor { } override fun process(subroutine: Subroutine): IStatement { - println("STMT OPTIMIZE $subroutine ${subroutine.calledBy} ${subroutine.calls}") super.process(subroutine) if(subroutine.asmAddress==null) { - if(subroutine.statements.isEmpty()) { - // remove empty subroutine + if(subroutine.containsNoCodeNorVars()) { optimizationsDone++ statementsToRemove.add(subroutine) } @@ -212,13 +238,13 @@ class StatementOptimizer(private val program: Program) : IAstProcessor { override fun process(ifStatement: IfStatement): IStatement { super.process(ifStatement) - if(ifStatement.truepart.isEmpty() && ifStatement.elsepart.isEmpty()) { + if(ifStatement.truepart.containsNoCodeNorVars() && ifStatement.elsepart.containsNoCodeNorVars()) { statementsToRemove.add(ifStatement) optimizationsDone++ return ifStatement } - if(ifStatement.truepart.isEmpty() && ifStatement.elsepart.isNotEmpty()) { + if(ifStatement.truepart.containsNoCodeNorVars() && ifStatement.elsepart.containsCodeOrVars()) { // invert the condition and move else part to true part ifStatement.truepart = ifStatement.elsepart ifStatement.elsepart = AnonymousScope(mutableListOf(), ifStatement.elsepart.position) @@ -246,7 +272,7 @@ class StatementOptimizer(private val program: Program) : IAstProcessor { override fun process(forLoop: ForLoop): IStatement { super.process(forLoop) - if(forLoop.body.isEmpty()) { + if(forLoop.body.containsNoCodeNorVars()) { // remove empty for loop statementsToRemove.add(forLoop) optimizationsDone++ diff --git a/compiler/src/prog8/parser/ModuleParsing.kt b/compiler/src/prog8/parser/ModuleParsing.kt index 5966e18d3..02112c256 100644 --- a/compiler/src/prog8/parser/ModuleParsing.kt +++ b/compiler/src/prog8/parser/ModuleParsing.kt @@ -22,8 +22,11 @@ private class LexerErrorListener: BaseErrorListener() { internal class CustomLexer(val modulePath: Path, input: CharStream?) : prog8Lexer(input) +internal fun moduleName(fileName: Path) = fileName.toString().substringBeforeLast('.') + + fun importModule(program: Program, filePath: Path): Module { - print("importing '${filePath.fileName}'") + print("importing '${moduleName(filePath.fileName)}'") if(filePath.parent!=null) { var importloc = filePath.toString() val curdir = Paths.get("").toAbsolutePath().toString() @@ -48,7 +51,7 @@ fun importLibraryModule(program: Program, name: String): Module? { } private fun importModule(program: Program, stream: CharStream, modulePath: Path, isLibrary: Boolean): Module { - val moduleName = modulePath.fileName + val moduleName = moduleName(modulePath.fileName) val lexer = CustomLexer(modulePath, stream) val lexerErrors = LexerErrorListener() lexer.addErrorListener(lexerErrors) diff --git a/examples/primes.p8 b/examples/primes.p8 index f89672ed3..51e40c1b6 100644 --- a/examples/primes.p8 +++ b/examples/primes.p8 @@ -3,6 +3,9 @@ ~ main { + ; TODO FIX THE COMPILER OPTIMIZER ; RESULTS IN WRONG CODE FOR THIS PROGRAM + + ubyte[256] sieve ubyte candidate_prime = 2 ; is increased in the loop