From 20d5eb79d0aab688886c0432766aa78901a5848a Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 12 Aug 2018 20:57:29 +0200 Subject: [PATCH] position and parent moved out of data class constructor --- il65/antlr/examples/test.ill | 19 +- il65/src/il65/AstChecker.kt | 73 ++++- il65/src/il65/AstOptimizer.kt | 227 +++++++++------ il65/src/il65/Main.kt | 15 +- il65/src/il65/ast/AST.kt | 529 ++++++++++++++++++++++++---------- 5 files changed, 598 insertions(+), 265 deletions(-) diff --git a/il65/antlr/examples/test.ill b/il65/antlr/examples/test.ill index df9437137..0d784761f 100644 --- a/il65/antlr/examples/test.ill +++ b/il65/antlr/examples/test.ill @@ -1,11 +1,18 @@ -~ main $c000 { - const byte hopla=55-33 - const byte hopla2=55-hopla - A = "derp" * %000100 +~ main $c003 { + memory byte derp = $ffdd1 + const byte hopla=55-33 + ; const byte hopla2=55-hopla + const float zwop = -1.7014118345e+38 + const float zwop = -1.7014118346e+38 - %import maghierniet + A = "derp" * %000100 - return 1+999 + %import maghierniet + %import maghierniet + %import maghierniet + %import maghierniet + + return 1+999 } %import imported1, 33, aaa diff --git a/il65/src/il65/AstChecker.kt b/il65/src/il65/AstChecker.kt index 6874111bf..60641142d 100644 --- a/il65/src/il65/AstChecker.kt +++ b/il65/src/il65/AstChecker.kt @@ -11,7 +11,6 @@ fun Module.checkValid() : List { class AstChecker : IAstProcessor { - private val checkResult: MutableList = mutableListOf() fun result(): List { @@ -26,6 +25,73 @@ class AstChecker : IAstProcessor { return expr } + override fun process(block: Block): IStatement { + if(block.address!=null && (block.address<0 || block.address>65535)) { + checkResult.add(SyntaxError("block memory address must be valid 0..\$ffff", block)) + } + block.statements.forEach { it.process(this) } + return block + } + + /** + * Check the variable declarations (values within range etc) + */ + override fun process(decl: VarDecl): IStatement { + fun err(msg: String) { + if(decl.value?.position == null) + throw AstException("declvalue no pos!") + checkResult.add(SyntaxError(msg, decl)) + } + when(decl.type) { + VarDeclType.VAR, VarDeclType.CONST -> { + val value = decl.value as? LiteralValue + if(value==null) + err("need a compile-time constant initializer value, found: ${decl.value!!::class.simpleName}") + else + when(decl.datatype) { + DataType.FLOAT -> { + val number = value.asFloat() + if(number==null) + err("need a const float initializer value") + else if(number > 1.7014118345e+38 || number < -1.7014118345e+38) + err("floating point value out of range for MFLPT format") + } + DataType.BYTE -> { + val number = value.asInt() + if(number==null) + err("need a const integer initializer value") + else if(number < 0 || number > 255) + err("value out of range for unsigned byte") + } + DataType.WORD -> { + val number = value.asInt() + if(number==null) + err("need a const integer initializer value") + else if(number < 0 || number > 65535) + err("value out of range for unsigned word") + } + DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { + val str = value.strvalue + if(str==null) + err("need a const string initializer value") + else if(str.isEmpty() || str.length>65535) + err("string length must be 1..65535") + } + } + } + VarDeclType.MEMORY -> { + val value = decl.value as LiteralValue + if(value.intvalue==null || value.intvalue<0 || value.intvalue>65535) { + err("memory address must be valid 0..\$ffff") + } + } + } + + decl.arrayspec?.process(this) + decl.value?.process(this) + return decl + } + /** * check the arguments of the directive */ @@ -35,14 +101,17 @@ class AstChecker : IAstProcessor { } when(directive.directive) { "%output" -> { + if(directive.parent !is Module) err("this directive may only occur at module level") if(directive.args.size!=1 || directive.args[0].name != "raw" && directive.args[0].name != "prg") err("invalid output directive type, expected raw or prg") } "%launcher" -> { + if(directive.parent !is Module) err("this directive may only occur at module level") if(directive.args.size!=1 || directive.args[0].name != "basic" && directive.args[0].name != "none") err("invalid launcher directive type, expected basic or none") } "%zp" -> { + if(directive.parent !is Module) err("this directive may only occur at module level") if(directive.args.size!=1 || directive.args[0].name != "compatible" && directive.args[0].name != "full" && @@ -50,10 +119,12 @@ class AstChecker : IAstProcessor { err("invalid zp directive style, expected compatible, full or full-restore") } "%address" -> { + if(directive.parent !is Module) err("this directive may only occur at module level") if(directive.args.size!=1 || directive.args[0].int == null) err("invalid address directive, expected numeric address argument") } "%import" -> { + if(directive.parent !is Module) err("this directive may only occur at module level") if(directive.args.size!=1 || directive.args[0].name==null) err("invalid import directive, expected module name argument") } diff --git a/il65/src/il65/AstOptimizer.kt b/il65/src/il65/AstOptimizer.kt index c5fe68966..c39232d73 100644 --- a/il65/src/il65/AstOptimizer.kt +++ b/il65/src/il65/AstOptimizer.kt @@ -26,6 +26,17 @@ class AstOptimizer : IAstProcessor { optimizationsDone = 0 } + override fun process(block: Block): IStatement { + block.statements = block.statements.map { it.process(this) } + return block + } + + override fun process(decl: VarDecl): IStatement { + decl.value = decl.value?.process(this) + decl.arrayspec?.process(this) + return decl + } + /** * Try to process a unary prefix expression. * Compile-time constant sub expressions will be evaluated on the spot. @@ -37,39 +48,41 @@ class AstOptimizer : IAstProcessor { val subexpr = expr.expression if (subexpr is LiteralValue) { // process prefixed literal values (such as -3, not true) - return when { + val result = when { expr.operator == "+" -> subexpr - expr.operator == "-" -> return when { + expr.operator == "-" -> when { subexpr.intvalue != null -> { optimizationsDone++ - LiteralValue(intvalue = subexpr.intvalue, position = subexpr.position) + LiteralValue(intvalue = subexpr.intvalue) } subexpr.floatvalue != null -> { optimizationsDone++ - LiteralValue(floatvalue = -subexpr.floatvalue, position = subexpr.position) + LiteralValue(floatvalue = -subexpr.floatvalue) } else -> throw UnsupportedOperationException("can only take negative of int or float") } - expr.operator == "~" -> return when { + expr.operator == "~" -> when { subexpr.intvalue != null -> { optimizationsDone++ - LiteralValue(intvalue = subexpr.intvalue.inv(), position = subexpr.position) + LiteralValue(intvalue = subexpr.intvalue.inv()) } else -> throw UnsupportedOperationException("can only take bitwise inversion of int") } - expr.operator == "not" -> return when { + expr.operator == "not" -> when { subexpr.intvalue != null -> { optimizationsDone++ - LiteralValue(intvalue = if (subexpr.intvalue == 0) 1 else 0, position = subexpr.position) + LiteralValue(intvalue = if (subexpr.intvalue == 0) 1 else 0) } subexpr.floatvalue != null -> { optimizationsDone++ - LiteralValue(intvalue = if (subexpr.floatvalue == 0.0) 1 else 0, position = subexpr.position) + LiteralValue(intvalue = if (subexpr.floatvalue == 0.0) 1 else 0) } else -> throw UnsupportedOperationException("can not take logical not of $subexpr") } else -> throw UnsupportedOperationException(expr.operator) } + result.position = subexpr.position + return result } return expr } @@ -98,7 +111,6 @@ class AstOptimizer : IAstProcessor { } override fun process(directive: Directive): IStatement { - println("directove OPT $directive") return directive } } @@ -135,7 +147,9 @@ class ConstExprEvaluator { private fun comparenotequal(left: LiteralValue, right: LiteralValue): LiteralValue { val leq = compareequal(left, right) - return LiteralValue(intvalue = if(leq.intvalue==1) 0 else 1, position = left.position) + val litval = LiteralValue(intvalue = if(leq.intvalue==1) 0 else 1) + litval.position = left.position + return litval } private fun compareequal(left: LiteralValue, right: LiteralValue): LiteralValue { @@ -153,159 +167,164 @@ class ConstExprEvaluator { right.arrayvalue!=null -> right.arrayvalue else -> throw AstException("missing literal value") } - return LiteralValue(intvalue = if(leftvalue==rightvalue) 1 else 0, position = left.position) + val litval = LiteralValue(intvalue = if(leftvalue==rightvalue) 1 else 0) + litval.position = left.position + return litval } private fun comparegreaterequal(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot compute $left >= $right" - return when { + val litval = when { left.intvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if (left.intvalue >= right.intvalue) 1 else 0, - position = left.position) + intvalue = if (left.intvalue >= right.intvalue) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if (left.intvalue >= right.floatvalue) 1 else 0, - position = left.position) + intvalue = if (left.intvalue >= right.floatvalue) 1 else 0) else -> throw ExpressionException(error) } left.floatvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if (left.floatvalue >= right.intvalue) 1 else 0, - position = left.position) + intvalue = if (left.floatvalue >= right.intvalue) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if (left.floatvalue >= right.floatvalue) 1 else 0, - position = left.position) + intvalue = if (left.floatvalue >= right.floatvalue) 1 else 0) else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } private fun comparelessequal(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot compute $left >= $right" - return when { + val litval = when { left.intvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if (left.intvalue <= right.intvalue) 1 else 0, - position = left.position) + intvalue = if (left.intvalue <= right.intvalue) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if (left.intvalue <= right.floatvalue) 1 else 0, - position = left.position) + intvalue = if (left.intvalue <= right.floatvalue) 1 else 0) else -> throw ExpressionException(error) } left.floatvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if (left.floatvalue <= right.intvalue) 1 else 0, - position = left.position) + intvalue = if (left.floatvalue <= right.intvalue) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if (left.floatvalue <= right.floatvalue) 1 else 0, - position = left.position) + intvalue = if (left.floatvalue <= right.floatvalue) 1 else 0) else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } private fun comparegreater(left: LiteralValue, right: LiteralValue): LiteralValue { val leq = comparelessequal(left, right) - return LiteralValue(intvalue = if(leq.intvalue==1) 0 else 1, position = left.position) + val litval = LiteralValue(intvalue = if(leq.intvalue==1) 0 else 1) + litval.position = left.position + return litval } private fun compareless(left: LiteralValue, right: LiteralValue): LiteralValue { val leq = comparegreaterequal(left, right) - return LiteralValue(intvalue = if(leq.intvalue==1) 0 else 1, position = left.position) + val litval = LiteralValue(intvalue = if(leq.intvalue==1) 0 else 1) + litval.position = left.position + return litval } private fun logicalxor(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot compute $left locical-xor $right" - return when { + val litval = when { left.intvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if ((left.intvalue!=0).xor(right.intvalue!=0)) 1 else 0, - position = left.position) + intvalue = if ((left.intvalue!=0).xor(right.intvalue!=0)) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if ((left.intvalue!=0).xor(right.floatvalue!=0.0)) 1 else 0, - position = left.position) + intvalue = if ((left.intvalue!=0).xor(right.floatvalue!=0.0)) 1 else 0) else -> throw ExpressionException(error) } left.floatvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if ((left.floatvalue!=0.0).xor(right.intvalue!=0)) 1 else 0, - position = left.position) + intvalue = if ((left.floatvalue!=0.0).xor(right.intvalue!=0)) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if ((left.floatvalue!=0.0).xor(right.floatvalue!=0.0)) 1 else 0, - position = left.position) + intvalue = if ((left.floatvalue!=0.0).xor(right.floatvalue!=0.0)) 1 else 0) else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } private fun logicalor(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot compute $left locical-or $right" - return when { + val litval = when { left.intvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if (left.intvalue!=0 || right.intvalue!=0) 1 else 0, - position = left.position) + intvalue = if (left.intvalue!=0 || right.intvalue!=0) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if (left.intvalue!=0 || right.floatvalue!=0.0) 1 else 0, - position = left.position) + intvalue = if (left.intvalue!=0 || right.floatvalue!=0.0) 1 else 0) else -> throw ExpressionException(error) } left.floatvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if (left.floatvalue!=0.0 || right.intvalue!=0) 1 else 0, - position = left.position) + intvalue = if (left.floatvalue!=0.0 || right.intvalue!=0) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if (left.floatvalue!=0.0 || right.floatvalue!=0.0) 1 else 0, - position = left.position) + intvalue = if (left.floatvalue!=0.0 || right.floatvalue!=0.0) 1 else 0) else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } private fun logicaland(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot compute $left locical-and $right" - return when { + val litval = when { left.intvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if (left.intvalue!=0 && right.intvalue!=0) 1 else 0, - position = left.position) + intvalue = if (left.intvalue!=0 && right.intvalue!=0) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if (left.intvalue!=0 && right.floatvalue!=0.0) 1 else 0, - position = left.position) + intvalue = if (left.intvalue!=0 && right.floatvalue!=0.0) 1 else 0) else -> throw ExpressionException(error) } left.floatvalue!=null -> when { right.intvalue!=null -> LiteralValue( - intvalue = if (left.floatvalue!=0.0 && right.intvalue!=0) 1 else 0, - position = left.position) + intvalue = if (left.floatvalue!=0.0 && right.intvalue!=0) 1 else 0) right.floatvalue!=null -> LiteralValue( - intvalue = if (left.floatvalue!=0.0 && right.floatvalue!=0.0) 1 else 0, - position = left.position) + intvalue = if (left.floatvalue!=0.0 && right.floatvalue!=0.0) 1 else 0) else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } private fun bitwisexor(left: LiteralValue, right: LiteralValue): LiteralValue { - if(left.intvalue!=null && right.intvalue !=null) - return LiteralValue(intvalue = left.intvalue.xor(right.intvalue), position = left.position) + if(left.intvalue!=null && right.intvalue !=null) { + val litval = LiteralValue(intvalue = left.intvalue.xor(right.intvalue)) + litval.position = left.position + return litval + } throw ExpressionException("cannot calculate $left ^ $right") } private fun bitwiseor(left: LiteralValue, right: LiteralValue): LiteralValue { - if(left.intvalue!=null && right.intvalue !=null) - return LiteralValue(intvalue = left.intvalue.or(right.intvalue), position = left.position) + if(left.intvalue!=null && right.intvalue !=null) { + val litval = LiteralValue(intvalue = left.intvalue.or(right.intvalue)) + litval.position = left.position + return litval + } throw ExpressionException("cannot calculate $left | $right") } private fun bitwiseand(left: LiteralValue, right: LiteralValue): LiteralValue { - if(left.intvalue!=null && right.intvalue !=null) - return LiteralValue(intvalue = left.intvalue.and(right.intvalue), position = left.position) + if(left.intvalue!=null && right.intvalue !=null) { + val litval = LiteralValue(intvalue = left.intvalue.and(right.intvalue)) + litval.position = left.position + return litval + } throw ExpressionException("cannot calculate $left & $right") } @@ -318,122 +337,138 @@ class ConstExprEvaluator { } private fun shiftright(left: LiteralValue, right: LiteralValue): LiteralValue { - if(left.intvalue!=null && right.intvalue !=null) - return LiteralValue(intvalue = left.intvalue.shr(right.intvalue), position = left.position) + if(left.intvalue!=null && right.intvalue !=null) { + val litval = LiteralValue(intvalue = left.intvalue.shr(right.intvalue)) + litval.position = left.position + return litval + } throw ExpressionException("cannot calculate $left >> $right") } private fun shiftleft(left: LiteralValue, right: LiteralValue): LiteralValue { - if(left.intvalue!=null && right.intvalue !=null) - return LiteralValue(intvalue = left.intvalue.shl(right.intvalue), position = left.position) + if(left.intvalue!=null && right.intvalue !=null) { + val litval = LiteralValue(intvalue = left.intvalue.shl(right.intvalue)) + litval.position = left.position + return litval + } throw ExpressionException("cannot calculate $left << $right") } private fun power(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot calculate $left ** $right" - return when { + val litval = when { left.intvalue!=null -> when { - right.intvalue!=null -> LiteralValue(intvalue = left.intvalue.toDouble().pow(right.intvalue).toInt(), position = left.position) - right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue.toDouble().pow(right.floatvalue), position = left.position) + right.intvalue!=null -> LiteralValue(intvalue = left.intvalue.toDouble().pow(right.intvalue).toInt()) + right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue.toDouble().pow(right.floatvalue)) else -> throw ExpressionException(error) } left.floatvalue!=null -> when { - right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.intvalue), position = left.position) - right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.floatvalue), position = left.position) + right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.intvalue)) + right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.floatvalue)) else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } private fun plus(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot add $left and $right" - return when { + val litval = when { left.intvalue!=null -> when { - right.intvalue!=null -> LiteralValue(intvalue = left.intvalue + right.intvalue, position = left.position) - right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue + right.floatvalue, position = left.position) + right.intvalue!=null -> LiteralValue(intvalue = left.intvalue + right.intvalue) + right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue + right.floatvalue) else -> throw ExpressionException(error) } left.floatvalue!=null -> when { - right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue + right.intvalue, position = left.position) - right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue + right.floatvalue, position = left.position) + right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue + right.intvalue) + right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue + right.floatvalue) else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } private fun minus(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot subtract $left and $right" - return when { + val litval = when { left.intvalue!=null -> when { - right.intvalue!=null -> LiteralValue(intvalue = left.intvalue - right.intvalue, position = left.position) - right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue - right.floatvalue, position = left.position) + right.intvalue!=null -> LiteralValue(intvalue = left.intvalue - right.intvalue) + right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue - right.floatvalue) else -> throw ExpressionException(error) } left.floatvalue!=null -> when { - right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue - right.intvalue, position = left.position) - right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue - right.floatvalue, position = left.position) + right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue - right.intvalue) + right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue - right.floatvalue) else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } private fun multiply(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot multiply $left and $right" - return when { + val litval = when { left.intvalue!=null -> when { - right.intvalue!=null -> LiteralValue(intvalue = left.intvalue * right.intvalue, position = left.position) - right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue * right.floatvalue, position = left.position) + right.intvalue!=null -> LiteralValue(intvalue = left.intvalue * right.intvalue) + right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue * right.floatvalue) right.strvalue!=null -> { if(right.strvalue.length * left.intvalue > 65535) throw ExpressionException("string too large") - LiteralValue(strvalue = right.strvalue.repeat(left.intvalue), position = left.position) + LiteralValue(strvalue = right.strvalue.repeat(left.intvalue)) } else -> throw ExpressionException(error) } left.floatvalue!=null -> when { - right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue * right.intvalue, position = left.position) - right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue * right.floatvalue, position = left.position) + right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue * right.intvalue) + right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue * right.floatvalue) else -> throw ExpressionException(error) } left.strvalue!=null -> when { right.intvalue!=null -> { if(left.strvalue.length * right.intvalue > 65535) throw ExpressionException("string too large") - LiteralValue(strvalue = left.strvalue.repeat(right.intvalue), position=left.position) + LiteralValue(strvalue = left.strvalue.repeat(right.intvalue)) } else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } private fun divide(left: LiteralValue, right: LiteralValue): LiteralValue { val error = "cannot divide $left by $right" - return when { + val litval = when { left.intvalue!=null -> when { right.intvalue!=null -> { if(right.intvalue==0) throw ExpressionException("attempt to divide by zero") - LiteralValue(intvalue = left.intvalue / right.intvalue, position = left.position) + LiteralValue(intvalue = left.intvalue / right.intvalue) } right.floatvalue!=null -> { if(right.floatvalue==0.0) throw ExpressionException("attempt to divide by zero") - LiteralValue(floatvalue = left.intvalue / right.floatvalue, position = left.position) + LiteralValue(floatvalue = left.intvalue / right.floatvalue) } else -> throw ExpressionException(error) } left.floatvalue!=null -> when { right.intvalue!=null -> { if(right.intvalue==0) throw ExpressionException("attempt to divide by zero") - LiteralValue(floatvalue = left.floatvalue / right.intvalue, position = left.position) + LiteralValue(floatvalue = left.floatvalue / right.intvalue) } right.floatvalue!=null -> { if(right.floatvalue==0.0) throw ExpressionException("attempt to divide by zero") - LiteralValue(floatvalue = left.floatvalue / right.floatvalue, position = left.position) + LiteralValue(floatvalue = left.floatvalue / right.floatvalue) } else -> throw ExpressionException(error) } else -> throw ExpressionException(error) } + litval.position = left.position + return litval } } diff --git a/il65/src/il65/Main.kt b/il65/src/il65/Main.kt index 1df9c8464..611be4b01 100644 --- a/il65/src/il65/Main.kt +++ b/il65/src/il65/Main.kt @@ -50,12 +50,14 @@ fun loadModule(filename: String) : Module { // TODO the comments: // tokens.commentTokens().forEach { println(it) } - // convert to Ast (optimizing this is done as a final step) - var moduleAst = parseTree.toAst(fileName.toString(),true) + // convert to Ast and optimize + var moduleAst = parseTree.toAst(fileName.toString(),true).optimized() + moduleAst.linkParents() + val checkResult = moduleAst.checkValid() checkResult.forEach { it.printError() } if(checkResult.isNotEmpty()) - throw ParsingFailedError("There are ${checkResult.size} syntax errors in '$fileName'.") + throw ParsingFailedError("There are ${checkResult.size} errors in '$fileName'.") // process imports val lines = moduleAst.lines.toMutableList() @@ -65,7 +67,7 @@ fun loadModule(filename: String) : Module { .map { Pair(it.first, executeImportDirective(it.second as Directive)) } imports.reversed().forEach { - println("IMPORT [in ${moduleAst.name}]: $it") + println("IMPORT [in ${moduleAst.name}]: $it") // TODO } moduleAst.lines = lines @@ -77,14 +79,15 @@ fun executeImportDirective(import: Directive): Module { if(import.directive!="%import" || import.args.size!=1 || import.args[0].name==null) throw SyntaxError("invalid import directive", import) - return Module("???", emptyList(), null) // TODO + return Module("???", emptyList()) // TODO } fun main(args: Array) { println("Reading source file: ${args[0]}") try { - val moduleAst = loadModule(args[0]).optimized() + val moduleAst = loadModule(args[0]).optimized() // one final global optimization + moduleAst.linkParents() // re-link parents in final configuration moduleAst.lines.map { println(it) diff --git a/il65/src/il65/ast/AST.kt b/il65/src/il65/ast/AST.kt index aefba0426..53f9a0dd9 100644 --- a/il65/src/il65/ast/AST.kt +++ b/il65/src/il65/ast/AST.kt @@ -51,11 +51,15 @@ interface IAstProcessor { fun process(expr: PrefixExpression): IExpression fun process(expr: BinaryExpression): IExpression fun process(directive: Directive): IStatement + fun process(block: Block): IStatement + fun process(decl: VarDecl): IStatement } interface Node { val position: Position? // optional for the sake of easy unit testing + var parent: Node? // will be linked correctly later + fun linkParents(parent: Node) } @@ -65,39 +69,84 @@ interface IStatement : Node { data class Module(val name: String, - var lines: List, - override val position: Position? = null) : Node { + var lines: List) : Node { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent=parent + } + fun linkParents() { + parent = null + lines.forEach {it.linkParents(this)} + } + fun process(processor: IAstProcessor): Module { lines = lines.map { it.process(processor) } return this } } -data class Block(val name: String, val address: Int?, var statements: List, - override val position: Position? = null) : IStatement { - override fun process(processor: IAstProcessor) : IStatement { - statements = statements.map { it.process(processor) } - return this + +data class Block(val name: String, + val address: Int?, + var statements: List) : IStatement { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + statements.forEach {it.linkParents(this)} + } + + override fun process(processor: IAstProcessor) = processor.process(this) +} + + +data class Directive(val directive: String, val args: List) : IStatement { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + args.forEach{it.linkParents(this)} + } + + override fun process(processor: IAstProcessor) = processor.process(this) +} + + +data class DirectiveArg(val str: String?, val name: String?, val int: Int?) : Node { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent } } -data class Directive(val directive: String, val args: List, - override val position: Position? = null) : IStatement { - override fun process(processor: IAstProcessor) : IStatement { - return processor.process(this) + +data class Label(val name: String) : IStatement { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent } -} -data class DirectiveArg(val str: String?, val name: String?, val int: Int?, - override val position: Position? = null) : Node - -data class Label(val name: String, - override val position: Position? = null) : IStatement { override fun process(processor: IAstProcessor) = this } -data class Return(var values: List, - override val position: Position? = null) : IStatement { + +data class Return(var values: List) : IStatement { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + values.forEach {it.linkParents(this)} + } + override fun process(processor: IAstProcessor): IStatement { values = values.map { it.process(processor) } return this @@ -105,52 +154,57 @@ data class Return(var values: List, } -interface IVarDecl : IStatement { - val datatype: DataType - val arrayspec: ArraySpec? - val name: String - var value: IExpression? -} +data class ArraySpec(var x: IExpression, var y: IExpression?) : Node { + override var position: Position? = null + override var parent: Node? = null -data class ArraySpec(var x: IExpression, - var y: IExpression?, - override val position: Position? = null) : Node + override fun linkParents(parent: Node) { + this.parent = parent + x.linkParents(this) + y?.linkParents(this) + } -data class VarDecl(override val datatype: DataType, - override val arrayspec: ArraySpec?, - override val name: String, - override var value: IExpression?, - override val position: Position? = null) : IVarDecl { - override fun process(processor: IAstProcessor): IStatement { - value = value?.process(processor) - return this + fun process(processor: IAstProcessor) { + x = x.process(processor) + y = y?.process(processor) } } -data class ConstDecl(override val datatype: DataType, - override val arrayspec: ArraySpec?, - override val name: String, - override var value: IExpression?, - override val position: Position? = null) : IVarDecl { - override fun process(processor: IAstProcessor): IStatement { - value = value?.process(processor) - return this - } + +enum class VarDeclType { + VAR, + CONST, + MEMORY } -data class MemoryVarDecl(override val datatype: DataType, - override val arrayspec: ArraySpec?, - override val name: String, - override var value: IExpression?, - override val position: Position? = null) : IVarDecl { - override fun process(processor: IAstProcessor): IStatement { - value = value?.process(processor) - return this +data class VarDecl(val type: VarDeclType, + val datatype: DataType, + val arrayspec: ArraySpec?, + val name: String, + var value: IExpression?) : IStatement { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + arrayspec?.linkParents(this) + value?.linkParents(this) } + + override fun process(processor: IAstProcessor) = processor.process(this) } -data class Assignment(var target: AssignTarget, val aug_op : String?, var value: IExpression, - override val position: Position? = null) : IStatement { + +data class Assignment(var target: AssignTarget, val aug_op : String?, var value: IExpression) : IStatement { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + target.linkParents(this) + value.linkParents(this) + } + override fun process(processor: IAstProcessor): IStatement { target = target.process(processor) value = value.process(processor) @@ -158,8 +212,15 @@ data class Assignment(var target: AssignTarget, val aug_op : String?, var value: } } -data class AssignTarget(val register: Register?, val identifier: Identifier?, - override val position: Position? = null) : Node { +data class AssignTarget(val register: Register?, val identifier: Identifier?) : Node { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + identifier?.linkParents(this) + } + fun process(processor: IAstProcessor) = this // for now } @@ -172,8 +233,15 @@ interface IExpression: Node { // note: some expression elements are mutable, to be able to rewrite/process the expression tree -data class PrefixExpression(val operator: String, var expression: IExpression, - override val position: Position? = null) : IExpression { +data class PrefixExpression(val operator: String, var expression: IExpression) : IExpression { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + expression.linkParents(this) + } + override fun constValue(): LiteralValue? { throw ExpressionException("should have been optimized away before const value was asked") } @@ -182,8 +250,16 @@ data class PrefixExpression(val operator: String, var expression: IExpression, } -data class BinaryExpression(var left: IExpression, val operator: String, var right: IExpression, - override val position: Position? = null) : IExpression { +data class BinaryExpression(var left: IExpression, val operator: String, var right: IExpression) : IExpression { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + left.linkParents(this) + right.linkParents(this) + } + override fun constValue(): LiteralValue? { throw ExpressionException("should have been optimized away before const value was asked") } @@ -194,15 +270,54 @@ data class BinaryExpression(var left: IExpression, val operator: String, var rig data class LiteralValue(val intvalue: Int? = null, val floatvalue: Double? = null, val strvalue: String? = null, - val arrayvalue: List? = null, - override val position: Position? = null) : IExpression { + val arrayvalue: List? = null) : IExpression { + override var position: Position? = null + override var parent: Node? = null + + fun asInt(): Int? { + return when { + intvalue!=null -> intvalue + floatvalue!=null -> floatvalue.toInt() + else -> { + if(strvalue!=null || arrayvalue!=null) + throw AstException("attempt to get int value from non-integer $this") + else null + } + } + } + + fun asFloat(): Double? { + return when { + floatvalue!=null -> floatvalue + intvalue!=null -> intvalue.toDouble() + else -> { + if(strvalue!=null || arrayvalue!=null) + throw AstException("attempt to get float value from non-integer $this") + else null + } + } + } + + override fun linkParents(parent: Node) { + this.parent = parent + arrayvalue?.forEach {it.linkParents(this)} + } + override fun constValue(): LiteralValue? = this override fun process(processor: IAstProcessor) = this } -data class RangeExpr(var from: IExpression, var to: IExpression, - override val position: Position? = null) : IExpression { +data class RangeExpr(var from: IExpression, var to: IExpression) : IExpression { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + from.linkParents(this) + to.linkParents(this) + } + override fun constValue(): LiteralValue? = null override fun process(processor: IAstProcessor): IExpression { from = from.process(processor) @@ -212,15 +327,27 @@ data class RangeExpr(var from: IExpression, var to: IExpression, } -data class RegisterExpr(val register: Register, - override val position: Position? = null) : IExpression { +data class RegisterExpr(val register: Register) : IExpression { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + } + override fun constValue(): LiteralValue? = null override fun process(processor: IAstProcessor) = this } -data class Identifier(val name: String, val scope: List, - override val position: Position? = null) : IExpression { +data class Identifier(val name: String, val scope: List) : IExpression { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + } + override fun constValue(): LiteralValue? { // @todo should look up the identifier and return its value if that is a compile time const return null @@ -230,14 +357,28 @@ data class Identifier(val name: String, val scope: List, } -data class CallTarget(val address: Int?, val identifier: Identifier?, - override val position: Position? = null) : Node { +data class CallTarget(val address: Int?, val identifier: Identifier?) : Node { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + identifier?.linkParents(this) + } + fun process(processor: IAstProcessor) = this } -data class PostIncrDecr(var target: AssignTarget, val operator: String, - override val position: Position? = null) : IStatement { +data class PostIncrDecr(var target: AssignTarget, val operator: String) : IStatement { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + target.linkParents(this) + } + override fun process(processor: IAstProcessor): IStatement { target = target.process(processor) return this @@ -245,8 +386,15 @@ data class PostIncrDecr(var target: AssignTarget, val operator: String, } -data class Jump(var target: CallTarget, - override val position: Position? = null) : IStatement { +data class Jump(var target: CallTarget) : IStatement { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + target.linkParents(this) + } + override fun process(processor: IAstProcessor): IStatement { target = target.process(processor) return this @@ -254,8 +402,16 @@ data class Jump(var target: CallTarget, } -data class FunctionCall(var target: CallTarget, var arglist: List, - override val position: Position? = null) : IExpression { +data class FunctionCall(var target: CallTarget, var arglist: List) : IExpression { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + target.linkParents(this) + arglist.forEach { it.linkParents(this) } + } + override fun constValue(): LiteralValue? { // if the function is a built-in function and the args are consts, should evaluate! return null @@ -269,8 +425,14 @@ data class FunctionCall(var target: CallTarget, var arglist: List, } -data class InlineAssembly(val assembly: String, - override val position: Position? = null) : IStatement { +data class InlineAssembly(val assembly: String) : IStatement { + override var position: Position? = null + override var parent: Node? = null + + override fun linkParents(parent: Node) { + this.parent = parent + } + override fun process(processor: IAstProcessor) = this } @@ -279,14 +441,18 @@ data class InlineAssembly(val assembly: String, fun ParserRuleContext.toPosition(withPosition: Boolean) : Position? { return if (withPosition) + // note: be ware of TAB characters in the source text, they count as 1 column... Position(start.line, start.charPositionInLine, stop.charPositionInLine+stop.text.length) else null } -fun il65Parser.ModuleContext.toAst(name: String, withPosition: Boolean) = - Module(name, modulestatement().map { it.toAst(withPosition) }, toPosition(withPosition)) +fun il65Parser.ModuleContext.toAst(name: String, withPosition: Boolean) : Module { + val module = Module(name, modulestatement().map { it.toAst(withPosition) }) + module.position = toPosition(withPosition) + return module +} fun il65Parser.ModulestatementContext.toAst(withPosition: Boolean) : IStatement { @@ -301,89 +467,112 @@ fun il65Parser.ModulestatementContext.toAst(withPosition: Boolean) : IStatement fun il65Parser.BlockContext.toAst(withPosition: Boolean) : IStatement { - return Block(identifier().text, + val block= Block(identifier().text, integerliteral()?.toAst(), - statement().map { it.toAst(withPosition) }, - toPosition(withPosition)) + statement().map { it.toAst(withPosition) }) + block.position = toPosition(withPosition) + return block } fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement { val vardecl = vardecl() if(vardecl!=null) { - return VarDecl(vardecl.datatype().toAst(), + val decl= VarDecl(VarDeclType.VAR, + vardecl.datatype().toAst(), vardecl.arrayspec()?.toAst(withPosition), vardecl.identifier().text, - null, - vardecl.toPosition(withPosition)) + null) + decl.position = vardecl.toPosition(withPosition) + return decl } val varinit = varinitializer() if(varinit!=null) { - return VarDecl(varinit.datatype().toAst(), + val decl= VarDecl(VarDeclType.VAR, + varinit.datatype().toAst(), varinit.arrayspec()?.toAst(withPosition), varinit.identifier().text, - varinit.expression().toAst(withPosition), - varinit.toPosition(withPosition)) + varinit.expression().toAst(withPosition)) + decl.position = varinit.toPosition(withPosition) + return decl } val constdecl = constdecl() if(constdecl!=null) { val cvarinit = constdecl.varinitializer() - return ConstDecl(cvarinit.datatype().toAst(), + val decl = VarDecl(VarDeclType.CONST, + cvarinit.datatype().toAst(), cvarinit.arrayspec()?.toAst(withPosition), cvarinit.identifier().text, - cvarinit.expression().toAst(withPosition), - cvarinit.toPosition(withPosition)) + cvarinit.expression().toAst(withPosition)) + decl.position = cvarinit.toPosition(withPosition) + return decl } val memdecl = memoryvardecl() if(memdecl!=null) { val mvarinit = memdecl.varinitializer() - return MemoryVarDecl(mvarinit.datatype().toAst(), + val decl = VarDecl(VarDeclType.MEMORY, + mvarinit.datatype().toAst(), mvarinit.arrayspec()?.toAst(withPosition), mvarinit.identifier().text, - mvarinit.expression().toAst(withPosition), - mvarinit.toPosition(withPosition)) + mvarinit.expression().toAst(withPosition)) + decl.position = mvarinit.toPosition(withPosition) + return decl } val assign = assignment() if (assign!=null) { - return Assignment(assign.assign_target().toAst(withPosition), - null, assign.expression().toAst(withPosition), - assign.toPosition(withPosition)) + val ast =Assignment(assign.assign_target().toAst(withPosition), + null, assign.expression().toAst(withPosition)) + ast.position = assign.toPosition(withPosition) + return ast } val augassign = augassignment() - if (augassign!=null) - return Assignment(augassign.assign_target().toAst(withPosition), + if (augassign!=null) { + val aug= Assignment(augassign.assign_target().toAst(withPosition), augassign.operator.text, - augassign.expression().toAst(withPosition), - augassign.toPosition(withPosition)) + augassign.expression().toAst(withPosition)) + aug.position = augassign.toPosition(withPosition) + return aug + } val post = postincrdecr() - if(post!=null) - return PostIncrDecr(post.assign_target().toAst(withPosition), - post.operator.text, post.toPosition(withPosition)) + if(post!=null) { + val ast = PostIncrDecr(post.assign_target().toAst(withPosition), post.operator.text) + ast.position = post.toPosition(withPosition) + return ast + } val directive = directive()?.toAst(withPosition) if(directive!=null) return directive val label=labeldef() - if(label!=null) - return Label(label.text, label.toPosition(withPosition)) + if(label!=null) { + val lbl = Label(label.text) + lbl.position = label.toPosition(withPosition) + return lbl + } val jump = unconditionaljump() - if(jump!=null) - return Jump(jump.call_location().toAst(withPosition), jump.toPosition(withPosition)) + if(jump!=null) { + val ast = Jump(jump.call_location().toAst(withPosition)) + ast.position = jump.toPosition(withPosition) + return ast + } val returnstmt = returnstmt() if(returnstmt!=null) return Return(returnstmt.expression_list().toAst(withPosition)) val asm = inlineasm() - if(asm!=null) - return InlineAssembly(asm.INLINEASMBLOCK().text, asm.toPosition(withPosition)) + if(asm!=null) { + val ast = InlineAssembly(asm.INLINEASMBLOCK().text) + ast.position = asm.toPosition(withPosition) + return ast + } throw UnsupportedOperationException(text) } @@ -392,20 +581,23 @@ fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement { fun il65Parser.Call_locationContext.toAst(withPosition: Boolean) : CallTarget { val address = integerliteral()?.toAst() val identifier = identifier() - return if(identifier!=null) - CallTarget(address, identifier.toAst(withPosition), toPosition(withPosition)) - else - CallTarget(address, scoped_identifier().toAst(withPosition), toPosition(withPosition)) + val result = + if(identifier!=null) CallTarget(address, identifier.toAst(withPosition)) + else CallTarget(address, scoped_identifier().toAst(withPosition)) + result.position = toPosition(withPosition) + return result } fun il65Parser.Assign_targetContext.toAst(withPosition: Boolean) : AssignTarget { val register = register()?.toAst() val identifier = identifier() - return if(identifier!=null) - AssignTarget(register, identifier.toAst(withPosition), toPosition(withPosition)) + val result = if(identifier!=null) + AssignTarget(register, identifier.toAst(withPosition)) else - AssignTarget(register, scoped_identifier()?.toAst(withPosition), toPosition(withPosition)) + AssignTarget(register, scoped_identifier()?.toAst(withPosition)) + result.position = toPosition(withPosition) + return result } @@ -415,22 +607,29 @@ fun il65Parser.RegisterContext.toAst() = Register.valueOf(text.toUpperCase()) fun il65Parser.DatatypeContext.toAst() = DataType.valueOf(text.toUpperCase()) -fun il65Parser.ArrayspecContext.toAst(withPosition: Boolean) = ArraySpec( - expression(0).toAst(withPosition), - if (expression().size > 1) expression(1).toAst(withPosition) else null, - toPosition(withPosition) -) +fun il65Parser.ArrayspecContext.toAst(withPosition: Boolean) : ArraySpec { + val spec = ArraySpec( + expression(0).toAst(withPosition), + if (expression().size > 1) expression(1).toAst(withPosition) else null) + spec.position = toPosition(withPosition) + return spec +} -fun il65Parser.DirectiveContext.toAst(withPosition: Boolean) = - Directive(directivename.text, directivearg().map { it.toAst(withPosition) }, toPosition(withPosition)) +fun il65Parser.DirectiveContext.toAst(withPosition: Boolean) : Directive { + val dir = Directive(directivename.text, directivearg().map { it.toAst(withPosition) }) + dir.position = toPosition(withPosition) + return dir +} -fun il65Parser.DirectiveargContext.toAst(withPosition: Boolean) = - DirectiveArg(stringliteral()?.text, - identifier()?.text, - integerliteral()?.toAst(), - toPosition(withPosition)) +fun il65Parser.DirectiveargContext.toAst(withPosition: Boolean) : DirectiveArg { + val darg = DirectiveArg(stringliteral()?.text, + identifier()?.text, + integerliteral()?.toAst()) + darg.position = toPosition(withPosition) + return darg +} fun il65Parser.IntegerliteralContext.toAst(): Int { @@ -449,18 +648,23 @@ fun il65Parser.ExpressionContext.toAst(withPosition: Boolean) : IExpression { val litval = literalvalue() if(litval!=null) { val booleanlit = litval.booleanliteral()?.toAst() - if(booleanlit!=null) - return LiteralValue(intvalue = if(booleanlit) 1 else 0) - return LiteralValue(litval.integerliteral()?.toAst(), - litval.floatliteral()?.toAst(), - litval.stringliteral()?.text, - litval.arrayliteral()?.toAst(withPosition), - litval.toPosition(withPosition) - ) + val value = + if(booleanlit!=null) + LiteralValue(intvalue = if(booleanlit) 1 else 0) + else + LiteralValue(litval.integerliteral()?.toAst(), + litval.floatliteral()?.toAst(), + litval.stringliteral()?.text, + litval.arrayliteral()?.toAst(withPosition)) + value.position = litval.toPosition(withPosition) + return value } - if(register()!=null) - return RegisterExpr(register().toAst(), register().toPosition(withPosition)) + if(register()!=null) { + val reg = RegisterExpr(register().toAst()) + reg.position = register().toPosition(withPosition) + return reg + } if(identifier()!=null) return identifier().toAst(withPosition) @@ -468,28 +672,37 @@ fun il65Parser.ExpressionContext.toAst(withPosition: Boolean) : IExpression { if(scoped_identifier()!=null) return scoped_identifier().toAst(withPosition) - if(bop!=null) - return BinaryExpression(left.toAst(withPosition), + if(bop!=null) { + val expr = BinaryExpression(left.toAst(withPosition), bop.text, - right.toAst(withPosition), - toPosition(withPosition)) + right.toAst(withPosition)) + expr.position = toPosition(withPosition) + return expr + } - if(prefix!=null) - return PrefixExpression(prefix.text, - expression(0).toAst(withPosition), - toPosition(withPosition)) + if(prefix!=null) { + val expr = PrefixExpression(prefix.text, + expression(0).toAst(withPosition)) + expr.position = toPosition(withPosition) + return expr + } val funcall = functioncall() if(funcall!=null) { val location = funcall.call_location().toAst(withPosition) - return if(funcall.expression_list()==null) - FunctionCall(location, emptyList(), funcall.toPosition(withPosition)) + val fcall = if(funcall.expression_list()==null) + FunctionCall(location, emptyList()) else - FunctionCall(location, funcall.expression_list().toAst(withPosition), funcall.toPosition(withPosition)) + FunctionCall(location, funcall.expression_list().toAst(withPosition)) + fcall.position = funcall.toPosition(withPosition) + return fcall } - if (rangefrom!=null && rangeto!=null) - return RangeExpr(rangefrom.toAst(withPosition), rangeto.toAst(withPosition), toPosition(withPosition)) + if (rangefrom!=null && rangeto!=null) { + val rexp = RangeExpr(rangefrom.toAst(withPosition), rangeto.toAst(withPosition)) + rexp.position = toPosition(withPosition) + return rexp + } if(childCount==3 && children[0].text=="(" && children[2].text==")") return expression(0).toAst(withPosition) // expression within ( ) @@ -502,7 +715,9 @@ fun il65Parser.Expression_listContext.toAst(withPosition: Boolean) = expression( fun il65Parser.IdentifierContext.toAst(withPosition: Boolean) : Identifier { - return Identifier(text, emptyList(), toPosition(withPosition)) + val ident = Identifier(text, emptyList()) + ident.position = toPosition(withPosition) + return ident } @@ -510,7 +725,9 @@ fun il65Parser.Scoped_identifierContext.toAst(withPosition: Boolean) : Identifie val names = NAME() val name = names.last().text val scope = names.take(names.size-1) - return Identifier(name, scope.map { it.text }, toPosition(withPosition)) + val ident = Identifier(name, scope.map { it.text }) + ident.position = toPosition(withPosition) + return ident }