mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
1e776b1f53
2
.gitignore
vendored
2
.gitignore
vendored
@ -23,3 +23,5 @@ __pycache__/
|
||||
parser.out
|
||||
parsetab.py
|
||||
.pytest_cache/
|
||||
compiler/src/prog8_kotlin.jar
|
||||
compiler/src/compiled_java
|
||||
|
@ -7,10 +7,10 @@
|
||||
|
||||
sub start() {
|
||||
|
||||
ubyte pixely = 255
|
||||
ubyte ub = 0
|
||||
byte b = 99
|
||||
byte b2 = 100
|
||||
ubyte ub = 255
|
||||
ubyte ub2 = 0
|
||||
word w = 999
|
||||
word w2 = 3
|
||||
uword uw = 40000
|
||||
@ -33,7 +33,6 @@ sub start() {
|
||||
ubyte[2,3] ubmatrix1
|
||||
ubyte[2,3] ubmatrix2
|
||||
|
||||
|
||||
memory byte mbyte = $c000
|
||||
memory byte mbyte2 = $d000
|
||||
memory ubyte mubyte = $c001
|
||||
@ -44,156 +43,138 @@ sub start() {
|
||||
memory uword muword2 = $d004
|
||||
memory float mfloat = $c006
|
||||
memory float mfloat2 = $d006
|
||||
memory byte[3] mbarr1 = $e000
|
||||
memory ubyte[3] mubarr1 = $e100
|
||||
memory word[3] mwarr1 = $e100
|
||||
memory uword[3] muwarr1 = $e100
|
||||
|
||||
;label:
|
||||
str string = "hello"
|
||||
str_p stringp = "hello"
|
||||
|
||||
|
||||
; all possible assignments to a BYTE VARIABLE (not array)
|
||||
|
||||
byte_assignment_to_register:
|
||||
A = 42
|
||||
A = X
|
||||
A = ub
|
||||
A = mubyte
|
||||
A = AY[4]
|
||||
A = ubarr1[2]
|
||||
A = string[4]
|
||||
A = string[X]
|
||||
A = string[b]
|
||||
A = string[ub]
|
||||
A = ubarr1[X]
|
||||
A = ubarr1[b]
|
||||
A = ubarr1[ub]
|
||||
A = AY[Y]
|
||||
A = AY[b]
|
||||
A = AY[ub]
|
||||
A = ubmatrix1[1,2]
|
||||
;A = ubmatrix1[1,Y] ; todo via evaluation
|
||||
A = ubmatrix1[X,2] ; todo via evaluation TODO fix error constant y dimension of index should have been const-folded with x into one value
|
||||
;A = ubmatrix1[X,Y] ; todo via evaluation
|
||||
;A = ubmatrix1[1,b2] ; todo via evaluation
|
||||
;A = ubmatrix1[X,b2] ; todo via evaluation
|
||||
A = ubmatrix1[b2,2] ; todo FIX ERROR constant y dimension of index should have been const-folded with x into one value
|
||||
;A = ubmatrix1[b2,X] ; todo via evaluation
|
||||
;A = ubmatrix1[b,b2] ; todo via evaluation
|
||||
;A = ubmatrix1[ub,ub2] ; todo via evaluation
|
||||
|
||||
;byte_assignment_to_bytevar:
|
||||
; b = 42
|
||||
; b = b2
|
||||
; b = mbyte
|
||||
; b = barr1[2]
|
||||
; b = bmatrix1[1,2]
|
||||
;
|
||||
; while A>99 {
|
||||
; X=22
|
||||
; }
|
||||
; ub = 42
|
||||
; ub = X
|
||||
; ub = ub2
|
||||
; ub = mubyte
|
||||
; ub = ubarr1[2]
|
||||
; ub = ubmatrix1[1,2]
|
||||
; ub = string[4]
|
||||
; ub = AY[4]
|
||||
;
|
||||
; repeat {
|
||||
; X=22
|
||||
; } until A>99
|
||||
;
|
||||
; for X in 0 to 99 {
|
||||
; Y=33
|
||||
; }
|
||||
;; all possible assignments to a WORD VARIABLE (not array)
|
||||
;
|
||||
; for ubyte derp in 2 to 44 {
|
||||
; X=44
|
||||
; }
|
||||
;word_assignment_to_registerpair:
|
||||
; AY = 42
|
||||
; AY = 42.w
|
||||
; AY = 42555
|
||||
; AY = X
|
||||
; AY = XY
|
||||
; AY = ub
|
||||
; AY = mubyte
|
||||
; AY = ubarr1[2]
|
||||
; AY = ubmatrix1[1,2]
|
||||
; AY = string[4]
|
||||
; AY = uw
|
||||
; AY = muword
|
||||
; AY = uwarr1[2]
|
||||
; AY = string[4]
|
||||
; AY = XY[4]
|
||||
;
|
||||
; if A<22 goto label
|
||||
;;word_assignment_to_wordvar:
|
||||
; w = -42
|
||||
; w = -42.w
|
||||
; w = -12345
|
||||
; w = X
|
||||
; w = b2
|
||||
; w = ub2
|
||||
; w = w2
|
||||
; w = mbyte
|
||||
; w = mubyte
|
||||
; w = mword
|
||||
; w = barr1[2]
|
||||
; w = ubarr1[2]
|
||||
; w = warr1[2]
|
||||
; w = bmatrix1[1,2]
|
||||
; w = ubmatrix1[1,2]
|
||||
; w = string[4]
|
||||
; w = AY[4]
|
||||
;
|
||||
; if X<22 {
|
||||
; A=99
|
||||
; } else {
|
||||
; Y=42
|
||||
; }
|
||||
|
||||
Y=42
|
||||
AY=42
|
||||
AY=42555
|
||||
Y = ub
|
||||
AY= ub
|
||||
AY= uw
|
||||
|
||||
Y = mubyte
|
||||
AY = mubyte
|
||||
AY = muword
|
||||
|
||||
Y = ubarr1[2]
|
||||
AY = ubarr1[2]
|
||||
AY = uwarr1[2]
|
||||
|
||||
barr1[2]=42
|
||||
ubarr1[2]=42
|
||||
warr1[2]=12555
|
||||
uwarr1[2]=42555
|
||||
farr1[2]=42.5678
|
||||
|
||||
ubarr1[2]=X
|
||||
uwarr1[2]=XY
|
||||
; farr1[2]=XY ; @todo
|
||||
|
||||
barr1[2] = b
|
||||
ubarr1[2] = ub
|
||||
warr1[2] = w
|
||||
uwarr1[2] = uw
|
||||
farr1[2] = fl1
|
||||
|
||||
barr1[2] = mbyte
|
||||
ubarr1[2] = mubyte
|
||||
warr1[2] = mword
|
||||
uwarr1[2] = muword
|
||||
farr1[2] = mfloat
|
||||
|
||||
b= barr1[2]
|
||||
ub = ubarr1[2]
|
||||
w = warr1[2]
|
||||
uw = uwarr1[2]
|
||||
; fl1 = farr1[2] ; @todo
|
||||
|
||||
mbyte= barr1[2]
|
||||
mubyte = ubarr1[2]
|
||||
mword = warr1[2]
|
||||
muword = uwarr1[2]
|
||||
; mfloat = farr1[2] ; @todo
|
||||
|
||||
barr1[2] = barr2[3]
|
||||
ubarr1[2] = ubarr2[3]
|
||||
warr1[2] = warr2[3]
|
||||
uwarr1[2] = uwarr2[3]
|
||||
; farr1[2] = farr2[3] ; @todo
|
||||
|
||||
|
||||
XY[2]=42
|
||||
XY[2] = ub
|
||||
XY[2] = mubyte
|
||||
ub = XY[2]
|
||||
uw = XY[2]
|
||||
;fl1 = XY[2] ; @todo
|
||||
mubyte = XY[2]
|
||||
muword = XY[2]
|
||||
;mfloat = XY[2] ; @todo
|
||||
XY[2] = AY[3] ; @todo wat is de output hiervan???
|
||||
|
||||
|
||||
|
||||
b = 1
|
||||
ub = 1
|
||||
w = 1
|
||||
uw = 1
|
||||
fl1 = 2.345
|
||||
|
||||
b = b2
|
||||
ub = pixely
|
||||
w = b2
|
||||
w = w2
|
||||
w = ub
|
||||
uw = ub
|
||||
uw = uw2
|
||||
;fl1 = ub ; @todo
|
||||
;fl1 = b2 ; @todo
|
||||
;fl1 = uw2 ; @todo
|
||||
;fl1 = w2 ; @todo
|
||||
fl1 = fl2
|
||||
|
||||
b = mbyte
|
||||
ub = mubyte
|
||||
w = mword
|
||||
w = mbyte
|
||||
w = mubyte
|
||||
uw = mubyte
|
||||
uw = muword
|
||||
fl1 = mfloat
|
||||
;fl1 = mbyte ; @todo
|
||||
;fl1 = mword ; @todo
|
||||
;fl1 = mubyte ; @todo
|
||||
;fl1 = muword ; @todo
|
||||
|
||||
mbyte = 1
|
||||
mubyte = 1
|
||||
mword = 1
|
||||
muword = 1
|
||||
mfloat = 3.456
|
||||
|
||||
%breakpoint
|
||||
|
||||
mbyte = b
|
||||
mubyte = ub
|
||||
mword = w
|
||||
muword = uw
|
||||
mfloat = fl2
|
||||
|
||||
%breakpoint
|
||||
|
||||
mbyte = mbyte2
|
||||
mubyte = mubyte2
|
||||
mword = mword2
|
||||
muword = muword2
|
||||
mfloat = mfloat2
|
||||
|
||||
; uw = 42
|
||||
; uw = 42.w
|
||||
; uw = 42555
|
||||
; uw = X
|
||||
; uw = AY
|
||||
; uw = ub2
|
||||
; uw = uw2
|
||||
; uw = mubyte
|
||||
; uw = muword
|
||||
; uw = ubarr1[2]
|
||||
; uw = uwarr1[2]
|
||||
; uw = ubmatrix1[1,2]
|
||||
; uw = string[4]
|
||||
; uw = AY[4]
|
||||
;
|
||||
;
|
||||
;; all possible assignments to a FLOAT VARIABLE
|
||||
;float_assignment_to_floatvar:
|
||||
; fl1 = 34
|
||||
; fl1 = 34555.w
|
||||
; fl1 = 3.33e22
|
||||
; fl1 = X
|
||||
; fl1 = AY
|
||||
; fl1 = b2
|
||||
; fl1 = ub2
|
||||
; fl1 = w2
|
||||
; fl1 = uw2
|
||||
; fl1 = mbyte
|
||||
; fl1 = mubyte
|
||||
; fl1 = mword
|
||||
; fl1 = muword
|
||||
; fl1 = barr1[2]
|
||||
; fl1 = ubarr1[2]
|
||||
; fl1 = warr1[2]
|
||||
; fl1 = uwarr1[2]
|
||||
; fl1 = bmatrix1[1,2]
|
||||
; fl1 = ubmatrix1[1,2]
|
||||
; fl1 = string[4]
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
mkdir compiled_java
|
||||
|
||||
java -jar ../antlr/lib/antlr-4.7.1-complete.jar -o ./prog8/parser -no-listener -no-visitor -package prog8.parser ../antlr/prog8.g4
|
||||
java -jar ../antlr/lib/antlr-4.7.1-complete.jar -o ./prog8/parser -Xexact-output-dir -no-listener -no-visitor -package prog8.parser ../antlr/prog8.g4
|
||||
|
||||
@dir /b /S src *.java > sources.txt
|
||||
javac -verbose -d compiled_java -cp ../antlr/lib/antlr-runtime-4.7.1.jar @sources.txt
|
||||
|
@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
java -jar ../antlr/lib/antlr-4.7.1-complete.jar -o ./prog8/parser -Xexact-output-dir -no-listener -no-visitor -package prog8.parser ../antlr/prog8.g4
|
||||
|
||||
find prog8 -name \*.java > javasources.txt
|
||||
mkdir -p compiled_java
|
||||
javac -verbose -d compiled_java -cp ../antlr/lib/antlr-runtime-4.7.1.jar @javasources.txt
|
||||
|
@ -67,7 +67,7 @@ enum class BranchCondition {
|
||||
}
|
||||
|
||||
val IterableDatatypes = setOf(
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.STR, DataType.STR_S, // note: the STR_P/STR_PS types aren't iterable because they store their length as the first byte
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B,
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W,
|
||||
DataType.ARRAY_F, DataType.MATRIX_UB, DataType.MATRIX_B)
|
||||
@ -231,7 +231,7 @@ interface IAstProcessor {
|
||||
|
||||
fun process(arrayIndexedExpression: ArrayIndexedExpression): IExpression {
|
||||
arrayIndexedExpression.identifier?.process(this)
|
||||
arrayIndexedExpression.array.process(this)
|
||||
arrayIndexedExpression.arrayspec.process(this)
|
||||
return arrayIndexedExpression
|
||||
}
|
||||
|
||||
@ -622,7 +622,7 @@ class VarDecl(val type: VarDeclType,
|
||||
DataType.WORD -> DataType.ARRAY_W
|
||||
DataType.FLOAT -> DataType.ARRAY_F
|
||||
else -> {
|
||||
datatypeErrors.add(SyntaxError("array can only contain bytes/words/floats", position))
|
||||
datatypeErrors.add(SyntaxError("arrayspec can only contain bytes/words/floats", position))
|
||||
DataType.UBYTE
|
||||
}
|
||||
}
|
||||
@ -898,13 +898,13 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
|
||||
|
||||
class ArrayIndexedExpression(val identifier: IdentifierReference?,
|
||||
val register: Register?,
|
||||
var array: ArraySpec,
|
||||
var arrayspec: ArraySpec,
|
||||
override val position: Position) : IExpression {
|
||||
override lateinit var parent: Node
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
identifier?.linkParents(this)
|
||||
array.linkParents(this)
|
||||
arrayspec.linkParents(this)
|
||||
}
|
||||
|
||||
override fun isIterable(namespace: INameScope, heap: HeapValues) = false
|
||||
@ -930,6 +930,10 @@ class ArrayIndexedExpression(val identifier: IdentifierReference?,
|
||||
}
|
||||
throw FatalAstException("cannot get indexed element on $target")
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ArrayIndexed(ident=$identifier, reg=$register, arrayspec=$arrayspec; pos=$position)"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1046,8 +1050,8 @@ class LiteralValue(val type: DataType,
|
||||
else "str:$strvalue"
|
||||
}
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> {
|
||||
if(heapId!=null) "array:#$heapId"
|
||||
else "array:$arrayvalue"
|
||||
if(heapId!=null) "arrayspec:#$heapId"
|
||||
else "arrayspec:$arrayvalue"
|
||||
}
|
||||
DataType.MATRIX_UB, DataType.MATRIX_B -> {
|
||||
if(heapId!=null) "matrix:#$heapId"
|
||||
@ -1936,7 +1940,7 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression {
|
||||
litval.charliteral()!=null -> LiteralValue(DataType.UBYTE, bytevalue = Petscii.encodePetscii(litval.charliteral().text.unescape(), true)[0], position = litval.toPosition())
|
||||
litval.arrayliteral()!=null -> {
|
||||
val array = litval.arrayliteral()?.toAst()
|
||||
// the actual type of the array can not yet be determined here (missing namespace & heap)
|
||||
// the actual type of the arrayspec can not yet be determined here (missing namespace & heap)
|
||||
// the ConstantFolder takes care of that and converts the type if needed.
|
||||
LiteralValue(DataType.ARRAY_UB, arrayvalue = array, position = litval.toPosition())
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
if(param.second.register==Register.AX || param.second.register==Register.AY ||
|
||||
param.second.register==Register.XY) {
|
||||
if(param.first.type!=DataType.UWORD && param.first.type !in StringDatatypes && param.first.type !in ArrayDatatypes)
|
||||
err("parameter '${param.first.name}' should be uword/str/array")
|
||||
err("parameter '${param.first.name}' should be uword/str/arrayspec")
|
||||
}
|
||||
}
|
||||
for(ret in subroutine.returntypes.withIndex().zip(subroutine.asmReturnvaluesRegisters)) {
|
||||
@ -260,7 +260,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
ret.second.register==Register.XY) {
|
||||
if(ret.first.value!=DataType.UWORD && ret.first.value != DataType.UBYTE &&
|
||||
ret.first.value !in StringDatatypes && ret.first.value !in ArrayDatatypes)
|
||||
err("return value #${ret.first.index+1} should be uword/ubyte/string/array")
|
||||
err("return value #${ret.first.index+1} should be uword/ubyte/string/arrayspec")
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,11 +330,17 @@ class AstChecker(private val namespace: INameScope,
|
||||
return super.process(assignment)
|
||||
}
|
||||
}
|
||||
} else if(assignment.target.arrayindexed!=null) {
|
||||
if(assignment.target.arrayindexed!!.register!=null) {
|
||||
val value = assignment.value
|
||||
if (value is ArrayIndexedExpression && value.register in setOf(Register.AX, Register.AY, Register.XY))
|
||||
checkResult.add(SyntaxError("reading AND writing from registerpair arrays not supported due to register overlap", assignment.position))
|
||||
}
|
||||
}
|
||||
|
||||
// it is not possible to assign a new array to something.
|
||||
// it is not possible to assign a new arrayspec to something.
|
||||
if(assignment.value.resultingDatatype(namespace, heap) in ArrayDatatypes)
|
||||
checkResult.add(SyntaxError("it's not possible to assign an array literal value to something, use it as a variable decl initializer instead", assignment.position))
|
||||
checkResult.add(SyntaxError("it's not possible to assign an arrayspec literal value to something, use it as a variable decl initializer instead", assignment.position))
|
||||
|
||||
if(assignment.aug_op!=null) {
|
||||
// check augmented assignment:
|
||||
@ -440,6 +446,25 @@ class AstChecker(private val namespace: INameScope,
|
||||
}
|
||||
}
|
||||
VarDeclType.MEMORY -> {
|
||||
if(decl.arrayspec!=null) {
|
||||
val arraySize = decl.arrayspec.size() ?: 1
|
||||
when(decl.datatype) {
|
||||
DataType.ARRAY_B, DataType.ARRAY_UB ->
|
||||
if(arraySize > 256)
|
||||
err("byte arrayspec length must be 1-256")
|
||||
DataType.ARRAY_W, DataType.ARRAY_UW ->
|
||||
if(arraySize > 128)
|
||||
err("word arrayspec length must be 1-128")
|
||||
DataType.ARRAY_F ->
|
||||
if(arraySize > 51)
|
||||
err("float arrayspec length must be 1-51")
|
||||
DataType.MATRIX_B, DataType.MATRIX_UB ->
|
||||
if(arraySize > 32768)
|
||||
err("invalid matrix size, must be 1-32768")
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
if(decl.value !is LiteralValue) {
|
||||
err("value of memory var decl is not a literal (it is a ${decl.value!!::class.simpleName}).", decl.value?.position)
|
||||
} else {
|
||||
@ -545,7 +570,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
if(lv.heapId==null)
|
||||
throw FatalAstException("array/matrix should have been moved to heap at ${lv.position}")
|
||||
throw FatalAstException("arrayspec/matrix should have been moved to heap at ${lv.position}")
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
@ -677,7 +702,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
val indexedRegister = postIncrDecr.target.arrayindexed?.register
|
||||
if(indexedRegister!=null) {
|
||||
if(indexedRegister==Register.A || indexedRegister==Register.X || indexedRegister==Register.Y)
|
||||
checkResult.add(SyntaxError("array indexing on registers requires register pair variable", postIncrDecr.position))
|
||||
checkResult.add(SyntaxError("indexing on registers requires register pair variable", postIncrDecr.position))
|
||||
} else {
|
||||
val target = postIncrDecr.target.arrayindexed?.identifier?.targetStatement(namespace)
|
||||
if(target==null) {
|
||||
@ -699,25 +724,45 @@ class AstChecker(private val namespace: INameScope,
|
||||
val target = arrayIndexedExpression.identifier!!.targetStatement(namespace)
|
||||
if(target is VarDecl) {
|
||||
if(target.datatype !in IterableDatatypes)
|
||||
checkResult.add(SyntaxError("array indexing requires an iterable variable", arrayIndexedExpression.position))
|
||||
checkResult.add(SyntaxError("indexing requires an iterable variable", arrayIndexedExpression.position))
|
||||
val arraysize = target.arrayspec?.size()
|
||||
if(arraysize!=null) {
|
||||
// check out of bounds
|
||||
if((arrayIndexedExpression.array.y as? LiteralValue)?.asIntegerValue != null) {
|
||||
throw FatalAstException("constant y dimension of index should have been const-folded with x into one value")
|
||||
if((arrayIndexedExpression.arrayspec.y as? LiteralValue)?.asIntegerValue != null) {
|
||||
throw FatalAstException("constant y dimension of index should have been const-folded with x into one value ${arrayIndexedExpression.arrayspec.position}")
|
||||
}
|
||||
val index = (arrayIndexedExpression.array.x as? LiteralValue)?.asIntegerValue
|
||||
val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue
|
||||
if(index!=null && (index<0 || index>=arraysize))
|
||||
checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.array.position))
|
||||
checkResult.add(ExpressionError("arrayspec index out of bounds", arrayIndexedExpression.arrayspec.position))
|
||||
} else if(target.datatype in StringDatatypes) {
|
||||
// check string lengths
|
||||
(arrayIndexedExpression.arrayspec.y as? LiteralValue)?.asIntegerValue
|
||||
val heapId = (target.value as LiteralValue).heapId!!
|
||||
val stringLen = heap.get(heapId).str!!.length
|
||||
val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue
|
||||
if(index!=null && (index<0 || index>=stringLen))
|
||||
checkResult.add(ExpressionError("index out of bounds", arrayIndexedExpression.arrayspec.position))
|
||||
}
|
||||
} else
|
||||
checkResult.add(SyntaxError("array indexing requires a variable to act upon", arrayIndexedExpression.position))
|
||||
checkResult.add(SyntaxError("indexing requires a variable to act upon", arrayIndexedExpression.position))
|
||||
} else if(reg==Register.A || reg==Register.X || reg==Register.Y) {
|
||||
checkResult.add(SyntaxError("array indexing on registers requires register pair variable", arrayIndexedExpression.position))
|
||||
} else if(arrayIndexedExpression.array.y!=null) {
|
||||
checkResult.add(SyntaxError("array indexing on registers can only use one index dimension", arrayIndexedExpression.position))
|
||||
checkResult.add(SyntaxError("indexing on registers requires register pair variable", arrayIndexedExpression.position))
|
||||
} else if(arrayIndexedExpression.arrayspec.y!=null) {
|
||||
checkResult.add(SyntaxError("indexing on registers can only use one index dimension", arrayIndexedExpression.position))
|
||||
}
|
||||
|
||||
// check index value 0..255
|
||||
val regx = (arrayIndexedExpression.arrayspec.x as? RegisterExpr)?.register
|
||||
val regy = (arrayIndexedExpression.arrayspec.y as? RegisterExpr)?.register
|
||||
if((regx in setOf(Register.AX, Register.AY, Register.XY)) ||
|
||||
(regy in setOf(Register.AX, Register.AY, Register.XY))) {
|
||||
checkResult.add(SyntaxError("array indexing is limited to byte size 0..255", arrayIndexedExpression.position))
|
||||
}
|
||||
val dtx = arrayIndexedExpression.arrayspec.x.resultingDatatype(namespace, heap)
|
||||
val dty = arrayIndexedExpression.arrayspec.y?.resultingDatatype(namespace, heap)
|
||||
if(dtx!=DataType.UBYTE && dtx!=DataType.BYTE || (dty!=null && dty != DataType.UBYTE && dty != DataType.BYTE))
|
||||
checkResult.add(SyntaxError("array indexing is limited to byte size 0..255", arrayIndexedExpression.position))
|
||||
|
||||
return super.process(arrayIndexedExpression)
|
||||
}
|
||||
|
||||
@ -760,7 +805,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
val expectedSize = arrayspec!!.size()
|
||||
val rangeSize=range.size()
|
||||
if(rangeSize!=null && rangeSize != expectedSize) {
|
||||
checkResult.add(ExpressionError("range size doesn't match array/matrix size, expected $expectedSize found $rangeSize", range.position))
|
||||
checkResult.add(ExpressionError("range size doesn't match arrayspec/matrix size, expected $expectedSize found $rangeSize", range.position))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@ -825,61 +870,61 @@ class AstChecker(private val namespace: INameScope,
|
||||
return err("string length must be 0-255")
|
||||
}
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||
// value may be either a single byte, or a byte array (of all constant values)
|
||||
// value may be either a single byte, or a byte arrayspec (of all constant values)
|
||||
if(value.type==targetDt) {
|
||||
val arraySpecSize = arrayspec.size()
|
||||
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize
|
||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||
if(arraySpecSize<1 || arraySpecSize>256)
|
||||
return err("byte array length must be 1-256")
|
||||
return err("byte arrayspec length must be 1-256")
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
if(constX?.asIntegerValue==null)
|
||||
return err("array size specifier must be constant integer value")
|
||||
return err("arrayspec size specifier must be constant integer value")
|
||||
val expectedSize = constX.asIntegerValue
|
||||
if (arraySize != expectedSize)
|
||||
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
|
||||
return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)")
|
||||
return true
|
||||
}
|
||||
return err("invalid byte array size, must be 1-256")
|
||||
return err("invalid byte arrayspec size, must be 1-256")
|
||||
}
|
||||
return err("invalid byte array initialization value ${value.type}, expected $targetDt")
|
||||
return err("invalid byte arrayspec initialization value ${value.type}, expected $targetDt")
|
||||
}
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
// value may be either a single word, or a word array
|
||||
// value may be either a single word, or a word arrayspec
|
||||
if(value.type==targetDt) {
|
||||
val arraySpecSize = arrayspec.size()
|
||||
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize
|
||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||
if(arraySpecSize<1 || arraySpecSize>128)
|
||||
return err("word array length must be 1-128")
|
||||
return err("word arrayspec length must be 1-128")
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
if(constX?.asIntegerValue==null)
|
||||
return err("array size specifier must be constant integer value")
|
||||
return err("arrayspec size specifier must be constant integer value")
|
||||
val expectedSize = constX.asIntegerValue
|
||||
if (arraySize != expectedSize)
|
||||
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
|
||||
return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)")
|
||||
return true
|
||||
}
|
||||
return err("invalid word array size, must be 1-128")
|
||||
return err("invalid word arrayspec size, must be 1-128")
|
||||
}
|
||||
return err("invalid word array initialization value ${value.type}, expected $targetDt")
|
||||
return err("invalid word arrayspec initialization value ${value.type}, expected $targetDt")
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
// value may be either a single float, or a float array
|
||||
// value may be either a single float, or a float arrayspec
|
||||
if(value.type==targetDt) {
|
||||
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).doubleArray!!.size
|
||||
val arraySpecSize = arrayspec.size()
|
||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||
if(arraySpecSize < 1 || arraySpecSize>51)
|
||||
return err("float array length must be 1-51")
|
||||
return err("float arrayspec length must be 1-51")
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
if(constX?.asIntegerValue==null)
|
||||
return err("array size specifier must be constant integer value")
|
||||
return err("arrayspec size specifier must be constant integer value")
|
||||
val expectedSize = constX.asIntegerValue
|
||||
if (arraySize != expectedSize)
|
||||
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
|
||||
return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)")
|
||||
} else
|
||||
return err("invalid float array size, must be 1-51")
|
||||
return err("invalid float arrayspec size, must be 1-51")
|
||||
|
||||
// check if the floating point values are all within range
|
||||
val doubles = if(value.arrayvalue!=null)
|
||||
@ -890,17 +935,17 @@ class AstChecker(private val namespace: INameScope,
|
||||
return err("floating point value overflow")
|
||||
return true
|
||||
}
|
||||
return err("invalid float array initialization value ${value.type}, expected $targetDt")
|
||||
return err("invalid float arrayspec initialization value ${value.type}, expected $targetDt")
|
||||
}
|
||||
DataType.MATRIX_UB, DataType.MATRIX_B -> {
|
||||
// value can only be a single byte, or a byte array (which represents the matrix)
|
||||
// value can only be a single byte, or a byte arrayspec (which represents the matrix)
|
||||
if(value.type==targetDt ||
|
||||
(targetDt==DataType.MATRIX_UB && value.type==DataType.ARRAY_UB) ||
|
||||
(targetDt==DataType.MATRIX_B && value.type==DataType.ARRAY_B)) {
|
||||
val arraySpecSize = arrayspec.size()
|
||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||
if(arraySpecSize<1 || arraySpecSize>256)
|
||||
return err("invalid matrix size, must be 1-256")
|
||||
if(arraySpecSize<1 || arraySpecSize>32768)
|
||||
return err("invalid matrix size, must be 1-32768")
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
val constY = arrayspec.y?.constValue(namespace, heap)
|
||||
if (constX?.asIntegerValue == null || (constY!=null && constY.asIntegerValue == null))
|
||||
@ -912,9 +957,9 @@ class AstChecker(private val namespace: INameScope,
|
||||
return err("initializer matrix size mismatch (expecting $expectedSize, got ${matrix.size} elements)")
|
||||
return true
|
||||
}
|
||||
return err("invalid matrix size, must be 1-256")
|
||||
return err("invalid matrix size, must be 1-32768")
|
||||
}
|
||||
return err("invalid matrix initialization value of type ${value.type} - expecting byte array")
|
||||
return err("invalid matrix initialization value of type ${value.type} - expecting byte arrayspec")
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
@ -126,7 +126,7 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
if(forLoop.decltype!=null)
|
||||
checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position))
|
||||
if(forLoop.loopRegister == Register.X || forLoop.loopRegister==Register.XY || forLoop.loopRegister==Register.AX)
|
||||
checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", forLoop.position))
|
||||
printWarning("possible problem writing to the X register, because it's used as an internal pointer", forLoop.position)
|
||||
} else if(forLoop.loopVar!=null) {
|
||||
val varName = forLoop.loopVar.nameInSource.last()
|
||||
when (forLoop.decltype) {
|
||||
@ -148,7 +148,7 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
|
||||
override fun process(assignTarget: AssignTarget): AssignTarget {
|
||||
if(assignTarget.register==Register.X || assignTarget.register==Register.AX || assignTarget.register==Register.XY)
|
||||
checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", assignTarget.position))
|
||||
printWarning("possible problem writing to the X register, because it's used as an internal pointer", assignTarget.position)
|
||||
return super.process(assignTarget)
|
||||
}
|
||||
}
|
||||
|
@ -312,7 +312,9 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.READ_INDEXED_VAR_WORD
|
||||
DataType.ARRAY_F -> Opcode.READ_INDEXED_VAR_FLOAT
|
||||
DataType.MATRIX_UB, DataType.MATRIX_B -> Opcode.READ_INDEXED_VAR_BYTE
|
||||
else -> throw CompilerException("invalid dt for indexed $dt")
|
||||
DataType.STR, DataType.STR_S -> Opcode.READ_INDEXED_VAR_BYTE
|
||||
DataType.STR_P, DataType.STR_PS -> throw CompilerException("cannot access pascal-string type $dt with index")
|
||||
else -> throw CompilerException("invalid dt for indexed access $dt")
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,7 +324,9 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.WRITE_INDEXED_VAR_WORD
|
||||
DataType.ARRAY_F -> Opcode.WRITE_INDEXED_VAR_FLOAT
|
||||
DataType.MATRIX_UB, DataType.MATRIX_B -> Opcode.WRITE_INDEXED_VAR_BYTE
|
||||
else -> throw CompilerException("invalid dt for indexed $dt")
|
||||
DataType.STR, DataType.STR_S -> Opcode.WRITE_INDEXED_VAR_BYTE
|
||||
DataType.STR_P, DataType.STR_PS -> throw CompilerException("cannot access pascal-string type $dt with index")
|
||||
else -> throw CompilerException("invalid dt for indexed access $dt")
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,14 +354,12 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
|
||||
private fun opcodePopmem(dt: DataType): Opcode {
|
||||
return when (dt) {
|
||||
DataType.UBYTE -> Opcode.POP_MEM_UB
|
||||
DataType.BYTE -> Opcode.POP_MEM_B
|
||||
DataType.UWORD -> Opcode.POP_MEM_UW
|
||||
DataType.WORD -> Opcode.POP_MEM_W
|
||||
DataType.UBYTE, DataType.BYTE -> Opcode.POP_MEM_BYTE
|
||||
DataType.UWORD, DataType.WORD -> Opcode.POP_MEM_WORD
|
||||
DataType.FLOAT -> Opcode.POP_MEM_FLOAT
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.MATRIX_UB,
|
||||
DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> Opcode.POP_MEM_UW
|
||||
DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> Opcode.POP_MEM_WORD
|
||||
}
|
||||
}
|
||||
|
||||
@ -628,7 +630,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.MATRIX_UB,
|
||||
DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> {
|
||||
if(lv.heapId==null)
|
||||
throw CompilerException("array/matrix should have been moved into heap ${lv.position}")
|
||||
throw CompilerException("arrayspec/matrix should have been moved into heap ${lv.position}")
|
||||
prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.heapId))
|
||||
}
|
||||
}
|
||||
@ -1046,14 +1048,14 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
val reg=arrayindexed.register
|
||||
if(reg==Register.A || reg==Register.X || reg==Register.Y)
|
||||
throw CompilerException("requires register pair")
|
||||
if(arrayindexed.array.y!=null)
|
||||
if(arrayindexed.arrayspec.y!=null)
|
||||
throw CompilerException("when using an address, can only use one index dimension")
|
||||
reg.toString()
|
||||
} else {
|
||||
variable!!.scopedname
|
||||
}
|
||||
translate(arrayindexed.array.x)
|
||||
val y = arrayindexed.array.y
|
||||
translate(arrayindexed.arrayspec.x)
|
||||
val y = arrayindexed.arrayspec.y
|
||||
if(y!=null) {
|
||||
// calc matrix index i=y*columns+x
|
||||
// (the const-folding will have removed this for us when both x and y are constants)
|
||||
@ -1167,12 +1169,12 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
when (valueDt) {
|
||||
DataType.UBYTE -> prog.instr(Opcode.UB2FLOAT)
|
||||
DataType.BYTE -> prog.instr(Opcode.B2FLOAT)
|
||||
DataType.UWORD -> prog.instr(Opcode.W2FLOAT)
|
||||
DataType.WORD -> prog.instr(Opcode.UW2FLOAT)
|
||||
DataType.UWORD -> prog.instr(Opcode.UW2FLOAT)
|
||||
DataType.WORD -> prog.instr(Opcode.W2FLOAT)
|
||||
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||
}
|
||||
}
|
||||
// todo: maybe if you assign byte or word to array/matrix, clear it with that value?
|
||||
// todo: maybe if you assign byte or word to arrayspec/matrix, clear it with that value?
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W,
|
||||
DataType.ARRAY_F, DataType.MATRIX_UB, DataType.MATRIX_B -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||
|
@ -16,15 +16,15 @@ abstract class Zeropage(private val options: CompilationOptions) {
|
||||
|
||||
val size =
|
||||
if(vardecl.arrayspec!=null) {
|
||||
printWarning("allocating a large value (array) in zeropage", vardecl.position)
|
||||
printWarning("allocating a large value (arrayspec) in zeropage", vardecl.position)
|
||||
val y = (vardecl.arrayspec.y as? LiteralValue)?.asIntegerValue
|
||||
if(y==null) {
|
||||
// 1 dimensional array
|
||||
// 1 dimensional arrayspec
|
||||
when(vardecl.datatype) {
|
||||
DataType.UBYTE -> (vardecl.arrayspec.x as LiteralValue).asIntegerValue!!
|
||||
DataType.UWORD -> (vardecl.arrayspec.x as LiteralValue).asIntegerValue!! * 2
|
||||
DataType.FLOAT -> (vardecl.arrayspec.x as LiteralValue).asIntegerValue!! * 5
|
||||
else -> throw CompilerException("array can only be of byte, word, float")
|
||||
else -> throw CompilerException("arrayspec can only be of byte, word, float")
|
||||
}
|
||||
} else {
|
||||
// 2 dimensional matrix (only bytes for now)
|
||||
|
@ -25,10 +25,6 @@ open class Instruction(val opcode: Opcode,
|
||||
// opcodes that manipulate a variable
|
||||
"${opcode.toString().toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd()
|
||||
}
|
||||
opcode in setOf(Opcode.COPY_MEM_BYTE, Opcode.COPY_MEM_WORD, Opcode.COPY_MEM_FLOAT) -> {
|
||||
// opcodes with two (address) args
|
||||
"${opcode.toString().toLowerCase()} $arg $arg2"
|
||||
}
|
||||
callLabel==null -> "${opcode.toString().toLowerCase()} $argStr"
|
||||
else -> "${opcode.toString().toLowerCase()} $callLabel $argStr"
|
||||
}
|
||||
|
@ -79,54 +79,47 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
when (it[0].value.opcode) {
|
||||
Opcode.PUSH_VAR_BYTE ->
|
||||
if (it[1].value.opcode == Opcode.POP_VAR_BYTE) {
|
||||
if (it[0].value.callLabel != it[1].value.callLabel)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_BYTE, null, null, it[0].value.callLabel, it[1].value.callLabel)
|
||||
else
|
||||
if (it[0].value.callLabel == it[1].value.callLabel) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD ->
|
||||
if (it[1].value.opcode == Opcode.POP_VAR_WORD) {
|
||||
if (it[0].value.callLabel != it[1].value.callLabel)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_WORD, null, null, it[0].value.callLabel, it[1].value.callLabel)
|
||||
else
|
||||
if (it[0].value.callLabel == it[1].value.callLabel) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT ->
|
||||
if (it[1].value.opcode == Opcode.POP_VAR_FLOAT) {
|
||||
if (it[0].value.callLabel != it[1].value.callLabel)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_FLOAT, null, null, it[0].value.callLabel, it[1].value.callLabel)
|
||||
else
|
||||
if (it[0].value.callLabel == it[1].value.callLabel) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB ->
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_B || it[1].value.opcode == Opcode.POP_MEM_UB) {
|
||||
if(it[0].value.arg != it[1].value.arg)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_BYTE, it[0].value.arg, it[1].value.arg)
|
||||
else
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_BYTE) {
|
||||
if(it[0].value.arg == it[1].value.arg) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW ->
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_W || it[1].value.opcode == Opcode.POP_MEM_UW) {
|
||||
if(it[0].value.arg != it[1].value.arg)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_WORD, it[0].value.arg, it[1].value.arg)
|
||||
else
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_WORD) {
|
||||
if(it[0].value.arg == it[1].value.arg) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_MEM_FLOAT ->
|
||||
if(it[1].value.opcode == Opcode.POP_MEM_FLOAT) {
|
||||
if(it[0].value.arg != it[1].value.arg)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_FLOAT, it[0].value.arg, it[1].value.arg)
|
||||
else
|
||||
if(it[0].value.arg == it[1].value.arg) {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,7 +282,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F -> {
|
||||
val litval = (decl.value as LiteralValue)
|
||||
if(litval.heapId==null)
|
||||
throw CompilerException("array/matrix should already be in the heap")
|
||||
throw CompilerException("arrayspec/matrix should already be in the heap")
|
||||
Value(decl.datatype, litval.heapId)
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ enum class Opcode {
|
||||
|
||||
// pushing values on the (evaluation) stack
|
||||
PUSH_BYTE, // push byte value
|
||||
PUSH_WORD, // push word value (or 'address' of string / array / matrix)
|
||||
PUSH_WORD, // push word value (or 'address' of string / arrayspec / matrix)
|
||||
PUSH_FLOAT, // push float value
|
||||
PUSH_MEM_B, // push byte value from memory to stack
|
||||
PUSH_MEM_UB, // push unsigned byte value from memory to stack
|
||||
@ -19,23 +19,13 @@ enum class Opcode {
|
||||
DISCARD_BYTE, // discard top byte value
|
||||
DISCARD_WORD, // discard top word value
|
||||
DISCARD_FLOAT, // discard top float value
|
||||
POP_MEM_B, // pop byte value into destination memory address
|
||||
POP_MEM_UB, // pop byte value into destination memory address
|
||||
POP_MEM_W, // pop word value into destination memory address
|
||||
POP_MEM_UW, // pop word value into destination memory address
|
||||
POP_MEM_BYTE, // pop (u)byte value into destination memory address
|
||||
POP_MEM_WORD, // pop (u)word value into destination memory address
|
||||
POP_MEM_FLOAT, // pop float value into destination memory address
|
||||
POP_VAR_BYTE, // pop byte value into variable (byte, ubyte)
|
||||
POP_VAR_WORD, // pop word value into variable (word, uword)
|
||||
POP_VAR_BYTE, // pop (u)byte value into variable
|
||||
POP_VAR_WORD, // pop (u)word value into variable
|
||||
POP_VAR_FLOAT, // pop float value into variable
|
||||
|
||||
// optimized copying of one var to another (replaces push+pop)
|
||||
COPY_VAR_BYTE,
|
||||
COPY_VAR_WORD,
|
||||
COPY_VAR_FLOAT,
|
||||
COPY_MEM_BYTE,
|
||||
COPY_MEM_WORD,
|
||||
COPY_MEM_FLOAT,
|
||||
|
||||
// numeric arithmetic
|
||||
ADD_UB,
|
||||
ADD_B,
|
||||
@ -187,7 +177,7 @@ enum class Opcode {
|
||||
NOTEQUAL_WORD,
|
||||
NOTEQUAL_F,
|
||||
|
||||
// array access
|
||||
// arrayspec access
|
||||
READ_INDEXED_VAR_BYTE,
|
||||
READ_INDEXED_VAR_WORD,
|
||||
READ_INDEXED_VAR_FLOAT,
|
||||
@ -233,32 +223,6 @@ val opcodesWithVarArgument = setOf(
|
||||
Opcode.ROL2_VAR_BYTE, Opcode.ROL2_VAR_WORD, Opcode.ROR2_VAR_BYTE, Opcode.ROR2_VAR_WORD,
|
||||
Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT,
|
||||
Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT,
|
||||
Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT,
|
||||
Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT,
|
||||
Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT
|
||||
)
|
||||
|
||||
val pushOpcodes = setOf(
|
||||
Opcode.PUSH_BYTE,
|
||||
Opcode.PUSH_WORD,
|
||||
Opcode.PUSH_FLOAT,
|
||||
Opcode.PUSH_MEM_B,
|
||||
Opcode.PUSH_MEM_UB,
|
||||
Opcode.PUSH_MEM_W,
|
||||
Opcode.PUSH_MEM_UW,
|
||||
Opcode.PUSH_MEM_FLOAT,
|
||||
Opcode.PUSH_VAR_BYTE,
|
||||
Opcode.PUSH_VAR_WORD,
|
||||
Opcode.PUSH_VAR_FLOAT
|
||||
)
|
||||
|
||||
val popOpcodes = setOf(
|
||||
Opcode.POP_MEM_B,
|
||||
Opcode.POP_MEM_UB,
|
||||
Opcode.POP_MEM_W,
|
||||
Opcode.POP_MEM_UW,
|
||||
Opcode.POP_MEM_FLOAT,
|
||||
Opcode.POP_VAR_BYTE,
|
||||
Opcode.POP_VAR_WORD,
|
||||
Opcode.POP_VAR_FLOAT
|
||||
)
|
File diff suppressed because it is too large
Load Diff
@ -100,7 +100,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
||||
if(arglist.type==DataType.ARRAY_UB || arglist.type==DataType.ARRAY_UW || arglist.type==DataType.ARRAY_F || arglist.type==DataType.MATRIX_UB) {
|
||||
val dt = arglist.arrayvalue!!.map {it.resultingDatatype(namespace, heap)}
|
||||
if(dt.any { it!=DataType.UBYTE && it!=DataType.UWORD && it!=DataType.FLOAT}) {
|
||||
throw FatalAstException("fuction $function only accepts array of numeric values")
|
||||
throw FatalAstException("fuction $function only accepts arrayspec of numeric values")
|
||||
}
|
||||
if(dt.any { it==DataType.FLOAT }) return DataType.FLOAT
|
||||
if(dt.any { it==DataType.UWORD }) return DataType.UWORD
|
||||
@ -119,10 +119,10 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
||||
DataType.ARRAY_F -> DataType.FLOAT
|
||||
DataType.MATRIX_UB -> DataType.UBYTE
|
||||
DataType.MATRIX_B -> DataType.BYTE
|
||||
null -> throw FatalAstException("function requires one argument which is an array $function")
|
||||
null -> throw FatalAstException("function requires one argument which is an arrayspec $function")
|
||||
}
|
||||
}
|
||||
throw FatalAstException("function requires one argument which is an array $function")
|
||||
throw FatalAstException("function requires one argument which is an arrayspec $function")
|
||||
}
|
||||
|
||||
val func = BuiltinFunctions[function]!!
|
||||
@ -237,7 +237,7 @@ private fun collectionArgOutputBoolean(args: List<IExpression>, position: Positi
|
||||
throw NotConstArgumentException()
|
||||
function(constants.map { it!!.toDouble() })
|
||||
} else {
|
||||
val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("function requires array/matrix argument", position)
|
||||
val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("function requires arrayspec/matrix argument", position)
|
||||
function(array.map { it.toDouble() })
|
||||
}
|
||||
return LiteralValue.fromBoolean(result, position)
|
||||
@ -313,7 +313,7 @@ private fun builtinAbs(args: List<IExpression>, position: Position, namespace:IN
|
||||
|
||||
private fun builtinAvg(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue {
|
||||
if(args.size!=1)
|
||||
throw SyntaxError("avg requires array/matrix argument", position)
|
||||
throw SyntaxError("avg requires arrayspec/matrix argument", position)
|
||||
val iterable = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException()
|
||||
|
||||
val result = if(iterable.arrayvalue!=null) {
|
||||
@ -323,7 +323,7 @@ private fun builtinAvg(args: List<IExpression>, position: Position, namespace:IN
|
||||
(constants.map { it!!.toDouble() }).average()
|
||||
}
|
||||
else {
|
||||
val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("avg requires array/matrix argument", position)
|
||||
val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("avg requires arrayspec/matrix argument", position)
|
||||
array.average()
|
||||
}
|
||||
return numericLiteral(result, args[0].position)
|
||||
|
@ -56,10 +56,10 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.MATRIX_UB, DataType.MATRIX_B -> {
|
||||
val litval = decl.value as? LiteralValue
|
||||
if(litval?.type==DataType.FLOAT)
|
||||
errors.add(ExpressionError("array requires only integers here", litval.position))
|
||||
errors.add(ExpressionError("arrayspec requires only integers here", litval.position))
|
||||
val size = decl.arrayspec!!.size()
|
||||
if(litval!=null && litval.isArray) {
|
||||
// array initializer value is an array already, keep as-is (or convert to WORDs if needed)
|
||||
// arrayspec initializer value is an arrayspec already, keep as-is (or convert to WORDs if needed)
|
||||
if(litval.heapId!=null) {
|
||||
if (decl.datatype == DataType.MATRIX_UB && litval.type != DataType.MATRIX_UB) {
|
||||
val array = heap.get(litval.heapId).copy(type = DataType.MATRIX_UB)
|
||||
@ -79,7 +79,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
}
|
||||
}
|
||||
} else if (size != null) {
|
||||
// array initializer is empty or a single int, and we know the size; create the array.
|
||||
// arrayspec initializer is empty or a single int, and we know the size; create the arrayspec.
|
||||
val fillvalue = if (litval == null) 0 else litval.asIntegerValue ?: 0
|
||||
when(decl.datatype){
|
||||
DataType.ARRAY_UB, DataType.MATRIX_UB -> {
|
||||
@ -109,7 +109,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
val litval = decl.value as? LiteralValue
|
||||
val size = decl.arrayspec!!.size()
|
||||
if(litval!=null && litval.isArray) {
|
||||
// array initializer value is an array already, make sure to convert to floats
|
||||
// arrayspec initializer value is an arrayspec already, make sure to convert to floats
|
||||
if(litval.heapId!=null) {
|
||||
val array = heap.get(litval.heapId)
|
||||
if (array.doubleArray == null) {
|
||||
@ -119,7 +119,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
}
|
||||
}
|
||||
} else if (size != null) {
|
||||
// array initializer is empty or a single int, and we know the size; create the array.
|
||||
// arrayspec initializer is empty or a single int, and we know the size; create the arrayspec.
|
||||
val fillvalue = if (litval == null) 0.0 else litval.asNumericValue?.toDouble() ?: 0.0
|
||||
if(fillvalue< FLOAT_MAX_NEGATIVE || fillvalue> FLOAT_MAX_POSITIVE)
|
||||
errors.add(ExpressionError("float value overflow", litval?.position ?: decl.position))
|
||||
@ -492,7 +492,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
val array: Array<IExpression> = arraylit.arrayvalue!!.map { it.process(this) }.toTypedArray()
|
||||
val allElementsAreConstant = array.fold(true) { c, expr-> c and (expr is LiteralValue)}
|
||||
if(!allElementsAreConstant) {
|
||||
addError(ExpressionError("array/matrix literal can contain only constant values", arraylit.position))
|
||||
addError(ExpressionError("arrayspec/matrix literal can contain only constant values", arraylit.position))
|
||||
return arraylit
|
||||
} else {
|
||||
val valuesInArray = array.map { it.constValue(namespace, heap)!!.asNumericValue!! }
|
||||
@ -533,24 +533,24 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
DataType.MATRIX_UB,
|
||||
DataType.MATRIX_B -> heap.add(arrayDt, integerArray)
|
||||
DataType.ARRAY_F -> heap.add(arrayDt, doubleArray)
|
||||
else -> throw CompilerException("invalid array type")
|
||||
else -> throw CompilerException("invalid arrayspec type")
|
||||
}
|
||||
return LiteralValue(arrayDt, heapId = heapId, position = arraylit.position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun process(arrayIndexedExpression: ArrayIndexedExpression): IExpression {
|
||||
if(arrayIndexedExpression.array.y!=null) {
|
||||
if(arrayIndexedExpression.array.size()!=null) {
|
||||
if(arrayIndexedExpression.arrayspec.y!=null) {
|
||||
if(arrayIndexedExpression.arrayspec.size()!=null) {
|
||||
// both x and y are known
|
||||
// calculate the 2-dimension index i = y*columns + x
|
||||
if(arrayIndexedExpression.identifier!=null) {
|
||||
val x = (arrayIndexedExpression.array.x as LiteralValue).asIntegerValue!!
|
||||
val y = (arrayIndexedExpression.array.y as LiteralValue).asIntegerValue!!
|
||||
val x = (arrayIndexedExpression.arrayspec.x as LiteralValue).asIntegerValue!!
|
||||
val y = (arrayIndexedExpression.arrayspec.y as LiteralValue).asIntegerValue!!
|
||||
val variable = arrayIndexedExpression.identifier.targetStatement(namespace) as? VarDecl
|
||||
if(variable!=null) {
|
||||
val index = x + y * (variable.arrayspec!!.x as LiteralValue).asIntegerValue!!
|
||||
arrayIndexedExpression.array = ArraySpec(LiteralValue.optimalInteger(index, arrayIndexedExpression.array.position), null, arrayIndexedExpression.array.position)
|
||||
arrayIndexedExpression.arrayspec = ArraySpec(LiteralValue.optimalInteger(index, arrayIndexedExpression.arrayspec.position), null, arrayIndexedExpression.arrayspec.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,16 +124,6 @@ class Program (val name: String,
|
||||
val args = if(parts.size==2) parts[1] else null
|
||||
val instruction = when(opcode) {
|
||||
Opcode.LINE -> Instruction(opcode, null, callLabel = args)
|
||||
Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT -> {
|
||||
val (v1, v2) = args!!.split(splitpattern, limit = 2)
|
||||
Instruction(opcode, null, null, v1, v2)
|
||||
}
|
||||
Opcode.COPY_MEM_BYTE, Opcode.COPY_MEM_WORD, Opcode.COPY_MEM_FLOAT -> {
|
||||
val (v1, v2) = args!!.split(splitpattern, limit = 2)
|
||||
val address1 = getArgValue(v1, heap)
|
||||
val address2 = getArgValue(v2, heap)
|
||||
Instruction(opcode, address1, address2)
|
||||
}
|
||||
Opcode.JUMP, Opcode.CALL, Opcode.BNEG, Opcode.BPOS,
|
||||
Opcode.BZ, Opcode.BNZ, Opcode.BCS, Opcode.BCC -> {
|
||||
if(args!!.startsWith('$')) {
|
||||
@ -222,7 +212,7 @@ class Program (val name: String,
|
||||
DataType.MATRIX_UB,
|
||||
DataType.MATRIX_B -> {
|
||||
if(!valueStr.startsWith("heap:"))
|
||||
throw VmExecutionException("invalid array/matrix value, should be a heap reference")
|
||||
throw VmExecutionException("invalid arrayspec/matrix value, should be a heap reference")
|
||||
else {
|
||||
val heapId = valueStr.substring(5).toInt()
|
||||
Value(type, heapId)
|
||||
|
@ -218,30 +218,24 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDt(value: Value?, expected: DataType) {
|
||||
if(value==null)
|
||||
throw VmExecutionException("expected value")
|
||||
if(value.type!=expected)
|
||||
throw VmExecutionException("expected $expected value, found ${value.type}")
|
||||
}
|
||||
|
||||
private fun checkDt(value: Value?, expected: Set<DataType>) {
|
||||
private fun checkDt(value: Value?, vararg expected: DataType) {
|
||||
if(value==null)
|
||||
throw VmExecutionException("expected value")
|
||||
if(value.type !in expected)
|
||||
throw VmExecutionException("incompatible type found ${value.type}")
|
||||
throw VmExecutionException("incompatible type ${value.type}")
|
||||
}
|
||||
|
||||
|
||||
private fun dispatch(ins: Instruction) : Instruction {
|
||||
traceOutput?.println("\n$ins")
|
||||
when (ins.opcode) {
|
||||
Opcode.NOP -> {}
|
||||
Opcode.PUSH_BYTE -> {
|
||||
checkDt(ins.arg, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(ins.arg, DataType.UBYTE, DataType.BYTE)
|
||||
evalstack.push(ins.arg)
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
checkDt(ins.arg, setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes)
|
||||
checkDt(ins.arg, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray())
|
||||
evalstack.push(ins.arg)
|
||||
}
|
||||
Opcode.PUSH_FLOAT -> {
|
||||
@ -280,29 +274,23 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.FLOAT)
|
||||
}
|
||||
Opcode.POP_MEM_UB -> {
|
||||
Opcode.POP_MEM_BYTE -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UBYTE)
|
||||
checkDt(value, DataType.BYTE, DataType.UBYTE)
|
||||
val address = ins.arg!!.integerValue()
|
||||
if(value.type==DataType.BYTE)
|
||||
mem.setSByte(address, value.integerValue().toShort())
|
||||
else
|
||||
mem.setUByte(address, value.integerValue().toShort())
|
||||
}
|
||||
Opcode.POP_MEM_B -> {
|
||||
Opcode.POP_MEM_WORD -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.BYTE)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setSByte(address, value.integerValue().toShort())
|
||||
}
|
||||
Opcode.POP_MEM_UW -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UWORD)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setUWord(address, value.integerValue())
|
||||
}
|
||||
Opcode.POP_MEM_W -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.WORD)
|
||||
checkDt(value, DataType.WORD, DataType.UWORD)
|
||||
val address = ins.arg!!.integerValue()
|
||||
if(value.type==DataType.WORD)
|
||||
mem.setSWord(address, value.integerValue())
|
||||
else
|
||||
mem.setUWord(address, value.integerValue())
|
||||
}
|
||||
Opcode.POP_MEM_FLOAT -> {
|
||||
val value = evalstack.pop()
|
||||
@ -765,12 +753,12 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.PUSH_VAR_BYTE -> {
|
||||
val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE)
|
||||
evalstack.push(value)
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD -> {
|
||||
val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(value, setOf(DataType.UWORD, DataType.WORD, DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.MATRIX_UB))
|
||||
checkDt(value, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray())
|
||||
evalstack.push(value)
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT -> {
|
||||
@ -780,62 +768,22 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.POP_VAR_BYTE -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE)
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(variable, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(variable, DataType.UBYTE, DataType.BYTE)
|
||||
if(value.type!=variable.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel!!] = value
|
||||
}
|
||||
Opcode.POP_VAR_WORD -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(value, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(variable, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(variable, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)
|
||||
if(value.type!=variable.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel!!] = value
|
||||
}
|
||||
Opcode.COPY_VAR_BYTE -> {
|
||||
val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}")
|
||||
checkDt(source, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(dest, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
if(dest.type!=source.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel2!!] = source
|
||||
}
|
||||
Opcode.COPY_VAR_WORD -> {
|
||||
val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}")
|
||||
checkDt(source, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(dest, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
if(dest.type!=source.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel2!!] = source
|
||||
}
|
||||
Opcode.COPY_VAR_FLOAT -> {
|
||||
val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}")
|
||||
checkDt(source, DataType.FLOAT)
|
||||
checkDt(dest, DataType.FLOAT)
|
||||
variables[ins.callLabel2!!] = source
|
||||
}
|
||||
Opcode.COPY_MEM_BYTE -> {
|
||||
val sourceAddr = ins.arg!!.integerValue()
|
||||
val destAddr = ins.arg2!!.integerValue()
|
||||
mem.setUByte(destAddr, mem.getUByte(sourceAddr))
|
||||
}
|
||||
Opcode.COPY_MEM_WORD -> {
|
||||
val sourceAddr = ins.arg!!.integerValue()
|
||||
val destAddr = ins.arg2!!.integerValue()
|
||||
mem.setUWord(destAddr, mem.getUWord(sourceAddr))
|
||||
}
|
||||
Opcode.COPY_MEM_FLOAT -> {
|
||||
val sourceAddr = ins.arg!!.integerValue()
|
||||
val destAddr = ins.arg2!!.integerValue()
|
||||
mem.setFloat(destAddr, mem.getFloat(sourceAddr))
|
||||
}
|
||||
Opcode.POP_VAR_FLOAT -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.FLOAT)
|
||||
@ -1229,13 +1177,13 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// assume the variable is a pointer (address) and get the ubyte value from that memory location
|
||||
evalstack.push(Value(DataType.UBYTE, mem.getUByte(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed byte element from the array
|
||||
// get indexed byte element from the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
when(array.type) {
|
||||
DataType.ARRAY_UB, DataType.MATRIX_UB -> evalstack.push(Value(DataType.UBYTE, array.array!![index]))
|
||||
DataType.ARRAY_B, DataType.MATRIX_B -> evalstack.push(Value(DataType.BYTE, array.array!![index]))
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> evalstack.push(Value(DataType.UBYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0]))
|
||||
else -> throw VmExecutionException("not a proper array/matrix/string variable with byte elements")
|
||||
else -> throw VmExecutionException("not a proper arrayspec/matrix/string variable with byte elements")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1247,12 +1195,12 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// assume the variable is a pointer (address) and get the word value from that memory location
|
||||
evalstack.push(Value(DataType.UWORD, mem.getUWord(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed word element from the array
|
||||
// get indexed word element from the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
when(array.type){
|
||||
DataType.ARRAY_UW -> evalstack.push(Value(DataType.UWORD, array.array!![index]))
|
||||
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, array.array!![index]))
|
||||
else -> throw VmExecutionException("not a proper array var with word elements")
|
||||
else -> throw VmExecutionException("not a proper arrayspec var with word elements")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1264,10 +1212,10 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// assume the variable is a pointer (address) and get the float value from that memory location
|
||||
evalstack.push(Value(DataType.UWORD, mem.getFloat(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed float element from the array
|
||||
// get indexed float element from the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
if(array.type!=DataType.ARRAY_F)
|
||||
throw VmExecutionException("not a proper array var with float elements")
|
||||
throw VmExecutionException("not a proper arrayspec var with float elements")
|
||||
evalstack.push(Value(DataType.FLOAT, array.doubleArray!![index]))
|
||||
}
|
||||
}
|
||||
@ -1275,13 +1223,13 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// store byte value on the stack in variable[index] (index is on the stack as well)
|
||||
val index = evalstack.pop().integerValue()
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE)
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and write the byte value to that memory location
|
||||
mem.setUByte(variable.integerValue(), value.integerValue().toShort())
|
||||
} else {
|
||||
// set indexed byte element in the array
|
||||
// set indexed byte element in the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
when(array.type) {
|
||||
DataType.ARRAY_UB, DataType.MATRIX_UB -> array.array!![index] = value.integerValue()
|
||||
@ -1294,7 +1242,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
chars[index] = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0]
|
||||
heap.update(variable.heapId, chars.joinToString(""))
|
||||
}
|
||||
else -> throw VmExecutionException("not a proper array/matrix/string var with byte elements")
|
||||
else -> throw VmExecutionException("not a proper arrayspec/matrix/string var with byte elements")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1302,18 +1250,18 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// store word value on the stack in variable[index] (index is on the stack as well)
|
||||
val index = evalstack.pop().integerValue()
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UWORD, DataType.WORD))
|
||||
checkDt(value, DataType.UWORD, DataType.WORD)
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and write the word value to that memory location
|
||||
mem.setUWord(variable.integerValue(), value.integerValue())
|
||||
} else {
|
||||
// set indexed word element in the array
|
||||
// set indexed word element in the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
when(array.type) {
|
||||
DataType.ARRAY_UW -> array.array!![index] = value.integerValue()
|
||||
DataType.ARRAY_W -> array.array!![index] = value.integerValue()
|
||||
else -> throw VmExecutionException("not a proper array var with word elements")
|
||||
else -> throw VmExecutionException("not a proper arrayspec var with word elements")
|
||||
}
|
||||
|
||||
}
|
||||
@ -1328,10 +1276,10 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// assume the variable is a pointer (address) and write the float value to that memory location
|
||||
mem.setFloat(variable.integerValue(), value.numericValue().toDouble())
|
||||
} else {
|
||||
// set indexed float element in the array
|
||||
// set indexed float element in the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
if(array.type!=DataType.ARRAY_F)
|
||||
throw VmExecutionException("not a proper array var with float elements")
|
||||
throw VmExecutionException("not a proper arrayspec var with float elements")
|
||||
array.doubleArray!![index] = value.numericValue().toDouble()
|
||||
}
|
||||
}
|
||||
@ -1570,7 +1518,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Syscall.FUNC_WRD -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE, DataType.UWORD)
|
||||
when(value.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> evalstack.push(Value(DataType.WORD, value.integerValue()))
|
||||
DataType.UWORD -> {
|
||||
@ -1587,7 +1535,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Syscall.FUNC_UWRD -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE, DataType.WORD))
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE, DataType.WORD)
|
||||
when(value.type) {
|
||||
DataType.UBYTE -> evalstack.push(Value(DataType.UWORD, value.integerValue()))
|
||||
DataType.UWORD -> evalstack.push(value)
|
||||
|
@ -222,10 +222,10 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, -23456)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, -55)),
|
||||
Instruction(Opcode.POP_MEM_B, Value(DataType.UWORD, 0x2000)),
|
||||
Instruction(Opcode.POP_MEM_UB, Value(DataType.UWORD, 0x2001)),
|
||||
Instruction(Opcode.POP_MEM_W, Value(DataType.UWORD, 0x3000)),
|
||||
Instruction(Opcode.POP_MEM_UW, Value(DataType.UWORD, 0x3002)),
|
||||
Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2000)),
|
||||
Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2001)),
|
||||
Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3000)),
|
||||
Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3002)),
|
||||
Instruction(Opcode.POP_MEM_FLOAT, Value(DataType.UWORD, 0x4000)))
|
||||
vm.load(makeProg(ins), null)
|
||||
assertEquals(0, vm.mem.getUWord(0x2000))
|
||||
@ -281,51 +281,6 @@ class TestStackVmOpcodes {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCopyVar() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.COPY_VAR_BYTE, null, null, "bvar1", "bvar2"),
|
||||
Instruction(Opcode.COPY_VAR_WORD, null, null, "wvar1", "wvar2"),
|
||||
Instruction(Opcode.COPY_VAR_FLOAT, null, null, "fvar1", "fvar2"),
|
||||
Instruction(Opcode.COPY_VAR_WORD, null, null, "wvar1", "bvar2"))
|
||||
val vars = mapOf(
|
||||
"bvar1" to Value(DataType.UBYTE, 1),
|
||||
"bvar2" to Value(DataType.UBYTE, 2),
|
||||
"wvar1" to Value(DataType.UWORD, 1111),
|
||||
"wvar2" to Value(DataType.UWORD, 2222),
|
||||
"fvar1" to Value(DataType.FLOAT, 11.11),
|
||||
"fvar2" to Value(DataType.FLOAT, 22.22)
|
||||
)
|
||||
vm.load(makeProg(ins, vars), null)
|
||||
assertEquals(12, vm.variables.size)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.UBYTE, 1), vm.variables["bvar2"])
|
||||
assertEquals(Value(DataType.UWORD, 1111), vm.variables["wvar2"])
|
||||
assertEquals(Value(DataType.FLOAT, 11.11), vm.variables["fvar2"])
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCopyMem() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.COPY_MEM_BYTE, Value(DataType.UWORD, 0xc000), Value(DataType.UWORD, 0xc001)),
|
||||
Instruction(Opcode.COPY_MEM_WORD, Value(DataType.UWORD, 0xc100), Value(DataType.UWORD, 0xc102)),
|
||||
Instruction(Opcode.COPY_MEM_FLOAT, Value(DataType.UWORD, 0xc200), Value(DataType.UWORD, 0xc300)))
|
||||
val mem=mapOf(0xc000 to listOf(Value(DataType.UBYTE, 0x45)),
|
||||
0xc100 to listOf(Value(DataType.UWORD, 0xc2ca)),
|
||||
0xc200 to listOf(Value(DataType.FLOAT, 42.25)))
|
||||
vm.load(makeProg(ins, mem=mem), null)
|
||||
assertEquals(0, vm.mem.getUByte(0xc001))
|
||||
assertEquals(0, vm.mem.getUWord(0xc102))
|
||||
assertEquals(0.0, vm.mem.getFloat(0xc300))
|
||||
vm.step(3)
|
||||
assertEquals(0x45, vm.mem.getUByte(0xc001))
|
||||
assertEquals(0xc2ca, vm.mem.getUWord(0xc102))
|
||||
assertEquals(42.25, vm.mem.getFloat(0xc300))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAdd() {
|
||||
testBinaryOperator(Value(DataType.UBYTE, 140), Opcode.ADD_UB, Value(DataType.UBYTE, 222), Value(DataType.UBYTE, 106))
|
||||
|
@ -200,17 +200,19 @@ Arrays can be made of bytes, words and floats. Matrixes can oly be made of bytes
|
||||
byte[4] array = [1, 2, 3, 4] ; initialize the array
|
||||
byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...]
|
||||
byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
|
||||
byte[2,3] matrix = 1 ; a matrix of 2*3=6 bytes all with value 1
|
||||
byte[2,3] matrix = [1,2,3,4,5,6] ; a 2*3 matrix with value |(1,2) (3,4) (5,6)|
|
||||
ubyte[2,3] matrix = 255 ; a matrix of 2*3=6 unsigned bytes all with value 255
|
||||
|
||||
value = array[3] ; the fourth value in the array (index is 0-based)
|
||||
value = matrix[4,2] ; the byte at the 5th column and 3rd row in the matrix
|
||||
char = string[4] ; the fifth character (=byte) in the string
|
||||
|
||||
.. note::
|
||||
Right now, the array and matrix size should be small enough to be indexable by a single byte index.
|
||||
This means byte arrays and matrixes should be <= 256 elements, word arrays <= 128 elements, and float
|
||||
arrays <= 51 elements. This limit may be lifted in a future version.
|
||||
Right now, the array should be small enough to be indexable by a single byte index.
|
||||
This means byte arrays should be <= 256 elements, word arrays <= 128 elements, and float
|
||||
arrays <= 51 elements. This limit may or may not be lifted in a future version.
|
||||
Matrixes can be indexed in each dimension only by a byte as well, this also means
|
||||
their maximum size is 65536 elements (bytes).
|
||||
|
||||
|
||||
Note that the various keywords for the data type and variable type (``byte``, ``word``, ``const``, etc.)
|
||||
|
@ -34,9 +34,15 @@ ror2_word
|
||||
ub2float
|
||||
rts
|
||||
|
||||
b2float
|
||||
rts
|
||||
|
||||
uw2float
|
||||
rts
|
||||
|
||||
w2float
|
||||
rts
|
||||
|
||||
push_float
|
||||
rts
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user