proper error message for arrays that are declared too big

This commit is contained in:
Irmen de Jong 2020-08-18 14:47:52 +02:00
parent 353f1954a5
commit 77c1376d6d
7 changed files with 52 additions and 29 deletions

View File

@ -492,8 +492,7 @@ internal class AstChecker(private val program: Program,
when(decl.value) { when(decl.value) {
null -> { null -> {
// a vardecl without an initial value, don't bother with the rest // a vardecl without an initial value, don't bother with it
return super.visit(decl)
} }
is RangeExpr -> throw FatalAstException("range expression should have been converted to a true array value") is RangeExpr -> throw FatalAstException("range expression should have been converted to a true array value")
is StringLiteralValue -> { 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) super.visit(decl)
} }

View File

@ -266,7 +266,6 @@ $endLabel inx""")
} }
private fun translateForOverIterableVar(stmt: ForLoop, iterableDt: DataType, ident: IdentifierReference) { private fun translateForOverIterableVar(stmt: ForLoop, iterableDt: DataType, ident: IdentifierReference) {
// TODO optimize this more
val loopLabel = asmgen.makeLabel("for_loop") val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end") val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel) asmgen.loopEndLabels.push(endLabel)
@ -291,9 +290,9 @@ $loopLabel lda ${65535.toHex()} ; modified
$endLabel""") $endLabel""")
} }
DataType.ARRAY_UB, DataType.ARRAY_B -> { 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 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") val modifiedLabel = asmgen.makeLabel("for_modified")
asmgen.out(""" asmgen.out("""
lda #<$iterableName lda #<$iterableName
@ -315,9 +314,9 @@ $counterLabel .byte 0
$endLabel""") $endLabel""")
} }
DataType.ARRAY_W, DataType.ARRAY_UW -> { 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 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 modifiedLabel = asmgen.makeLabel("for_modified")
val modifiedLabel2 = asmgen.makeLabel("for_modified2") val modifiedLabel2 = asmgen.makeLabel("for_modified2")
val loopvarName = asmgen.asmIdentifierName(stmt.loopVar) val loopvarName = asmgen.asmIdentifierName(stmt.loopVar)

View File

@ -274,22 +274,16 @@ private fun builtinLen(args: List<Expression>, position: Position, program: Prog
arraySize = target.arraysize?.size() arraySize = target.arraysize?.size()
if(arraySize==null) if(arraySize==null)
throw CannotEvaluateException("len", "arraysize unknown") throw CannotEvaluateException("len", "arraysize unknown")
if(arraySize>256)
throw CompilerException("array length exceeds byte limit ${target.position}")
NumericLiteralValue.optimalInteger(arraySize, args[0].position) NumericLiteralValue.optimalInteger(arraySize, args[0].position)
} }
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
arraySize = target.arraysize?.size() arraySize = target.arraysize?.size()
if(arraySize==null) if(arraySize==null)
throw CannotEvaluateException("len", "arraysize unknown") throw CannotEvaluateException("len", "arraysize unknown")
if(arraySize>256)
throw CompilerException("array length exceeds byte limit ${target.position}")
NumericLiteralValue.optimalInteger(arraySize, args[0].position) NumericLiteralValue.optimalInteger(arraySize, args[0].position)
} }
DataType.STR -> { DataType.STR -> {
val refLv = target.value as StringLiteralValue 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) NumericLiteralValue.optimalInteger(refLv.value.length, args[0].position)
} }
in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position) in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position)

View File

@ -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`` can't be used as *identifiers* elsewhere. You can't make a variable, block or subroutine with the name ``byte``
for instance. 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 Strings
^^^^^^^ ^^^^^^^

View File

@ -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:: should be the *memory address* where the value is located::
&byte BORDERCOLOR = $d020 &byte BORDERCOLOR = $d020
&ubyte[5*40] top5screenrows = $0400 ; works for array as well
Direct access to memory locations Direct access to memory locations

View File

@ -2,8 +2,8 @@
TODO TODO
==== ====
- optimize assignment codegeneration
- get rid of all TODO's ;-) - get rid of all TODO's ;-)
- allow declaring arrays on specific memory location and page-aligned
- option to load the built-in library 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' ? - 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 - investigate support for 8bitguy's Commander X16 platform https://www.commanderx16.com and https://github.com/commanderx16/x16-docs

View File

@ -24,20 +24,20 @@ main {
; c64.CHROUT('\n') ; c64.CHROUT('\n')
; ubyte bb ubyte bb
; ubyte from = 10 ubyte from = 10
; ubyte end = 20 ubyte end = 20
;
; for bb in from to end step 3 { for bb in from to end step 3 {
; c64scr.print_ub(bb) c64scr.print_ub(bb)
; c64.CHROUT(',') c64.CHROUT(',')
; } }
; c64.CHROUT('\n') c64.CHROUT('\n')
; for bb in end to from step -3 { for bb in end to from step -3 {
; c64scr.print_ub(bb) c64scr.print_ub(bb)
; c64.CHROUT(',') c64.CHROUT(',')
; } }
; c64.CHROUT('\n') c64.CHROUT('\n')
word ww word ww
word fromw = -10 word fromw = -10