assignment to array-indexed

This commit is contained in:
Irmen de Jong 2018-10-02 03:07:46 +02:00
parent 38e7d48492
commit af0d52b5c2
10 changed files with 633 additions and 540 deletions

View File

@ -117,6 +117,7 @@ assign_target:
register
| identifier
| scoped_identifier
| arrayindexed
;
postincrdecr : assign_target operator = ('++' | '--') ;

View File

@ -16,81 +16,61 @@
const word width = 320
const word height = 200
float x1 = -1.0
float y1 = 1.0
float[6] xcoor = [-1.0, 1.0, 1.0, 0.5, 0.2, -1.0]
float[6] ycoor = [1.0, 1.0, -1.0, -0.3, -0.6, -1.0]
float x2 = 1.0
float y2 = 1.0
float x3 = 1.0
float y3 = -1.0
float x4 = -1.0
float y4 = -1.0
float rx1
float rx2
float rx3
float rx4
float ry1
float ry2
float ry3
float ry4
float[len(xcoor)] rotatedx
float[len(ycoor)] rotatedy
sub start() {
float t
_vm_gfx_clearscr(0)
byte i
while(1) {
if irq.time_changed {
irq.time_changed = 0
_vm_gfx_clearscr(0)
_vm_gfx_text(130, 80, 5, "Spin !!!")
t = flt(irq.global_time) / 60.0
rotate_all(t)
plot_pixels()
_vm_gfx_text(120, 40, 5, "Spin to Win !!!")
for i in 0 to width//10 {
_vm_gfx_line(i*2+100, 100, i*10, 199, 6)
}
rotate_points(flt(irq.global_time) / 30.0)
draw_lines()
}
}
}
sub rotate_all(t: float) {
rx1 = x1 * cos(t) - y1 * sin(t)
ry1 = x1 * sin(t) + y1 * cos(t)
sub rotate_points(t: float) {
rx2 = x2 * cos(t) - y2 * sin(t)
ry2 = x2 * sin(t) + y2 * cos(t)
; rotate around origin (0,0) and zoom a bit
byte i
float zoom
zoom = (0.6 + sin(t*1.4)/2.2)
rx3 = x3 * cos(t) - y3 * sin(t)
ry3 = x3 * sin(t) + y3 * cos(t)
rx4 = x4 * cos(t) - y4 * sin(t)
ry4 = x4 * sin(t) + y4 * cos(t)
for i in 0 to len(xcoor)-1 {
rotatedx[i] = xcoor[i] * cos(t) - ycoor[i] * sin(t)
rotatedy[i] = xcoor[i] * sin(t) + ycoor[i] * cos(t)
rotatedx[i] *= zoom
rotatedy[i] *= zoom
}
}
sub plot_pixels() {
word sx1
word sx2
word sx3
word sx4
word sy1
word sy2
word sy3
word sy4
sub draw_lines() {
byte i
sx1 = floor(rx1 * height/3 + width/2)
sx2 = floor(rx2 * height/3 + width/2)
sx3 = floor(rx3 * height/3 + width/2)
sx4 = floor(rx4 * height/3 + width/2)
sy1 = floor(ry1 * height/3 + height/2)
sy2 = floor(ry2 * height/3 + height/2)
sy3 = floor(ry3 * height/3 + height/2)
sy4 = floor(ry4 * height/3 + height/2)
sub toscreenx(x: float) -> word {
return floor(x * height/3 + width /2)
}
_vm_gfx_line(sx1, sy1, sx2, sy2, 1)
_vm_gfx_line(sx2, sy2, sx3, sy3, 7)
_vm_gfx_line(sx3, sy3, sx4, sy4, 10)
_vm_gfx_line(sx4, sy4, sx1, sy1, 14)
sub toscreeny(y: float) -> word {
return floor(y * height/3 + height /2)
}
for i in 0 to len(xcoor)-2 {
_vm_gfx_line(toscreenx(rotatedx[i]), toscreeny(rotatedy[i]), toscreenx(rotatedx[i+1]), toscreeny(rotatedy[i+1]), i+7)
}
_vm_gfx_line(toscreenx(rotatedx[len(xcoor)-1]), toscreeny(rotatedy[len(xcoor)-1]), toscreenx(rotatedx[0]), toscreeny(rotatedy[0]), 14)
}
}

View File

@ -27,30 +27,36 @@ sub start() {
byte i
word w
for i in 0 to 2 {
_vm_write_num(farray5[i])
_vm_write_char('\n')
}
;warray3[1] = warray3[1] + 1
warray3[1] += 1
;warray3[1] ++
for w in [1,2,3777] { ;@todo loop over array literal
_vm_write_num(w)
_vm_write_char('\n')
}
for i in barray3 { ; @todo loop over symbol
_vm_write_num(i)
_vm_write_char('\n')
}
for i in "hello" { ; @todo loop over string
_vm_write_num(i)
_vm_write_char('\n')
}
; for i in 0 to 2 {
; _vm_write_num(farray5[i])
; _vm_write_char('\n')
; }
for w in "hello" { ; @todo loop over string
_vm_write_num(w)
_vm_write_char('\n')
}
; for w in [1,2,3777] { ;@todo loop over array literal
; _vm_write_num(w)
; _vm_write_char('\n')
; }
;
; for i in barray3 { ; @todo loop over symbol
; _vm_write_num(i)
; _vm_write_char('\n')
; }
;
; for i in "hello" { ; @todo loop over string
; _vm_write_num(i)
; _vm_write_char('\n')
; }
;
; for w in "hello" { ; @todo loop over string
; _vm_write_num(w)
; _vm_write_char('\n')
; }
return

View File

@ -226,6 +226,12 @@ interface IAstProcessor {
arrayIndexedExpression.array.process(this)
return arrayIndexedExpression
}
fun process(assignTarget: AssignTarget): AssignTarget {
assignTarget.arrayindexed?.process(this)
assignTarget.identifier?.process(this)
return assignTarget
}
}
@ -674,25 +680,39 @@ class Assignment(var target: AssignTarget, val aug_op : String?, var value: IExp
}
}
data class AssignTarget(val register: Register?, val identifier: IdentifierReference?, override val position: Position) : Node {
data class AssignTarget(val register: Register?,
val identifier: IdentifierReference?,
val arrayindexed: ArrayIndexedExpression?,
override val position: Position) : Node {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
identifier?.linkParents(this)
arrayindexed?.linkParents(this)
}
fun process(processor: IAstProcessor) = this
fun process(processor: IAstProcessor) = processor.process(this)
fun determineDatatype(namespace: INameScope, stmt: IStatement): DataType {
fun determineDatatype(namespace: INameScope, heap: HeapValues, stmt: IStatement): DataType {
if(register!=null)
return when(register){
Register.A, Register.X, Register.Y -> DataType.BYTE
Register.AX, Register.AY, Register.XY -> DataType.WORD
}
val symbol = namespace.lookup(identifier!!.nameInSource, stmt) ?: throw FatalAstException("symbol lookup failed: ${identifier.nameInSource}")
if(symbol is VarDecl) return symbol.datatype
if(identifier!=null) {
val symbol = namespace.lookup(identifier.nameInSource, stmt)
?: throw FatalAstException("symbol lookup failed: ${identifier.nameInSource}")
if (symbol is VarDecl) return symbol.datatype
}
if(arrayindexed!=null) {
val dt = arrayindexed.resultingDatatype(namespace, heap)
if(dt!=null)
return dt
}
throw FatalAstException("cannot determine datatype of assignment target $this")
}
}
@ -1685,10 +1705,12 @@ private fun prog8Parser.Sub_paramsContext.toAst(): List<SubroutineParameter> =
private fun prog8Parser.Assign_targetContext.toAst() : AssignTarget {
val register = register()?.toAst()
val identifier = identifier()
return if(identifier!=null)
AssignTarget(register, identifier.toAst(), toPosition())
else
AssignTarget(register, scoped_identifier()?.toAst(), toPosition())
return when {
register!=null -> AssignTarget(register, null, null, toPosition())
identifier!=null -> AssignTarget(null, identifier.toAst(), null, toPosition())
arrayindexed()!=null -> AssignTarget(null, null, arrayindexed().toAst(), toPosition())
else -> AssignTarget(null, scoped_identifier()?.toAst(), null, toPosition())
}
}
@ -1810,7 +1832,7 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression {
throw FatalAstException(text)
}
private fun prog8Parser.ArrayindexedContext.toAst(): IExpression {
private fun prog8Parser.ArrayindexedContext.toAst(): ArrayIndexedExpression {
return ArrayIndexedExpression(identifier()?.toAst() ?: scoped_identifier()?.toAst(),
register()?.toAst(),
arrayspec().toAst(),

View File

@ -251,6 +251,8 @@ class AstChecker(private val namespace: INameScope,
* Also check data type compatibility
*/
override fun process(assignment: Assignment): IStatement {
// todo deal with target.arrayindexed
if(assignment.target.identifier!=null) {
val targetName = assignment.target.identifier!!.nameInSource
val targetSymbol = namespace.lookup(targetName, assignment)
@ -276,8 +278,13 @@ class AstChecker(private val namespace: INameScope,
val target: IExpression =
if(assignment.target.register!=null)
RegisterExpr(assignment.target.register!!, assignment.target.position)
else
else if(assignment.target.identifier!=null)
assignment.target.identifier!!
else if(assignment.target.arrayindexed!=null) {
// todo deal with target.arrayindexed
assignment.target.arrayindexed!!
} else throw FatalAstException("strange assignment")
val expression = BinaryExpression(target, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
expression.linkParents(assignment.parent)
val assignment2 = Assignment(assignment.target, null, expression, assignment.position)
@ -285,7 +292,7 @@ class AstChecker(private val namespace: INameScope,
return process(assignment2)
}
val targetDatatype = assignment.target.determineDatatype(namespace, assignment)
val targetDatatype = assignment.target.determineDatatype(namespace, heap, assignment)
val constVal = assignment.value.constValue(namespace, heap)
if(constVal!=null) {
checkValueTypeAndRange(targetDatatype, null, constVal, heap)
@ -550,7 +557,7 @@ class AstChecker(private val namespace: INameScope,
}
override fun process(postIncrDecr: PostIncrDecr): IStatement {
if(postIncrDecr.target.register==null) {
if(postIncrDecr.target.identifier!=null) {
val targetName = postIncrDecr.target.identifier!!.nameInSource
val target = namespace.lookup(targetName, postIncrDecr)
if(target==null) {
@ -562,6 +569,8 @@ class AstChecker(private val namespace: INameScope,
checkResult.add(SyntaxError("can only increment or decrement a byte/float/word variable", postIncrDecr.position))
}
}
} else if(postIncrDecr.target.arrayindexed!=null) {
// todo deal with target.arrayindexed
}
return super.process(postIncrDecr)
}

View File

@ -444,7 +444,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
}
}
is IdentifierReference -> translate(expr)
is ArrayIndexedExpression -> translate(expr)
is ArrayIndexedExpression -> translate(expr, false)
is RangeExpr -> {
TODO("TRANSLATE range $expr")
}
@ -592,7 +592,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stackvmProg.instr(opcode)
}
private fun translate(arrayindexed: ArrayIndexedExpression) {
private fun translate(arrayindexed: ArrayIndexedExpression, write: Boolean) {
val variable = arrayindexed.identifier?.targetStatement(namespace) as? VarDecl
val variableName =
if(arrayindexed.register!=null) {
@ -615,7 +615,11 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stackvmProg.instr(Opcode.MUL)
stackvmProg.instr(Opcode.ADD)
}
stackvmProg.instr(Opcode.PUSH_INDEXED_VAR, callLabel = variableName)
if(write)
stackvmProg.instr(Opcode.WRITE_INDEXED_VAR, callLabel = variableName)
else
stackvmProg.instr(Opcode.READ_INDEXED_VAR, callLabel = variableName)
}
@ -652,17 +656,29 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
private fun translate(stmt: PostIncrDecr) {
stackvmProg.line(stmt.position)
if(stmt.target.register!=null) {
when(stmt.operator) {
when {
stmt.target.register!=null -> when(stmt.operator) {
"++" -> stackvmProg.instr(Opcode.INC_VAR, callLabel = stmt.target.register.toString())
"--" -> stackvmProg.instr(Opcode.DEC_VAR, callLabel = stmt.target.register.toString())
}
} else {
val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl
when(stmt.operator) {
"++" -> stackvmProg.instr(Opcode.INC_VAR, callLabel = targetStatement.scopedname)
"--" -> stackvmProg.instr(Opcode.DEC_VAR, callLabel = targetStatement.scopedname)
stmt.target.identifier!=null -> {
val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl
when(stmt.operator) {
"++" -> stackvmProg.instr(Opcode.INC_VAR, callLabel = targetStatement.scopedname)
"--" -> stackvmProg.instr(Opcode.DEC_VAR, callLabel = targetStatement.scopedname)
}
}
stmt.target.arrayindexed!=null -> {
// todo: generate more efficient bytecode for this?
translate(stmt.target.arrayindexed!!, false)
stackvmProg.instr(Opcode.PUSH, Value(stmt.target.arrayindexed!!.resultingDatatype(namespace, heap)!!, 1))
when(stmt.operator) {
"++" -> stackvmProg.instr(Opcode.ADD)
"--" -> stackvmProg.instr(Opcode.SUB)
}
translate(stmt.target.arrayindexed!!, true)
}
else -> throw CompilerException("very strange postincrdecr")
}
}
@ -670,7 +686,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stackvmProg.line(stmt.position)
translate(stmt.value)
val valueDt = stmt.value.resultingDatatype(namespace, heap)
val targetDt = stmt.target.determineDatatype(namespace, stmt)
val targetDt = stmt.target.determineDatatype(namespace, heap, stmt)
if(valueDt!=targetDt) {
// convert value to target datatype if possible
when(targetDt) {
@ -696,27 +712,32 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
if(stmt.aug_op!=null) {
// augmented assignment
if(stmt.target.identifier!=null) {
val target = stmt.target.identifier!!.targetStatement(namespace)!!
when(target) {
is VarDecl -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = target.scopedname)
else -> throw CompilerException("invalid assignment target type ${target::class}")
when {
stmt.target.identifier!=null -> {
val target = stmt.target.identifier!!.targetStatement(namespace)!!
when(target) {
is VarDecl -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = target.scopedname)
else -> throw CompilerException("invalid assignment target type ${target::class}")
}
}
} else if(stmt.target.register!=null) {
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = stmt.target.register.toString())
stmt.target.register!=null -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = stmt.target.register.toString())
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, false)
}
translateAugAssignOperator(stmt.aug_op)
}
// pop the result value back into the assignment target
if(stmt.target.identifier!=null) {
val target = stmt.target.identifier!!.targetStatement(namespace)!!
when(target) {
is VarDecl -> stackvmProg.instr(Opcode.POP_VAR, callLabel = target.scopedname)
else -> throw CompilerException("invalid assignment target type ${target::class}")
when {
stmt.target.identifier!=null -> {
val target = stmt.target.identifier!!.targetStatement(namespace)!!
when(target) {
is VarDecl -> stackvmProg.instr(Opcode.POP_VAR, callLabel = target.scopedname)
else -> throw CompilerException("invalid assignment target type ${target::class}")
}
}
} else if(stmt.target.register!=null) {
stackvmProg.instr(Opcode.POP_VAR, callLabel = stmt.target.register.toString())
stmt.target.register!=null -> stackvmProg.instr(Opcode.POP_VAR, callLabel = stmt.target.register.toString())
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, true) // write value to it
}
}
@ -915,9 +936,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
*/
fun makeAssignmentTarget(): AssignTarget {
return if(varname!=null)
AssignTarget(null, IdentifierReference(varname, range.position), range.position)
AssignTarget(null, IdentifierReference(varname, range.position), null, range.position)
else
AssignTarget(register, null, range.position)
AssignTarget(register, null, null, range.position)
}
val startAssignment = Assignment(makeAssignmentTarget(), null, range.from, range.position)
@ -970,6 +991,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} else {
null
}
// todo deal with target.arrayindexed?
when (literalStepValue) {
1 -> {

View File

@ -67,7 +67,7 @@ class StatementOptimizer(private val globalNamespace: INameScope, private val he
if(range.size()==1) {
// for loop over a (constant) range of just a single value-- optimize the loop away
// loopvar/reg = range value , follow by block
val assignment = Assignment(AssignTarget(forLoop.loopRegister, forLoop.loopVar, forLoop.position), null, range.from, forLoop.position)
val assignment = Assignment(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, forLoop.position), null, range.from, forLoop.position)
forLoop.body.add(0, assignment)
return AnonymousStatementList(forLoop.parent, forLoop.body, forLoop.position)
}

File diff suppressed because it is too large Load Diff

View File

@ -107,7 +107,7 @@ class Program (val name: String,
Opcode.INC_VAR, Opcode.DEC_VAR,
Opcode.SHR_VAR, Opcode.SHL_VAR, Opcode.ROL_VAR, Opcode.ROR_VAR,
Opcode.ROL2_VAR, Opcode.ROR2_VAR, Opcode.POP_VAR, Opcode.PUSH_VAR,
Opcode.PUSH_INDEXED_VAR -> {
Opcode.READ_INDEXED_VAR, Opcode.WRITE_INDEXED_VAR -> {
val withoutQuotes =
if(args!!.startsWith('"') && args.endsWith('"'))
args.substring(1, args.length-1) else args

View File

@ -94,7 +94,8 @@ enum class Opcode {
NOTEQUAL,
// array access
PUSH_INDEXED_VAR,
READ_INDEXED_VAR,
WRITE_INDEXED_VAR,
// branching
JUMP,
@ -911,7 +912,8 @@ class StackVm(private var traceOutputFile: String?) {
Opcode.LINE -> {
sourceLine = ins.callLabel!!
}
Opcode.PUSH_INDEXED_VAR -> {
Opcode.READ_INDEXED_VAR -> {
// put the value of variable[index] onto the stack
val index = evalstack.pop().integerValue()
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
if(variable.type==DataType.WORD) {
@ -930,7 +932,46 @@ class StackVm(private var traceOutputFile: String?) {
DataType.STR,
DataType.STR_P,
DataType.STR_S,
DataType.STR_PS -> throw VmExecutionException("not a proper array/matrix var")
DataType.STR_PS -> throw VmExecutionException("not a proper array/matrix var") // todo: allow strings
}
}
}
Opcode.WRITE_INDEXED_VAR -> {
// store value on the stack in variable[index] (index is on the stack as well)
val index = evalstack.pop().integerValue()
val value = evalstack.pop()
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
if(variable.type==DataType.WORD) {
// assume the variable is a pointer (address) and write the byte value to that memory location
if(value.type!=DataType.BYTE)
throw VmExecutionException("writing a non-byte value to memory location")
mem.setByte(variable.integerValue(), value.integerValue().toShort())
} else {
// set indexed element in the array
val array = heap.get(variable.heapId)
when(array.type) {
DataType.ARRAY, DataType.MATRIX -> {
if(value.type!=DataType.BYTE)
throw VmExecutionException("writing a non-byte value into byte array/matrix")
array.array!![index] = value.integerValue()
}
DataType.ARRAY_W -> {
if(value.type!=DataType.WORD)
throw VmExecutionException("writing a non-word value into word array")
array.array!![index] = value.integerValue()
}
DataType.ARRAY_F -> {
if(value.type!=DataType.FLOAT)
throw VmExecutionException("writing a non-float value into float array")
array.doubleArray!![index] = value.numericValue().toDouble()
}
DataType.BYTE,
DataType.WORD,
DataType.FLOAT,
DataType.STR,
DataType.STR_P,
DataType.STR_S,
DataType.STR_PS -> throw VmExecutionException("not a proper array/matrix var") // todo: allow strings
}
}
}