From 77c1376d6dee7c23089db6b68732c2b4f22510ac Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 18 Aug 2020 14:47:52 +0200 Subject: [PATCH] proper error message for arrays that are declared too big --- .../src/prog8/ast/processing/AstChecker.kt | 23 +++++++++++++-- .../target/c64/codegen/ForLoopsAsmGen.kt | 9 +++--- .../src/prog8/functions/BuiltinFunctions.kt | 6 ---- docs/source/programming.rst | 10 +++++++ docs/source/syntaxreference.rst | 1 + docs/source/todo.rst | 4 +-- examples/test.p8 | 28 +++++++++---------- 7 files changed, 52 insertions(+), 29 deletions(-) diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 68a1dd9f3..e8e4893cc 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -492,8 +492,7 @@ internal class AstChecker(private val program: Program, when(decl.value) { null -> { - // a vardecl without an initial value, don't bother with the rest - return super.visit(decl) + // a vardecl without an initial value, don't bother with it } is RangeExpr -> throw FatalAstException("range expression should have been converted to a true array value") is StringLiteralValue -> { @@ -577,6 +576,26 @@ internal class AstChecker(private val program: Program, } } + // array length limits + if(decl.isArray) { + val length = decl.arraysize!!.size() ?: 1 + when (decl.datatype) { + DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B -> { + if(length==0 || length>256) + err("string and byte array length must be 1-256") + } + DataType.ARRAY_UW, DataType.ARRAY_W -> { + if(length==0 || length>128) + err("word array length must be 1-128") + } + DataType.ARRAY_F -> { + if(length==0 || length>51) + err("float array length must be 1-51") + } + else -> {} + } + } + super.visit(decl) } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt index c7ff34ae2..2f0ce3c6f 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt @@ -266,7 +266,6 @@ $endLabel inx""") } private fun translateForOverIterableVar(stmt: ForLoop, iterableDt: DataType, ident: IdentifierReference) { - // TODO optimize this more val loopLabel = asmgen.makeLabel("for_loop") val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) @@ -291,9 +290,9 @@ $loopLabel lda ${65535.toHex()} ; modified $endLabel""") } DataType.ARRAY_UB, DataType.ARRAY_B -> { - // TODO: optimize loop code when the length of the array is < 256 (i.e. always) + // TODO: optimize loop code when the length of the array is 255 or less instead of 256 val length = decl.arraysize!!.size()!! - val counterLabel = asmgen.makeLabel("for_counter") // todo allocate dynamically, zero page preferred if iterations >= 8 + val counterLabel = asmgen.makeLabel("for_counter") // todo allocate dynamically, zero page preferred if len >= 16 val modifiedLabel = asmgen.makeLabel("for_modified") asmgen.out(""" lda #<$iterableName @@ -315,9 +314,9 @@ $counterLabel .byte 0 $endLabel""") } DataType.ARRAY_W, DataType.ARRAY_UW -> { - // TODO: optimize loop code when the length of the array is < 256 (i.e. always) + // TODO: optimize loop code when the length of the array is 255 or less instead of 256 val length = decl.arraysize!!.size()!! * 2 - val counterLabel = asmgen.makeLabel("for_counter") // todo allocate dynamically, zero page preferred if iterations >= 8 + val counterLabel = asmgen.makeLabel("for_counter") // todo allocate dynamically, zero page preferred if len >= 16 val modifiedLabel = asmgen.makeLabel("for_modified") val modifiedLabel2 = asmgen.makeLabel("for_modified2") val loopvarName = asmgen.asmIdentifierName(stmt.loopVar) diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 166e251df..da8cf55c2 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -274,22 +274,16 @@ private fun builtinLen(args: List, position: Position, program: Prog arraySize = target.arraysize?.size() if(arraySize==null) throw CannotEvaluateException("len", "arraysize unknown") - if(arraySize>256) - throw CompilerException("array length exceeds byte limit ${target.position}") NumericLiteralValue.optimalInteger(arraySize, args[0].position) } DataType.ARRAY_F -> { arraySize = target.arraysize?.size() if(arraySize==null) throw CannotEvaluateException("len", "arraysize unknown") - if(arraySize>256) - throw CompilerException("array length exceeds byte limit ${target.position}") NumericLiteralValue.optimalInteger(arraySize, args[0].position) } DataType.STR -> { val refLv = target.value as StringLiteralValue - if(refLv.value.length>255) - throw CompilerException("string length exceeds byte limit ${refLv.position}") NumericLiteralValue.optimalInteger(refLv.value.length, args[0].position) } in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position) diff --git a/docs/source/programming.rst b/docs/source/programming.rst index cdda09e7a..ac610542f 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -257,6 +257,16 @@ Note that the various keywords for the data type and variable type (``byte``, `` can't be used as *identifiers* elsewhere. You can't make a variable, block or subroutine with the name ``byte`` for instance. +**Arrays at a specific memory location:** +Using the memory-mapped syntax it is possible to define an array to be located at a specific memory location. +For instance to reference the first 5 rows of the Commodore 64's screen matrix as an array, you can define:: + + &ubyte[5*40] top5screenrows = $0400 + +This way you can set the second character on the second row from the top like this:: + + top5screenrows[41] = '!' + Strings ^^^^^^^ diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 1b8009c17..4fd436983 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -306,6 +306,7 @@ should be allocated by the compiler. Instead, the (mandatory) value assigned to should be the *memory address* where the value is located:: &byte BORDERCOLOR = $d020 + &ubyte[5*40] top5screenrows = $0400 ; works for array as well Direct access to memory locations diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 257a9473d..d2f9976b2 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,9 +2,9 @@ TODO ==== +- optimize assignment codegeneration - get rid of all TODO's ;-) -- allow declaring arrays on specific memory location and page-aligned -- option to load the built-inlibrary files from a directory instead of the embedded ones (for easier library development/debugging) +- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging) - aliases for imported symbols for example perhaps '%alias print = c64scr.print' ? - investigate support for 8bitguy's Commander X16 platform https://www.commanderx16.com and https://github.com/commanderx16/x16-docs - see if we can group some errors together for instance the (now single) errors about unidentified symbols diff --git a/examples/test.p8 b/examples/test.p8 index f8fb190a8..08c9043eb 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -24,20 +24,20 @@ main { ; c64.CHROUT('\n') -; ubyte bb -; ubyte from = 10 -; ubyte end = 20 -; -; for bb in from to end step 3 { -; c64scr.print_ub(bb) -; c64.CHROUT(',') -; } -; c64.CHROUT('\n') -; for bb in end to from step -3 { -; c64scr.print_ub(bb) -; c64.CHROUT(',') -; } -; c64.CHROUT('\n') + ubyte bb + ubyte from = 10 + ubyte end = 20 + + for bb in from to end step 3 { + c64scr.print_ub(bb) + c64.CHROUT(',') + } + c64.CHROUT('\n') + for bb in end to from step -3 { + c64scr.print_ub(bb) + c64.CHROUT(',') + } + c64.CHROUT('\n') word ww word fromw = -10