From 28ab7bbe3447ac0eae54ed5e4b42d090a5b5f9a4 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 5 Sep 2018 22:51:34 +0200 Subject: [PATCH] fix symbol usage tracking, also track scopes themselves. Fix directive option comparisons. --- il65/examples/test.ill | 4 ++-- il65/il65.sh | 7 +++++++ il65/src/il65/Main.kt | 26 +++++++++++++------------- il65/src/il65/ast/AST.kt | 19 +++++++++++-------- il65/src/il65/ast/AstChecker.kt | 18 +++++++++++++++--- il65/src/il65/compiler/Compiler.kt | 4 ---- 6 files changed, 48 insertions(+), 30 deletions(-) create mode 100755 il65/il65.sh diff --git a/il65/examples/test.ill b/il65/examples/test.ill index a93d3f732..e1495c2e6 100644 --- a/il65/examples/test.ill +++ b/il65/examples/test.ill @@ -106,7 +106,7 @@ P_irqd(1) } else X=33 - X= extra233.thingy() ; TODO EHHHH, should be counted as used? + X= extra233.thingy() if(6>36) { @@ -131,7 +131,7 @@ cool: mega: cool: sub ultrafoo() -> () { - X= extra233.thingy() ; TODO EHHHH, should be counted as used? + X= extra233.thingy() return 33 goto main.mega } diff --git a/il65/il65.sh b/il65/il65.sh new file mode 100755 index 000000000..777016001 --- /dev/null +++ b/il65/il65.sh @@ -0,0 +1,7 @@ +#/bin/env sh + +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 + +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 56aaea91a..a503422a5 100644 --- a/il65/src/il65/Main.kt +++ b/il65/src/il65/Main.kt @@ -27,19 +27,6 @@ fun main(args: Array) { moduleAst.linkParents() val globalNameSpaceBeforeOptimization = moduleAst.definingScope() - - // perform syntax checks and optimizations - moduleAst.checkIdentifiers() - moduleAst.optimizeExpressions(globalNameSpaceBeforeOptimization) - moduleAst.checkValid(globalNameSpaceBeforeOptimization) // check if tree is valid - val allScopedSymbolDefinitions = moduleAst.checkIdentifiers() - moduleAst.optimizeStatements(globalNameSpaceBeforeOptimization, allScopedSymbolDefinitions) - val globalNamespaceAfterOptimize = moduleAst.definingScope() // it could have changed in the meantime - moduleAst.checkValid(globalNamespaceAfterOptimize) // check if final tree is valid - moduleAst.checkRecursion() // check if there are recursive subroutine calls - - // globalNamespaceAfterOptimize.debugPrint() - // determine special compiler options val options = moduleAst.statements.filter { it is Directive && it.directive=="%option" }.flatMap { (it as Directive).args }.toSet() @@ -58,6 +45,19 @@ fun main(args: Array) { ) + // perform syntax checks and optimizations + moduleAst.checkIdentifiers() + moduleAst.optimizeExpressions(globalNameSpaceBeforeOptimization) + 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 + 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, globalNamespaceAfterOptimize) diff --git a/il65/src/il65/ast/AST.kt b/il65/src/il65/ast/AST.kt index db1395675..d3044078a 100644 --- a/il65/src/il65/ast/AST.kt +++ b/il65/src/il65/ast/AST.kt @@ -383,7 +383,10 @@ class Module(override val name: String, } override fun registerUsedName(name: String) { + // make sure to also register each scope separately scopedNamesUsed.add(name) + if(name.contains('.')) + registerUsedName(name.substringBeforeLast('.')) } } } @@ -412,7 +415,7 @@ class Block(override val name: String, } -class Directive(val directive: String, val args: List) : IStatement { +data class Directive(val directive: String, val args: List) : IStatement { override var position: Position? = null override lateinit var parent: Node @@ -425,7 +428,7 @@ class Directive(val directive: String, val args: List) : IStatemen } -class DirectiveArg(val str: String?, val name: String?, val int: Int?) : Node { +data class DirectiveArg(val str: String?, val name: String?, val int: Int?) : Node { override var position: Position? = null override lateinit var parent: Node @@ -435,7 +438,7 @@ class DirectiveArg(val str: String?, val name: String?, val int: Int?) : Node { } -class Label(val name: String) : IStatement { +data class Label(val name: String) : IStatement { override var position: Position? = null override lateinit var parent: Node val scopedname: List by lazy { makeScopedName(name) } @@ -542,7 +545,7 @@ class Assignment(var target: AssignTarget, val aug_op : String?, var value: IExp } } -class AssignTarget(val register: Register?, val identifier: IdentifierReference?) : Node { +data class AssignTarget(val register: Register?, val identifier: IdentifierReference?) : Node { override var position: Position? = null override lateinit var parent: Node @@ -597,7 +600,7 @@ class BinaryExpression(var left: IExpression, val operator: String, var right: I override fun referencesIdentifier(name: String) = left.referencesIdentifier(name) || right.referencesIdentifier(name) } -class LiteralValue(val intvalue: Int? = null, +data class LiteralValue(val intvalue: Int? = null, val floatvalue: Double? = null, val strvalue: String? = null, val arrayvalue: MutableList? = null) : IExpression { @@ -667,7 +670,7 @@ class RegisterExpr(val register: Register) : IExpression { } -class IdentifierReference(val nameInSource: List) : IExpression { +data class IdentifierReference(val nameInSource: List) : IExpression { override var position: Position? = null override lateinit var parent: Node @@ -849,7 +852,7 @@ class Subroutine(override val name: String, } -class SubroutineParameter(val name: String, val register: Register?, val statusflag: Statusflag?) : Node { +data class SubroutineParameter(val name: String, val register: Register?, val statusflag: Statusflag?) : Node { override var position: Position? = null override lateinit var parent: Node @@ -859,7 +862,7 @@ class SubroutineParameter(val name: String, val register: Register?, val statusf } -class SubroutineReturnvalue(val register: Register?, val statusflag: Statusflag?, val clobbered: Boolean) : Node { +data class SubroutineReturnvalue(val register: Register?, val statusflag: Statusflag?, val clobbered: Boolean) : Node { override var position: Position? = null override lateinit var parent: Node diff --git a/il65/src/il65/ast/AstChecker.kt b/il65/src/il65/ast/AstChecker.kt index 8eb9cd669..5d278b1cf 100644 --- a/il65/src/il65/ast/AstChecker.kt +++ b/il65/src/il65/ast/AstChecker.kt @@ -1,5 +1,6 @@ package il65.ast +import il65.compiler.CompilationOptions import il65.functions.BuiltIns import il65.parser.ParsingFailedError @@ -7,8 +8,8 @@ import il65.parser.ParsingFailedError * General checks on the Ast */ -fun Module.checkValid(globalNamespace: INameScope) { - val checker = AstChecker(globalNamespace) +fun Module.checkValid(globalNamespace: INameScope, compilerOptions: CompilationOptions) { + val checker = AstChecker(globalNamespace, compilerOptions) this.process(checker) val checkResult = checker.result() checkResult.forEach { @@ -24,7 +25,7 @@ fun Module.checkValid(globalNamespace: INameScope) { * todo check subroutine return values against the call's result assignments */ -class AstChecker(private val globalNamespace: INameScope) : IAstProcessor { +class AstChecker(private val globalNamespace: INameScope, val compilerOptions: CompilationOptions) : IAstProcessor { private val checkResult: MutableList = mutableListOf() fun result(): List { @@ -121,6 +122,10 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor { err("recursive var declaration") } + if(!compilerOptions.floats && decl.datatype==DataType.FLOAT) { + err("float var/const declaration, but floating point is not enabled via options") + } + when(decl.type) { VarDeclType.VAR, VarDeclType.CONST -> { when { @@ -233,6 +238,13 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor { return super.process(directive) } + override fun process(literalValue: LiteralValue): LiteralValue { + if(!compilerOptions.floats && literalValue.isFloat) { + checkResult.add(SyntaxError("floating point value used, but floating point is not enabled via options", literalValue.position)) + } + return super.process(literalValue) + } + private fun checkConstInitializerValueArray(decl: VarDecl) { val value = decl.value as LiteralValue // init value should either be a scalar or an array with the same dimensions as the arrayspec. diff --git a/il65/src/il65/compiler/Compiler.kt b/il65/src/il65/compiler/Compiler.kt index 1d697420f..ec8b86256 100644 --- a/il65/src/il65/compiler/Compiler.kt +++ b/il65/src/il65/compiler/Compiler.kt @@ -89,10 +89,6 @@ data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, va class Compiler(private val options: CompilationOptions, val namespace: INameScope) { - init { - val zeropage = Zeropage(options) - } - fun compile(module: Module) : IntermediateForm { println("\nCompiling parsed source code to intermediate code...") // todo