mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 01:29:28 +00:00
more complete for loops, various comma separated lists can now be split over multiple lines
This commit is contained in:
parent
af0d52b5c2
commit
18c6165325
@ -163,7 +163,7 @@ functioncall_stmt :
|
||||
|
||||
|
||||
expression_list :
|
||||
expression (',' expression)*
|
||||
expression (',' EOL? expression)*
|
||||
;
|
||||
|
||||
returnstmt : 'return' expression_list? ;
|
||||
@ -186,7 +186,7 @@ wordsuffix : '.w' ;
|
||||
|
||||
booleanliteral : 'true' | 'false' ;
|
||||
|
||||
arrayliteral : '[' expression (',' expression)* ']' ;
|
||||
arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ;
|
||||
|
||||
stringliteral : STRING ;
|
||||
|
||||
@ -219,11 +219,11 @@ statement_block :
|
||||
;
|
||||
|
||||
|
||||
sub_params : sub_param (',' sub_param)* ;
|
||||
sub_params : sub_param (',' EOL? sub_param)* ;
|
||||
|
||||
sub_param : identifier ':' datatype;
|
||||
|
||||
sub_returns : datatype (',' datatype)* ;
|
||||
sub_returns : datatype (',' EOL? datatype)* ;
|
||||
|
||||
asmsubroutine :
|
||||
'asmsub' identifier '(' asmsub_params? ')'
|
||||
@ -232,13 +232,13 @@ asmsubroutine :
|
||||
|
||||
asmsub_address : '=' address=integerliteral ;
|
||||
|
||||
asmsub_params : asmsub_param (',' asmsub_param)* ;
|
||||
asmsub_params : asmsub_param (',' EOL? asmsub_param)* ;
|
||||
|
||||
asmsub_param : identifier ':' datatype '@' (register | statusregister);
|
||||
|
||||
clobber : register (',' register)* ;
|
||||
|
||||
asmsub_returns : asmsub_return (',' asmsub_return)* ;
|
||||
asmsub_returns : asmsub_return (',' EOL? asmsub_return)* ;
|
||||
|
||||
asmsub_return : datatype '@' (register | statusregister) ;
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
const word height = 200
|
||||
|
||||
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[6] ycoor = [0.2, 1.0, -1.0, -0.3, -0.6, -1.0]
|
||||
|
||||
float[len(xcoor)] rotatedx
|
||||
float[len(ycoor)] rotatedy
|
||||
@ -69,8 +69,10 @@
|
||||
}
|
||||
|
||||
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[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)
|
||||
_vm_gfx_line(toscreenx(rotatedx[len(xcoor)-1]), toscreeny(rotatedy[len(xcoor)-1]),
|
||||
toscreenx(rotatedx[0]), toscreeny(rotatedy[0]), 14)
|
||||
}
|
||||
}
|
@ -2,24 +2,32 @@
|
||||
|
||||
~ main {
|
||||
|
||||
const word width = 320
|
||||
const word height = 200
|
||||
|
||||
sub start() {
|
||||
|
||||
_vm_gfx_clearscr(0)
|
||||
_vm_gfx_text(5, 5, 7, "Swirl !!!")
|
||||
|
||||
const word width = 320
|
||||
const word height = 200
|
||||
float x
|
||||
float y
|
||||
float t
|
||||
byte color
|
||||
|
||||
while(1) {
|
||||
x = ((sin(t*1.01) +cos(t*1.1234)) * width/4.1) + width/2
|
||||
y = ((cos(t)+sin(t*0.03456)) * height/4.1) + height/2
|
||||
_vm_gfx_pixel(floor(x),floor(y), color//16)
|
||||
x = sin(t*1.01) + cos(t*1.1234)
|
||||
y = cos(t) + sin(t*0.03456)
|
||||
_vm_gfx_pixel(screenx(x), screeny(y), color//16)
|
||||
t += 0.01
|
||||
color++
|
||||
}
|
||||
}
|
||||
|
||||
sub screenx(x: float) -> word {
|
||||
return floor(x * width/4.1) + width // 2
|
||||
}
|
||||
sub screeny(y: float) -> word {
|
||||
return floor(y * height/4.1) + height // 2
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ sub start() {
|
||||
|
||||
word[10] warray1
|
||||
word[10] warray2 = 112233
|
||||
word[10] warray3 = [1,2,3,4,5,6,7,8,9, 65535]
|
||||
word[10] warray3 = [1,2000,3000,4,5,6,7,8,9, 65535]
|
||||
|
||||
byte[4,5] mvar1
|
||||
byte[4,5] mvar2 = 22
|
||||
@ -23,40 +23,31 @@ sub start() {
|
||||
float[3] farray4 = [1,2,35566]
|
||||
float[3] farray5 = [1,2.22334,3.1415]
|
||||
|
||||
str name = "irmen"
|
||||
|
||||
byte i
|
||||
word w
|
||||
|
||||
;warray3[1] = warray3[1] + 1
|
||||
warray3[1] += 1
|
||||
;warray3[1] ++
|
||||
_vm_write_str(name)
|
||||
_vm_write_char('\n')
|
||||
name[2] = '@'
|
||||
_vm_write_str(name)
|
||||
_vm_write_char('\n')
|
||||
|
||||
for i in barray3 {
|
||||
_vm_write_num(i)
|
||||
_vm_write_char('\n')
|
||||
}
|
||||
|
||||
for w in warray3 {
|
||||
_vm_write_num(w)
|
||||
_vm_write_char('\n')
|
||||
}
|
||||
|
||||
; for i in 0 to 2 {
|
||||
; _vm_write_num(farray5[i])
|
||||
; _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')
|
||||
; }
|
||||
for i in name {
|
||||
_vm_write_num(i)
|
||||
_vm_write_char('\n')
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
|
@ -1258,7 +1258,7 @@ class FunctionCall(override var target: IdentifierReference,
|
||||
override fun resultingDatatype(namespace: INameScope, heap: HeapValues): DataType? {
|
||||
val constVal = constValue(namespace, heap,false)
|
||||
if(constVal!=null)
|
||||
return constVal.resultingDatatype(namespace, heap)
|
||||
return constVal.type
|
||||
val stmt = target.targetStatement(namespace) ?: return null
|
||||
when (stmt) {
|
||||
is BuiltinFunctionStatementPlaceholder -> {
|
||||
|
@ -95,6 +95,10 @@ class AstChecker(private val namespace: INameScope,
|
||||
override fun process(forLoop: ForLoop): IStatement {
|
||||
if(forLoop.body.isEmpty())
|
||||
printWarning("for loop body is empty", forLoop.position)
|
||||
|
||||
if(forLoop.iterable is LiteralValue)
|
||||
checkResult.add(SyntaxError("currently not possible to loop over a literal value directly, use a variable instead", forLoop.position)) // todo loop over literals
|
||||
|
||||
if(!forLoop.iterable.isIterable(namespace, heap)) {
|
||||
checkResult.add(ExpressionError("can only loop over an iterable type", forLoop.position))
|
||||
} else {
|
||||
|
@ -821,24 +821,111 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val iterableValue: LiteralValue?
|
||||
if(loop.iterable is LiteralValue) {
|
||||
if (!loop.iterable.isIterable(namespace, heap))
|
||||
throw CompilerException("loop over something that isn't iterable ${loop.iterable}")
|
||||
iterableValue = loop.iterable as LiteralValue
|
||||
} else if(loop.iterable is IdentifierReference) {
|
||||
val idRef = loop.iterable as IdentifierReference
|
||||
iterableValue = ((idRef.targetStatement(namespace) as? VarDecl)?.value as? LiteralValue)
|
||||
if(iterableValue!=null && !iterableValue.isIterable(namespace, heap))
|
||||
throw CompilerException("loop over something that isn't iterable ${loop.iterable}")
|
||||
} else {
|
||||
throw CompilerException("loopvar is something strange ${loop.iterable}")
|
||||
// ok, must be a literalvalue
|
||||
val iterableValue: LiteralValue
|
||||
when {
|
||||
loop.iterable is LiteralValue -> {
|
||||
TODO("loop over literal value (move literal to auto-generated heap variable)")
|
||||
}
|
||||
loop.iterable is IdentifierReference -> {
|
||||
val idRef = loop.iterable as IdentifierReference
|
||||
val vardecl = (idRef.targetStatement(namespace) as VarDecl)
|
||||
iterableValue = vardecl.value as LiteralValue
|
||||
if(!iterableValue.isIterable(namespace, heap))
|
||||
throw CompilerException("loop over something that isn't iterable ${loop.iterable}")
|
||||
}
|
||||
else -> throw CompilerException("loopvar is something strange ${loop.iterable}")
|
||||
}
|
||||
|
||||
TODO("LOOP OVER ITERABLE VALUE (array/matrix/string) $iterableValue")
|
||||
translateForOverIterableVar(loop, loopVarDt, iterableValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateForOverIterableVar(loop: ForLoop, varDt: DataType, iterableValue: LiteralValue) {
|
||||
if(varDt==DataType.BYTE && iterableValue.type !in setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.MATRIX))
|
||||
throw CompilerException("loop variable type doesn't match iterableValue type (byte)")
|
||||
else if(varDt==DataType.WORD && iterableValue.type != DataType.ARRAY_W)
|
||||
throw CompilerException("loop variable type doesn't match iterableValue type (word)")
|
||||
else if(varDt==DataType.FLOAT && iterableValue.type != DataType.ARRAY_F)
|
||||
throw CompilerException("loop variable type doesn't match iterableValue type (float)")
|
||||
val numElements: Int
|
||||
val indexVar: String
|
||||
when(iterableValue.type) {
|
||||
DataType.BYTE,
|
||||
DataType.WORD,
|
||||
DataType.FLOAT -> throw CompilerException("non-iterableValue type")
|
||||
DataType.STR,
|
||||
DataType.STR_P,
|
||||
DataType.STR_S,
|
||||
DataType.STR_PS -> {
|
||||
numElements = iterableValue.strvalue?.length ?: heap.get(iterableValue.heapId!!).str!!.length
|
||||
indexVar = if(numElements>255) "XY" else "X"
|
||||
}
|
||||
DataType.ARRAY,
|
||||
DataType.ARRAY_W,
|
||||
DataType.MATRIX -> {
|
||||
numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).array!!.size
|
||||
indexVar = if(numElements>255) "XY" else "X"
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).doubleArray!!.size
|
||||
indexVar = if(numElements>255) "XY" else "X"
|
||||
}
|
||||
}
|
||||
|
||||
if(indexVar=="X" && loop.loopRegister!=null && loop.loopRegister in setOf(Register.X, Register.AX, Register.XY))
|
||||
throw CompilerException("loopVar cannot use X register because it is needed as internal index")
|
||||
if(indexVar=="XY" && loop.loopRegister!=null && loop.loopRegister in setOf(Register.X, Register.AX, Register.Y, Register.AY, Register.XY))
|
||||
throw CompilerException("loopVar cannot use X and Y registers because they are needed as internal index")
|
||||
|
||||
/**
|
||||
* indexVar = 0
|
||||
* loop:
|
||||
* LV = iterableValue[indexVar]
|
||||
* ..body..
|
||||
* ..break statement: goto break
|
||||
* ..continue statement: goto continue
|
||||
* ..
|
||||
* continue:
|
||||
* IV++
|
||||
* if IV!=numElements goto loop
|
||||
* break:
|
||||
* nop
|
||||
*/
|
||||
val loopLabel = makeLabel("loop")
|
||||
val continueLabel = makeLabel("continue")
|
||||
val breakLabel = makeLabel("break")
|
||||
|
||||
continueStmtLabelStack.push(continueLabel)
|
||||
breakStmtLabelStack.push(breakLabel)
|
||||
|
||||
stackvmProg.instr(Opcode.PUSH, Value(if(numElements<=255) DataType.BYTE else DataType.WORD, 0))
|
||||
stackvmProg.instr(Opcode.POP_VAR, callLabel = indexVar)
|
||||
stackvmProg.label(loopLabel)
|
||||
val assignTarget = if(loop.loopRegister!=null)
|
||||
AssignTarget(loop.loopRegister, null, null, loop.position)
|
||||
else
|
||||
AssignTarget(null, loop.loopVar, null, loop.position)
|
||||
val arrayspec = ArraySpec(RegisterExpr(Register.valueOf(indexVar), loop.position), null, loop.position)
|
||||
val assignLv = Assignment(assignTarget, null, ArrayIndexedExpression(loop.iterable as IdentifierReference, null, arrayspec, loop.position), loop.position)
|
||||
assignLv.linkParents(loop.parent)
|
||||
translate(assignLv)
|
||||
translate(loop.body)
|
||||
stackvmProg.label(continueLabel)
|
||||
stackvmProg.instr(Opcode.INC_VAR, callLabel = indexVar)
|
||||
|
||||
// TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH / SUB opcodes and make use of the wrapping around of the value.
|
||||
stackvmProg.instr(Opcode.PUSH, Value(varDt, numElements))
|
||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = indexVar)
|
||||
stackvmProg.instr(Opcode.SUB)
|
||||
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
|
||||
|
||||
stackvmProg.label(breakLabel)
|
||||
stackvmProg.instr(Opcode.NOP)
|
||||
|
||||
breakStmtLabelStack.pop()
|
||||
continueStmtLabelStack.pop()
|
||||
}
|
||||
|
||||
private fun translateForOverConstantRange(varname: String, varDt: DataType, range: IntProgression, body: MutableList<IStatement>) {
|
||||
/**
|
||||
* for LV in start..last { body }
|
||||
|
@ -16,7 +16,7 @@ import prog8.functions.BuiltinFunctions
|
||||
todo statement optimization: X+=1, X-=1 --> X++/X-- ,
|
||||
todo remove statements that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc
|
||||
todo optimize addition with self into shift 1 (A+=A -> A<<=1)
|
||||
todo assignment optimization: optimize some simple multiplications into shifts (A*=8 -> A<<=3)
|
||||
todo assignment optimization: optimize some simple multiplications and divisions into shifts (A*=2 -> lsl(A), X=X/2 -> lsr(X) )
|
||||
todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to)
|
||||
todo merge sequence of assignments into one (as long as the value is a constant and the target not a MEMORY type!)
|
||||
todo report more always true/always false conditions
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -926,13 +926,13 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
DataType.ARRAY, DataType.MATRIX -> evalstack.push(Value(DataType.BYTE, array.array!![index]))
|
||||
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, array.array!![index]))
|
||||
DataType.ARRAY_F -> evalstack.push(Value(DataType.FLOAT, array.doubleArray!![index]))
|
||||
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
|
||||
DataType.STR_PS -> evalstack.push(Value(DataType.BYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0]))
|
||||
DataType.BYTE,
|
||||
DataType.WORD,
|
||||
DataType.FLOAT -> throw VmExecutionException("not a proper array/matrix var")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -965,13 +965,19 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
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
|
||||
DataType.STR_PS -> {
|
||||
if(value.type!=DataType.BYTE)
|
||||
throw VmExecutionException("writing a non-byte value into a string")
|
||||
val chars = array.str!!.toCharArray()
|
||||
chars[index] = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0]
|
||||
heap.update(variable.heapId, chars.joinToString(""))
|
||||
}
|
||||
DataType.BYTE,
|
||||
DataType.WORD,
|
||||
DataType.FLOAT -> throw VmExecutionException("not a proper array/matrix var")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user