mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 01:29:28 +00:00
fix for loop code generation.
added flt conversion function. attempt at implementing break and continue. var initializer value can be omitted for numeric vars (and default to 0) subroutine return statement not needed when no return values.
This commit is contained in:
parent
63492a1805
commit
00d74551b3
@ -66,6 +66,8 @@ statement :
|
||||
| labeldef
|
||||
| returnstmt
|
||||
| forloop
|
||||
| breakstmt
|
||||
| continuestmt
|
||||
// @todo whileloop, repeatloop
|
||||
;
|
||||
|
||||
@ -216,17 +218,5 @@ branchcondition: 'if_cs' | 'if_cc' | 'if_eq' | 'if_ne' | 'if_pl' | 'if_mi' | 'if
|
||||
|
||||
|
||||
forloop :
|
||||
'for' (register | identifier) 'in' expression EOL? loop_statement_block EOL
|
||||
;
|
||||
|
||||
loop_statement_block :
|
||||
'{' EOL
|
||||
(statement_in_loopblock | EOL) *
|
||||
'}'
|
||||
;
|
||||
|
||||
statement_in_loopblock :
|
||||
statement
|
||||
| breakstmt
|
||||
| continuestmt
|
||||
'for' (register | identifier) 'in' expression EOL? statement_block EOL
|
||||
;
|
||||
|
49
compiler/examples/mandelbrot.p8
Normal file
49
compiler/examples/mandelbrot.p8
Normal file
@ -0,0 +1,49 @@
|
||||
%option enable_floats
|
||||
|
||||
~ main {
|
||||
|
||||
sub start() -> () {
|
||||
|
||||
const word width = 159
|
||||
const word height = 127
|
||||
word pixelx
|
||||
byte pixely
|
||||
float xx
|
||||
float yy
|
||||
float x
|
||||
float y
|
||||
float x2
|
||||
byte iter
|
||||
word plotx
|
||||
byte ploty
|
||||
|
||||
_vm_gfx_clearscr(11)
|
||||
|
||||
for pixely in 0 to height { ; @todo 255 as upper limit doesn't work it overflows the loop
|
||||
for pixelx in 0 to width {
|
||||
xx=flt(pixelx)/width/3+0.2 ; @todo fix division to return float always, add // integer division
|
||||
yy=flt(pixely)/height/3.6+0.4
|
||||
|
||||
x=0.0
|
||||
y=0.0
|
||||
|
||||
for iter in 0 to 31 {
|
||||
if(x*x + y*y > 4) break
|
||||
x2 = x*x - y*y + xx
|
||||
y=x*y*2 + yy
|
||||
x=x2
|
||||
}
|
||||
|
||||
plotx = pixelx*2
|
||||
ploty = pixely*2
|
||||
_vm_gfx_pixel(plotx, ploty, iter)
|
||||
_vm_gfx_pixel(plotx+1, ploty, iter)
|
||||
_vm_gfx_pixel(plotx, ploty+1, iter)
|
||||
_vm_gfx_pixel(plotx+1, ploty+1, iter)
|
||||
}
|
||||
}
|
||||
|
||||
_vm_gfx_text(5, 5, 7, "Mandelbrot Fractal")
|
||||
}
|
||||
|
||||
}
|
@ -655,7 +655,7 @@ data class AssignTarget(val register: Register?, val identifier: IdentifierRefer
|
||||
Register.AX, Register.AY, Register.XY -> DataType.WORD
|
||||
}
|
||||
|
||||
val symbol = namespace.lookup(identifier!!.nameInSource, stmt)
|
||||
val symbol = namespace.lookup(identifier!!.nameInSource, stmt) ?: throw FatalAstException("symbol lookup failed: ${identifier!!.nameInSource}")
|
||||
if(symbol is VarDecl) return symbol.datatype
|
||||
throw FatalAstException("cannot determine datatype of assignment target $this")
|
||||
}
|
||||
@ -729,8 +729,7 @@ class BinaryExpression(var left: IExpression, val operator: String, var right: I
|
||||
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
||||
}
|
||||
DataType.WORD -> when(rightDt) {
|
||||
DataType.BYTE -> DataType.BYTE
|
||||
DataType.WORD -> DataType.WORD
|
||||
DataType.BYTE, DataType.WORD -> DataType.WORD
|
||||
DataType.FLOAT -> DataType.FLOAT
|
||||
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
||||
}
|
||||
@ -1057,6 +1056,7 @@ class FunctionCall(override var target: IdentifierReference,
|
||||
"len" -> builtinLen(arglist, position, namespace)
|
||||
"lsb" -> builtinLsb(arglist, position, namespace)
|
||||
"msb" -> builtinMsb(arglist, position, namespace)
|
||||
"flt" -> builtinFlt(arglist, position, namespace)
|
||||
"any" -> builtinAny(arglist, position, namespace)
|
||||
"all" -> builtinAll(arglist, position, namespace)
|
||||
"floor" -> builtinFloor(arglist, position, namespace)
|
||||
@ -1109,10 +1109,14 @@ class FunctionCall(override var target: IdentifierReference,
|
||||
return null // no return value
|
||||
}
|
||||
if(stmt.returnvalues.size==1) {
|
||||
return when(stmt.returnvalues[0].register) {
|
||||
Register.A, Register.X, Register.Y -> DataType.BYTE
|
||||
Register.AX, Register.AY, Register.XY -> DataType.WORD
|
||||
else -> TODO("return type for non-register result from subroutine $stmt")
|
||||
if(stmt.returnvalues[0].register!=null) {
|
||||
return when(stmt.returnvalues[0].register!!) {
|
||||
Register.A, Register.X, Register.Y -> DataType.BYTE
|
||||
Register.AX, Register.AY, Register.XY -> DataType.WORD
|
||||
}
|
||||
} else if(stmt.returnvalues[0].statusflag!=null) {
|
||||
val flag = stmt.returnvalues[0].statusflag!!
|
||||
TODO("return value in status flag $flag")
|
||||
}
|
||||
}
|
||||
TODO("return type for subroutine with multiple return values $stmt")
|
||||
@ -1122,7 +1126,7 @@ class FunctionCall(override var target: IdentifierReference,
|
||||
|
||||
override val isIterable: Boolean
|
||||
get() {
|
||||
TODO("iterable function call result?")
|
||||
TODO("isIterable of function call result")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1364,6 +1368,12 @@ private fun prog8Parser.StatementContext.toAst() : IStatement {
|
||||
val forloop = forloop()?.toAst()
|
||||
if(forloop!=null) return forloop
|
||||
|
||||
val breakstmt = breakstmt()?.toAst()
|
||||
if(breakstmt!=null) return breakstmt
|
||||
|
||||
val continuestmt = continuestmt()?.toAst()
|
||||
if(continuestmt!=null) return continuestmt
|
||||
|
||||
throw FatalAstException("unprocessed source text (are we missing ast conversion rules for parser elements?): $text")
|
||||
}
|
||||
|
||||
@ -1607,7 +1617,7 @@ private fun prog8Parser.ForloopContext.toAst(): ForLoop {
|
||||
val loopregister = register()?.toAst()
|
||||
val loopvar = identifier()?.toAst()
|
||||
val iterable = expression()!!.toAst()
|
||||
val body = loop_statement_block().toAst()
|
||||
val body = statement_block().toAst()
|
||||
return ForLoop(loopregister, loopvar, iterable, body, toPosition())
|
||||
}
|
||||
|
||||
@ -1637,17 +1647,3 @@ class ForLoop(val loopRegister: Register?,
|
||||
private fun prog8Parser.ContinuestmtContext.toAst() = Continue(toPosition())
|
||||
|
||||
private fun prog8Parser.BreakstmtContext.toAst() = Break(toPosition())
|
||||
|
||||
private fun prog8Parser.Loop_statement_blockContext.toAst() : MutableList<IStatement> {
|
||||
return statement_in_loopblock().asSequence().map {it.toAst()}.toMutableList()
|
||||
}
|
||||
|
||||
private fun prog8Parser.Statement_in_loopblockContext.toAst(): IStatement {
|
||||
val breakstmt = breakstmt()?.toAst()
|
||||
if(breakstmt!=null) return breakstmt
|
||||
|
||||
val contstmt = continuestmt()?.toAst()
|
||||
if(contstmt!=null) return contstmt
|
||||
|
||||
return this.statement().toAst()
|
||||
}
|
||||
|
@ -178,8 +178,9 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
||||
.map {(it as InlineAssembly).assembly}
|
||||
.count { it.contains(" rts") || it.contains("\trts") ||
|
||||
it.contains(" jmp") || it.contains("\tjmp")}
|
||||
if(amount==0 )
|
||||
err("subroutine must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
|
||||
if(amount==0 && subroutine.returnvalues.isNotEmpty())
|
||||
err("subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
|
||||
// @todo validate return values versus subroutine signature
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,10 +267,22 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
||||
err("float var/const declaration, but floating point is not enabled via options")
|
||||
}
|
||||
|
||||
// for now, variables can only be declared in a block or subroutine (not in a loop statement block) @todo fix this
|
||||
if(decl.parent !is Block && decl.parent !is Subroutine) {
|
||||
err ("variables must be declared at block or subroutine level")
|
||||
}
|
||||
|
||||
when(decl.type) {
|
||||
VarDeclType.VAR, VarDeclType.CONST -> {
|
||||
if (decl.value == null) {
|
||||
err("var/const declaration needs a compile-time constant initializer value")
|
||||
if(decl.datatype == DataType.BYTE || decl.datatype==DataType.WORD || decl.datatype==DataType.FLOAT) {
|
||||
// initialize numeric var with value zero by default.
|
||||
val litVal = LiteralValue(DataType.BYTE, 0, position = decl.position)
|
||||
litVal.parent = decl
|
||||
decl.value = litVal
|
||||
} else {
|
||||
err("var/const declaration needs a compile-time constant initializer value for this type")
|
||||
}
|
||||
return super.process(decl)
|
||||
}
|
||||
when {
|
||||
@ -523,10 +536,14 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
||||
}
|
||||
when (targetDt) {
|
||||
DataType.FLOAT -> {
|
||||
val number = value.floatvalue
|
||||
?: return err("floating point value expected")
|
||||
val number = when(value.type) {
|
||||
DataType.BYTE -> value.bytevalue!!.toDouble()
|
||||
DataType.WORD -> value.wordvalue!!.toDouble()
|
||||
DataType.FLOAT -> value.floatvalue!!
|
||||
else -> return err("numeric value expected")
|
||||
}
|
||||
if (number > 1.7014118345e+38 || number < -1.7014118345e+38)
|
||||
return err("floating point value '$number' out of range for MFLPT format")
|
||||
return err("value '$number' out of range for MFLPT format")
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
val number = value.asIntegerValue ?: return if (value.floatvalue!=null)
|
||||
|
@ -3,6 +3,7 @@ package prog8.compiler
|
||||
import prog8.ast.*
|
||||
import prog8.stackvm.*
|
||||
import java.io.PrintStream
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
@ -132,6 +133,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
var stmtUniqueSequenceNr = 0
|
||||
private set
|
||||
|
||||
val breakStmtLabelStack : Stack<String> = Stack()
|
||||
val continueStmtLabelStack : Stack<String> = Stack()
|
||||
|
||||
override fun process(subroutine: Subroutine): IStatement {
|
||||
stackvmProg.label(subroutine.scopedname)
|
||||
translate(subroutine.statements)
|
||||
@ -182,16 +186,18 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
|
||||
private fun translate(stmt: Continue) {
|
||||
stackvmProg.line(stmt.position)
|
||||
TODO("translate CONTINUE")
|
||||
// * ..continue statement: goto continue
|
||||
// we somehow have to know what the correct 'continue' label is
|
||||
if(continueStmtLabelStack.empty())
|
||||
throw CompilerException("continue outside of loop statement block")
|
||||
val label = continueStmtLabelStack.peek()
|
||||
stackvmProg.instr(Opcode.JUMP, null, label)
|
||||
}
|
||||
|
||||
private fun translate(stmt: Break) {
|
||||
stackvmProg.line(stmt.position)
|
||||
TODO("translate BREAK")
|
||||
// * ..break statement: goto break
|
||||
// we somehow have to know what the correct 'break' label is
|
||||
if(breakStmtLabelStack.empty())
|
||||
throw CompilerException("break outside of loop statement block")
|
||||
val label = breakStmtLabelStack.peek()
|
||||
stackvmProg.instr(Opcode.JUMP, null, label)
|
||||
}
|
||||
|
||||
private fun translate(branch: BranchStatement) {
|
||||
@ -532,7 +538,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
loop.loopRegister!=null ->
|
||||
translateForOverVariableRange(null, loop.loopRegister, loopVarDt, loop.iterable as RangeExpr, loop.body)
|
||||
else ->
|
||||
translateForOverVariableRange(loopVarName, null, loopVarDt, loop.iterable as RangeExpr, loop.body)
|
||||
translateForOverVariableRange(loop.loopVar!!.nameInSource, null, loopVarDt, loop.iterable as RangeExpr, loop.body)
|
||||
}
|
||||
} else {
|
||||
val litVal = loop.iterable as? LiteralValue
|
||||
@ -574,6 +580,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
val loopLabel = makeLabel("loop")
|
||||
val continueLabel = makeLabel("continue")
|
||||
val breakLabel = makeLabel("break")
|
||||
continueStmtLabelStack.push(continueLabel)
|
||||
breakStmtLabelStack.push(breakLabel)
|
||||
|
||||
val varValue = Value(DataType.STR, null, varname)
|
||||
stackvmProg.instr(Opcode.PUSH, Value(varDt, range.first))
|
||||
stackvmProg.instr(Opcode.POP_VAR, varValue)
|
||||
@ -606,9 +615,13 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
stackvmProg.instr(Opcode.BNE, callLabel = loopLabel)
|
||||
}
|
||||
stackvmProg.label(breakLabel)
|
||||
stackvmProg.instr(Opcode.NOP)
|
||||
|
||||
breakStmtLabelStack.pop()
|
||||
continueStmtLabelStack.pop()
|
||||
}
|
||||
|
||||
private fun translateForOverVariableRange(varname: String?, register: Register?, varDt: DataType, range: RangeExpr, body: MutableList<IStatement>) {
|
||||
private fun translateForOverVariableRange(varname: List<String>?, register: Register?, varDt: DataType, range: RangeExpr, body: MutableList<IStatement>) {
|
||||
/**
|
||||
* for LV in start..last { body }
|
||||
* (and we already know that the range is not empty)
|
||||
@ -628,29 +641,42 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
* break:
|
||||
*
|
||||
*/
|
||||
val assignmentTarget =
|
||||
if(varname!=null)
|
||||
AssignTarget(null, IdentifierReference(listOf(varname), range.position), range.position)
|
||||
else
|
||||
AssignTarget(register, null, range.position)
|
||||
fun makeAssignmentTarget(): AssignTarget {
|
||||
return if(varname!=null)
|
||||
AssignTarget(null, IdentifierReference(varname, range.position), range.position)
|
||||
else
|
||||
AssignTarget(register, null, range.position)
|
||||
}
|
||||
|
||||
var assignmentTarget = makeAssignmentTarget()
|
||||
val startAssignment = Assignment(assignmentTarget, null, range.from, range.position)
|
||||
startAssignment.linkParents(range.parent)
|
||||
|
||||
var stepIncrement: PostIncrDecr? = null
|
||||
var stepAddition: Assignment? = null
|
||||
if(range.step==null)
|
||||
if(range.step==null) {
|
||||
assignmentTarget = makeAssignmentTarget()
|
||||
stepIncrement = PostIncrDecr(assignmentTarget, "++", range.position)
|
||||
else
|
||||
stepIncrement.linkParents(range.parent)
|
||||
}
|
||||
else {
|
||||
assignmentTarget = makeAssignmentTarget()
|
||||
stepAddition = Assignment(
|
||||
assignmentTarget,
|
||||
"+=",
|
||||
range.step ?: LiteralValue(DataType.BYTE, 1, position = range.position),
|
||||
range.position
|
||||
assignmentTarget,
|
||||
"+=",
|
||||
range.step ?: LiteralValue(DataType.BYTE, 1, position = range.position),
|
||||
range.position
|
||||
)
|
||||
stepAddition.linkParents(range.parent)
|
||||
}
|
||||
translate(startAssignment)
|
||||
|
||||
val loopLabel = makeLabel("loop")
|
||||
val continueLabel = makeLabel("continue")
|
||||
val breakLabel = makeLabel("break")
|
||||
continueStmtLabelStack.push(continueLabel)
|
||||
breakStmtLabelStack.push(breakLabel)
|
||||
|
||||
stackvmProg.label(loopLabel)
|
||||
translate(body)
|
||||
stackvmProg.label(continueLabel)
|
||||
@ -661,12 +687,17 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
|
||||
val comparison = BinaryExpression(
|
||||
if(varname!=null)
|
||||
IdentifierReference(listOf(varname), range.position)
|
||||
IdentifierReference(varname, range.position)
|
||||
else
|
||||
RegisterExpr(register!!, range.position)
|
||||
,"<=", range.to, range.position)
|
||||
comparison.linkParents(range.parent)
|
||||
translate(comparison)
|
||||
stackvmProg.instr(Opcode.BNE, callLabel = loopLabel)
|
||||
stackvmProg.label(breakLabel)
|
||||
stackvmProg.instr(Opcode.NOP)
|
||||
|
||||
breakStmtLabelStack.pop()
|
||||
continueStmtLabelStack.pop()
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ val BuiltinFunctionNames = setOf(
|
||||
"P_carry", "P_irqd", "rol", "ror", "rol2", "ror2", "lsl", "lsr",
|
||||
"sin", "cos", "abs", "acos", "asin", "tan", "atan", "rnd", "rndw", "rndf",
|
||||
"ln", "log2", "log10", "sqrt", "rad", "deg", "round", "floor", "ceil",
|
||||
"max", "min", "avg", "sum", "len", "any", "all", "lsb", "msb",
|
||||
"max", "min", "avg", "sum", "len", "any", "all", "lsb", "msb", "flt",
|
||||
"_vm_write_memchr", "_vm_write_memstr", "_vm_write_num", "_vm_write_char",
|
||||
"_vm_write_str", "_vm_input_str", "_vm_gfx_clearscr", "_vm_gfx_pixel", "_vm_gfx_text"
|
||||
)
|
||||
@ -45,7 +45,8 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
||||
}
|
||||
|
||||
return when (function) {
|
||||
"sin", "cos", "tan", "asin", "acos", "atan", "ln", "log2", "log10", "sqrt", "rad", "deg", "avg", "rndf" -> DataType.FLOAT
|
||||
"sin", "cos", "tan", "asin", "acos", "atan", "ln", "log2", "log10",
|
||||
"sqrt", "rad", "deg", "avg", "rndf", "flt" -> DataType.FLOAT
|
||||
"lsb", "msb", "any", "all", "rnd" -> DataType.BYTE
|
||||
"rndw" -> DataType.WORD
|
||||
"rol", "rol2", "ror", "ror2", "P_carry", "P_irqd" -> null // no return value so no datatype
|
||||
@ -200,6 +201,16 @@ fun builtinRad(args: List<IExpression>, position: Position, namespace:INameScope
|
||||
fun builtinDeg(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::toDegrees)
|
||||
|
||||
fun builtinFlt(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue {
|
||||
// 1 numeric arg, convert to float
|
||||
if(args.size!=1)
|
||||
throw SyntaxError("flt requires one numeric argument", position)
|
||||
|
||||
val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException()
|
||||
val number = constval.asNumericValue ?: throw SyntaxError("flt requires one numeric argument", position)
|
||||
return LiteralValue(DataType.FLOAT, floatvalue = number.toDouble(), position = position)
|
||||
}
|
||||
|
||||
fun builtinAbs(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue {
|
||||
// 1 arg, type = float or int, result type= same as argument type
|
||||
if(args.size!=1)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -160,7 +160,8 @@ enum class Syscall(val callNr: Short) {
|
||||
FUNC_ALL(88),
|
||||
FUNC_RND(89), // push a random byte on the stack
|
||||
FUNC_RNDW(90), // push a random word on the stack
|
||||
FUNC_RNDF(91) // push a random float on the stack (between 0.0 and 1.0)
|
||||
FUNC_RNDF(91), // push a random float on the stack (between 0.0 and 1.0)
|
||||
FUNC_FLT(92)
|
||||
|
||||
// note: not all builtin functions of the Prog8 language are present as functions:
|
||||
// some of them are already opcodes (such as MSB and ROL)!
|
||||
@ -581,13 +582,14 @@ class Program (val name: String,
|
||||
val instructions = mutableListOf<Instruction>()
|
||||
val labels = mutableMapOf<String, Instruction>()
|
||||
val splitpattern = Pattern.compile("\\s+")
|
||||
var nextInstructionLabelname = ""
|
||||
val nextInstructionLabels = Stack<String>() // more than one label can occur on the same line
|
||||
|
||||
while(true) {
|
||||
val (lineNr, line) = lines.next()
|
||||
if(line=="%end_instructions")
|
||||
return Pair(instructions, labels)
|
||||
if(!line.startsWith(' ') && line.endsWith(':')) {
|
||||
nextInstructionLabelname = line.substring(0, line.length-1)
|
||||
nextInstructionLabels.push(line.substring(0, line.length-1))
|
||||
} else if(line.startsWith(' ')) {
|
||||
val parts = line.trimStart().split(splitpattern, limit = 2)
|
||||
val opcodeStr = parts[0].toUpperCase()
|
||||
@ -621,9 +623,9 @@ class Program (val name: String,
|
||||
}
|
||||
}
|
||||
instructions.add(instruction)
|
||||
if(nextInstructionLabelname.isNotEmpty()) {
|
||||
labels[nextInstructionLabelname] = instruction
|
||||
nextInstructionLabelname = ""
|
||||
while(nextInstructionLabels.isNotEmpty()) {
|
||||
val label = nextInstructionLabels.pop()
|
||||
labels[label] = instruction
|
||||
}
|
||||
} else throw VmExecutionException("syntax error at line ${lineNr+1}")
|
||||
}
|
||||
@ -844,8 +846,8 @@ class StackVm(val traceOutputFile: String?) {
|
||||
|
||||
fun step() {
|
||||
// step is invoked every 1/100 sec
|
||||
// we execute 5000 instructions in one go so we end up doing 500.000 instructions per second
|
||||
val instructionsPerStep = 5000
|
||||
// we execute 10k instructions in one go so we end up doing 1 million vm instructions per second
|
||||
val instructionsPerStep = 10000
|
||||
val start = System.currentTimeMillis()
|
||||
for(i:Int in 0..instructionsPerStep) {
|
||||
try {
|
||||
@ -1111,6 +1113,7 @@ class StackVm(val traceOutputFile: String?) {
|
||||
Syscall.FUNC_SQRT -> evalstack.push(Value(DataType.FLOAT, sqrt(evalstack.pop().numericValue().toDouble())))
|
||||
Syscall.FUNC_RAD -> evalstack.push(Value(DataType.FLOAT, Math.toRadians(evalstack.pop().numericValue().toDouble())))
|
||||
Syscall.FUNC_DEG -> evalstack.push(Value(DataType.FLOAT, Math.toDegrees(evalstack.pop().numericValue().toDouble())))
|
||||
Syscall.FUNC_FLT -> evalstack.push(Value(DataType.FLOAT, evalstack.pop().numericValue().toDouble()))
|
||||
Syscall.FUNC_FLOOR -> {
|
||||
val value = evalstack.pop()
|
||||
val result =
|
||||
|
@ -153,7 +153,8 @@ Variables and values
|
||||
--------------------
|
||||
|
||||
Variables are named values that can change during the execution of the program.
|
||||
When declaring a variable it is required to specify the initial value it should get.
|
||||
When declaring a numeric variable it is possible to specify the initial value, if you don't want it to be zero.
|
||||
For other data types it is required to specify that initial value it should get.
|
||||
Values will usually be part of an expression or assignment statement::
|
||||
|
||||
12345 ; integer number
|
||||
@ -290,7 +291,9 @@ The resulting value is simply a 16 bit word. Example::
|
||||
Loops
|
||||
-----
|
||||
|
||||
The *for*-loop is used to iterate over a range of values. Iteration is done in steps of 1, but you can change this.
|
||||
The *for*-loop is used to let a variable (or register) iterate over a range of values. Iteration is done in steps of 1, but you can change this.
|
||||
The loop variable must be declared as byte or word earlier. Floating point iteration is not supported.
|
||||
|
||||
The *while*-loop is used to repeat a piece of code while a certain condition is still true.
|
||||
The *repeat--until* loop is used to repeat a piece of code until a certain condition is true.
|
||||
|
||||
@ -492,6 +495,10 @@ lsb(x)
|
||||
msb(x)
|
||||
Get the most significant byte of the word x.
|
||||
|
||||
flt(x)
|
||||
Explicitly convert the number x to a floating point number.
|
||||
Usually this is done automatically but sometimes it may be required to force this.
|
||||
|
||||
any(x)
|
||||
1 ('true') if any of the values in the non-scalar (array or matrix) value x is 'true' (not zero), else 0 ('false')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user