mirror of
https://github.com/irmen/prog8.git
synced 2025-05-14 03:38:21 +00:00
fix type casting issues and unary ^ operator
signed numbers are no longer implicitly converted to unsigned proper range check on bankof()
This commit is contained in:
parent
58f696d00a
commit
50c3d809dc
@ -294,6 +294,14 @@ class PtNumber(type: DataType, val number: Double, position: Position) : PtExpre
|
|||||||
if (trunc != number)
|
if (trunc != number)
|
||||||
throw IllegalArgumentException("refused truncating of float to avoid loss of precision @$position")
|
throw IllegalArgumentException("refused truncating of float to avoid loss of precision @$position")
|
||||||
}
|
}
|
||||||
|
when(type) {
|
||||||
|
DataType.UBYTE -> require(number in 0.0..255.0)
|
||||||
|
DataType.BYTE -> require(number in -128.0..127.0)
|
||||||
|
DataType.UWORD -> require(number in 0.0..65535.0)
|
||||||
|
DataType.WORD -> require(number in -32728.0..32767.0)
|
||||||
|
DataType.LONG -> require(number in -2147483647.0..2147483647.0)
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int = Objects.hash(type, number)
|
override fun hashCode(): Int = Objects.hash(type, number)
|
||||||
@ -318,7 +326,7 @@ class PtPrefix(val operator: String, type: DataType, position: Position): PtExpr
|
|||||||
get() = children.single() as PtExpression
|
get() = children.single() as PtExpression
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(operator in setOf("+", "-", "~", "^", "<<", "not")) { "invalid prefix operator: $operator" }
|
require(operator in setOf("+", "-", "~", "^", "<<", "not")) { "invalid prefix operator: $operator" } // TODO ^ and << are experimental
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=", "xor")
|
|||||||
val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
|
val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
|
||||||
val LogicalOperators = setOf("and", "or", "xor", "not", "in")
|
val LogicalOperators = setOf("and", "or", "xor", "not", "in")
|
||||||
val BitwiseOperators = setOf("&", "|", "^", "~")
|
val BitwiseOperators = setOf("&", "|", "^", "~")
|
||||||
val PrefixOperators = setOf("+", "-", "~", "not")
|
val PrefixOperators = setOf("+", "-", "~", "^", "<<", "not") // TODO ^ and << are experimental
|
||||||
|
|
||||||
fun invertedComparisonOperator(operator: String) =
|
fun invertedComparisonOperator(operator: String) =
|
||||||
when (operator) {
|
when (operator) {
|
||||||
|
@ -1089,7 +1089,7 @@ object PetsciiEncoding {
|
|||||||
Ok(text.map {
|
Ok(text.map {
|
||||||
try {
|
try {
|
||||||
encodeChar(it, lowercase)
|
encodeChar(it, lowercase)
|
||||||
} catch (x: CharConversionException) {
|
} catch (_: CharConversionException) {
|
||||||
encodeChar(it, !lowercase)
|
encodeChar(it, !lowercase)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1135,7 +1135,7 @@ object PetsciiEncoding {
|
|||||||
Ok(text.map {
|
Ok(text.map {
|
||||||
try {
|
try {
|
||||||
encodeChar(it, lowercase)
|
encodeChar(it, lowercase)
|
||||||
} catch (x: CharConversionException) {
|
} catch (_: CharConversionException) {
|
||||||
encodeChar(it, !lowercase)
|
encodeChar(it, !lowercase)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -275,7 +275,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
|||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
compilationResult = result
|
compilationResult = result
|
||||||
} catch (x: AstException) {
|
} catch (_: AstException) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ internal val constEvaluatorsForBuiltinFuncs: Map<String, ConstExpressionCaller>
|
|||||||
"lsw" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x and 65535).toDouble() } },
|
"lsw" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x and 65535).toDouble() } },
|
||||||
"msb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 8 and 255).toDouble()} },
|
"msb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 8 and 255).toDouble()} },
|
||||||
"msw" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 16 and 65535).toDouble()} },
|
"msw" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 16 and 65535).toDouble()} },
|
||||||
"bankof" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 16 and 255).toDouble()} },
|
"bankof" to ::builtinBankof,
|
||||||
"mkword" to ::builtinMkword,
|
"mkword" to ::builtinMkword,
|
||||||
"clamp__ubyte" to ::builtinClampUByte,
|
"clamp__ubyte" to ::builtinClampUByte,
|
||||||
"clamp__byte" to ::builtinClampByte,
|
"clamp__byte" to ::builtinClampByte,
|
||||||
@ -153,6 +153,15 @@ private fun builtinLen(args: List<Expression>, position: Position, program: Prog
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun builtinBankof(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||||
|
if (args.size != 1)
|
||||||
|
throw SyntaxError("bankof requires one argument", position)
|
||||||
|
val const = args[0].constValue(program)?.number?.toInt() ?: throw NotConstArgumentException()
|
||||||
|
if(const > 0xffffff)
|
||||||
|
throw SyntaxError("integer overflow, bank exceeds 255", position)
|
||||||
|
return NumericLiteral(DataType.UBYTE, (const ushr 16 and 255).toDouble(), position)
|
||||||
|
}
|
||||||
|
|
||||||
private fun builtinMkword(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
private fun builtinMkword(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||||
if (args.size != 2)
|
if (args.size != 2)
|
||||||
throw SyntaxError("mkword requires msb and lsb arguments", position)
|
throw SyntaxError("mkword requires msb and lsb arguments", position)
|
||||||
|
@ -1142,22 +1142,34 @@ internal class AstChecker(private val program: Program,
|
|||||||
if(dt==DataType.UNDEFINED)
|
if(dt==DataType.UNDEFINED)
|
||||||
return // any error should be reported elsewhere
|
return // any error should be reported elsewhere
|
||||||
|
|
||||||
if(expr.operator=="-") {
|
when (expr.operator) {
|
||||||
|
"-" -> {
|
||||||
if (dt != DataType.BYTE && dt != DataType.WORD && dt != DataType.FLOAT) {
|
if (dt != DataType.BYTE && dt != DataType.WORD && dt != DataType.FLOAT) {
|
||||||
errors.err("can only take negative of a signed number type", expr.position)
|
errors.err("can only take negative of a signed number type", expr.position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(expr.operator == "~") {
|
"~" -> {
|
||||||
if(dt !in IntegerDatatypes)
|
if(dt !in IntegerDatatypes)
|
||||||
errors.err("can only use bitwise invert on integer types", expr.position)
|
errors.err("can only use bitwise invert on integer types", expr.position)
|
||||||
else if(dt==DataType.BOOL)
|
else if(dt==DataType.BOOL)
|
||||||
errors.err("bitwise invert is for integer types, use 'not' on booleans", expr.position)
|
errors.err("bitwise invert is for integer types, use 'not' on booleans", expr.position)
|
||||||
}
|
}
|
||||||
else if(expr.operator == "not") {
|
"not" -> {
|
||||||
if(dt!=DataType.BOOL) {
|
if(dt!=DataType.BOOL) {
|
||||||
errors.err("logical not is for booleans", expr.position)
|
errors.err("logical not is for booleans", expr.position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"^" -> { // TODO ^ prefix operator is experimental
|
||||||
|
if(dt in IntegerDatatypes) {
|
||||||
|
val value = expr.expression.constValue(program)?.number?.toInt()
|
||||||
|
if(value!=null && value > 0xffffff) {
|
||||||
|
errors.err("integer overflow, bank exceeds 255", expr.position)
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
errors.err("bankof operator can only take integer values", expr.position)
|
||||||
|
}
|
||||||
|
"<<" -> throw FatalAstException("unary << should have been replaced by a const uword") // TODO << is experimental
|
||||||
|
}
|
||||||
super.visit(expr)
|
super.visit(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class AstPreprocessor(val program: Program,
|
|||||||
val constval = range.to.constValue(program)
|
val constval = range.to.constValue(program)
|
||||||
if(constval!=null)
|
if(constval!=null)
|
||||||
modifications += IAstModification.ReplaceNode(range.to, constval, range)
|
modifications += IAstModification.ReplaceNode(range.to, constval, range)
|
||||||
} catch (x: SyntaxError) {
|
} catch (_: SyntaxError) {
|
||||||
// syntax errors will be reported later
|
// syntax errors will be reported later
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ class AstPreprocessor(val program: Program,
|
|||||||
val constval = range.step.constValue(program)
|
val constval = range.step.constValue(program)
|
||||||
if(constval!=null)
|
if(constval!=null)
|
||||||
modifications += IAstModification.ReplaceNode(range.step, constval, range)
|
modifications += IAstModification.ReplaceNode(range.step, constval, range)
|
||||||
} catch (x: SyntaxError) {
|
} catch (_: SyntaxError) {
|
||||||
// syntax errors will be reported later
|
// syntax errors will be reported later
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ class TestCompilerOnRanges: FunSpec({
|
|||||||
(array as ArrayLiteral).value.size shouldBe 26
|
(array as ArrayLiteral).value.size shouldBe 26
|
||||||
val forloop = (statements.dropLast(1).last() as ForLoop)
|
val forloop = (statements.dropLast(1).last() as ForLoop)
|
||||||
forloop.iterable shouldBe instanceOf<RangeExpression>()
|
forloop.iterable shouldBe instanceOf<RangeExpression>()
|
||||||
(forloop.iterable as RangeExpression).step shouldBe NumericLiteral(DataType.UBYTE, -2.0, Position.DUMMY)
|
(forloop.iterable as RangeExpression).step shouldBe NumericLiteral(DataType.BYTE, -2.0, Position.DUMMY)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("range with start/end variables should be ok") {
|
test("range with start/end variables should be ok") {
|
||||||
@ -285,7 +285,7 @@ class TestCompilerOnRanges: FunSpec({
|
|||||||
val statements = result.compilerAst.entrypoint.statements
|
val statements = result.compilerAst.entrypoint.statements
|
||||||
val forloop = (statements.dropLast(1).last() as ForLoop)
|
val forloop = (statements.dropLast(1).last() as ForLoop)
|
||||||
forloop.iterable shouldBe instanceOf<RangeExpression>()
|
forloop.iterable shouldBe instanceOf<RangeExpression>()
|
||||||
(forloop.iterable as RangeExpression).step shouldBe NumericLiteral(DataType.UBYTE, -2.0, Position.DUMMY)
|
(forloop.iterable as RangeExpression).step shouldBe NumericLiteral(DataType.BYTE, -2.0, Position.DUMMY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,11 +6,7 @@ import io.kotest.matchers.doubles.plusOrMinus
|
|||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.kotest.matchers.shouldNotBe
|
import io.kotest.matchers.shouldNotBe
|
||||||
import io.kotest.matchers.string.shouldContain
|
import io.kotest.matchers.string.shouldContain
|
||||||
import prog8.ast.expressions.NumericLiteral
|
|
||||||
import prog8.ast.statements.Assignment
|
|
||||||
import prog8.code.core.DataType
|
|
||||||
import prog8.code.core.InternalCompilerException
|
import prog8.code.core.InternalCompilerException
|
||||||
import prog8.code.core.Position
|
|
||||||
import prog8.code.core.toHex
|
import prog8.code.core.toHex
|
||||||
import prog8.code.target.C64Target
|
import prog8.code.target.C64Target
|
||||||
import prog8.code.target.cbm.Mflpt5
|
import prog8.code.target.cbm.Mflpt5
|
||||||
@ -162,15 +158,33 @@ class TestNumbers: FunSpec({
|
|||||||
sub start() {
|
sub start() {
|
||||||
uword @shared qq = ${'$'}2ff33
|
uword @shared qq = ${'$'}2ff33
|
||||||
cx16.r0 = ${'$'}1fc0f
|
cx16.r0 = ${'$'}1fc0f
|
||||||
|
cx16.r0L = 1234
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
val errors = ErrorReporterForTests()
|
val errors = ErrorReporterForTests()
|
||||||
compileText(C64Target(), true, src, writeAssembly = false, errors=errors) shouldBe null
|
compileText(C64Target(), true, src, writeAssembly = false, errors=errors) shouldBe null
|
||||||
errors.errors.size shouldBe 2
|
errors.errors.size shouldBe 6
|
||||||
errors.warnings.size shouldBe 0
|
errors.warnings.size shouldBe 0
|
||||||
errors.errors[0] shouldContain "out of range"
|
errors.errors[0] shouldContain "out of range"
|
||||||
errors.errors[1] shouldContain "out of range"
|
errors.errors[1] shouldContain "doesn't match"
|
||||||
|
errors.errors[2] shouldContain "out of range"
|
||||||
|
errors.errors[3] shouldContain "doesn't match"
|
||||||
|
errors.errors[4] shouldContain "out of range"
|
||||||
|
errors.errors[5] shouldContain "cannot assign word to byte"
|
||||||
|
}
|
||||||
|
|
||||||
|
test("large numeric literals still ok if actual value is small") {
|
||||||
|
val src="""
|
||||||
|
main {
|
||||||
|
sub start() {
|
||||||
|
cx16.r1L = %000000000001
|
||||||
|
cx16.r2L = ${'$'}000000000001
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
val errors = ErrorReporterForTests()
|
||||||
|
compileText(C64Target(), true, src, writeAssembly = false, errors=errors) shouldNotBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
test("big numbers okay in const expressions if result fits") {
|
test("big numbers okay in const expressions if result fits") {
|
||||||
@ -185,7 +199,7 @@ class TestNumbers: FunSpec({
|
|||||||
compileText(C64Target(), true, src, writeAssembly = false) shouldNotBe null
|
compileText(C64Target(), true, src, writeAssembly = false) shouldNotBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
test("signed negative numbers cast to unsigned allowed") {
|
test("signed negative numbers not implicitly cast to unsigned") {
|
||||||
val src="""
|
val src="""
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
@ -197,13 +211,14 @@ class TestNumbers: FunSpec({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
val errors = ErrorReporterForTests()
|
||||||
val statements = result.compilerAst.entrypoint.statements
|
compileText(C64Target(), false, src, writeAssembly = false, errors=errors) shouldBe null
|
||||||
statements.size shouldBe 8
|
errors.errors.size shouldBe 6
|
||||||
(statements[1] as Assignment).value shouldBe NumericLiteral(DataType.UWORD, 32768.0, Position.DUMMY)
|
errors.errors[0] shouldContain "out of range"
|
||||||
(statements[3] as Assignment).value shouldBe NumericLiteral(DataType.UWORD, 65535.0, Position.DUMMY)
|
errors.errors[1] shouldContain "WORD doesn't match"
|
||||||
(statements[5] as Assignment).value shouldBe NumericLiteral(DataType.UBYTE, 255.0, Position.DUMMY)
|
errors.errors[2] shouldContain "out of range"
|
||||||
(statements[6] as Assignment).value shouldBe NumericLiteral(DataType.UWORD, 65534.0, Position.DUMMY)
|
errors.errors[3] shouldContain "BYTE doesn't match"
|
||||||
(statements[7] as Assignment).value shouldBe NumericLiteral(DataType.UBYTE, 254.0, Position.DUMMY)
|
errors.errors[4] shouldContain "out of range"
|
||||||
|
errors.errors[5] shouldContain "BYTE doesn't match"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -162,6 +162,14 @@ class TestNumericLiteral: FunSpec({
|
|||||||
NumericLiteral.optimalInteger(-1000, Position.DUMMY).number shouldBe -1000.0
|
NumericLiteral.optimalInteger(-1000, Position.DUMMY).number shouldBe -1000.0
|
||||||
NumericLiteral.optimalInteger(1000u, Position.DUMMY).type shouldBe DataType.UWORD
|
NumericLiteral.optimalInteger(1000u, Position.DUMMY).type shouldBe DataType.UWORD
|
||||||
NumericLiteral.optimalInteger(1000u, Position.DUMMY).number shouldBe 1000.0
|
NumericLiteral.optimalInteger(1000u, Position.DUMMY).number shouldBe 1000.0
|
||||||
|
|
||||||
|
NumericLiteral.optimalInteger(DataType.UBYTE, DataType.UWORD, 1, Position.DUMMY).type shouldBe DataType.UWORD
|
||||||
|
NumericLiteral.optimalInteger(DataType.UWORD, DataType.UBYTE, 1, Position.DUMMY).type shouldBe DataType.UWORD
|
||||||
|
NumericLiteral.optimalInteger(DataType.UWORD, null, 1, Position.DUMMY).type shouldBe DataType.UWORD
|
||||||
|
NumericLiteral.optimalInteger(DataType.UBYTE, DataType.UBYTE, -1, Position.DUMMY).type shouldBe DataType.BYTE
|
||||||
|
NumericLiteral.optimalInteger(DataType.UBYTE, null, -1, Position.DUMMY).type shouldBe DataType.BYTE
|
||||||
|
NumericLiteral.optimalInteger(DataType.UWORD, DataType.UWORD, -1, Position.DUMMY).type shouldBe DataType.WORD
|
||||||
|
NumericLiteral.optimalInteger(DataType.UWORD, null, -1, Position.DUMMY).type shouldBe DataType.WORD
|
||||||
}
|
}
|
||||||
|
|
||||||
test("optimalNumeric") {
|
test("optimalNumeric") {
|
||||||
@ -183,6 +191,22 @@ class TestNumericLiteral: FunSpec({
|
|||||||
NumericLiteral.optimalNumeric(1234.0, Position.DUMMY).number shouldBe 1234.0
|
NumericLiteral.optimalNumeric(1234.0, Position.DUMMY).number shouldBe 1234.0
|
||||||
NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).type shouldBe DataType.WORD
|
NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).type shouldBe DataType.WORD
|
||||||
NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).number shouldBe -1234.0
|
NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).number shouldBe -1234.0
|
||||||
|
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UBYTE, DataType.UWORD, 1.0, Position.DUMMY).type shouldBe DataType.UWORD
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UWORD, DataType.UBYTE, 1.0, Position.DUMMY).type shouldBe DataType.UWORD
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UWORD, null, 1.0, Position.DUMMY).type shouldBe DataType.UWORD
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UBYTE, DataType.UBYTE, -1.0, Position.DUMMY).type shouldBe DataType.BYTE
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UBYTE, null, -1.0, Position.DUMMY).type shouldBe DataType.BYTE
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UWORD, DataType.UWORD, -1.0, Position.DUMMY).type shouldBe DataType.WORD
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UWORD, null, -1.0, Position.DUMMY).type shouldBe DataType.WORD
|
||||||
|
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UBYTE, DataType.UWORD, 1.234, Position.DUMMY).type shouldBe DataType.FLOAT
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UWORD, DataType.UBYTE, 1.234, Position.DUMMY).type shouldBe DataType.FLOAT
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UWORD, null, 1.234, Position.DUMMY).type shouldBe DataType.FLOAT
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UBYTE, DataType.UBYTE, -1.234, Position.DUMMY).type shouldBe DataType.FLOAT
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UBYTE, null, -1.234, Position.DUMMY).type shouldBe DataType.FLOAT
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UWORD, DataType.UWORD, -1.234, Position.DUMMY).type shouldBe DataType.FLOAT
|
||||||
|
NumericLiteral.optimalNumeric(DataType.UWORD, null, -1.234, Position.DUMMY).type shouldBe DataType.FLOAT
|
||||||
}
|
}
|
||||||
|
|
||||||
test("cast can change value") {
|
test("cast can change value") {
|
||||||
|
@ -896,8 +896,7 @@ main {
|
|||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
val errors = ErrorReporterForTests()
|
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
||||||
val result = compileText(C64Target(), false, src, writeAssembly = false, errors = errors)!!
|
|
||||||
val program = result.compilerAst
|
val program = result.compilerAst
|
||||||
val st = program.entrypoint.statements
|
val st = program.entrypoint.statements
|
||||||
st.size shouldBe 1
|
st.size shouldBe 1
|
||||||
@ -909,4 +908,49 @@ main {
|
|||||||
ifexpr.truevalue shouldBe instanceOf<NumericLiteral>()
|
ifexpr.truevalue shouldBe instanceOf<NumericLiteral>()
|
||||||
ifexpr.falsevalue shouldBe instanceOf<NumericLiteral>()
|
ifexpr.falsevalue shouldBe instanceOf<NumericLiteral>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("correct data types of numeric literals in word/byte scenario") {
|
||||||
|
val src = """
|
||||||
|
main {
|
||||||
|
sub start() {
|
||||||
|
const uword WIDTH = 40
|
||||||
|
const uword WIDER = 400
|
||||||
|
cx16.r0 = cx16.r0-1+WIDTH
|
||||||
|
cx16.r0 = cx16.r0-1+WIDER
|
||||||
|
cx16.r0 = cx16.r0L * 5 ; byte multiplication
|
||||||
|
cx16.r0 = cx16.r0L * ${'$'}0005 ; word multiplication
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
||||||
|
val program = result.compilerAst
|
||||||
|
val st = program.entrypoint.statements
|
||||||
|
st.size shouldBe 6
|
||||||
|
val v1 = (st[2] as Assignment).value as BinaryExpression
|
||||||
|
v1.operator shouldBe "+"
|
||||||
|
(v1.left as IdentifierReference).nameInSource shouldBe listOf("cx16","r0")
|
||||||
|
(v1.right as NumericLiteral).type shouldBe DataType.UWORD
|
||||||
|
(v1.right as NumericLiteral).number shouldBe 39
|
||||||
|
|
||||||
|
val v2 = (st[3] as Assignment).value as BinaryExpression
|
||||||
|
v2.operator shouldBe "+"
|
||||||
|
(v2.left as IdentifierReference).nameInSource shouldBe listOf("cx16","r0")
|
||||||
|
(v2.right as NumericLiteral).type shouldBe DataType.UWORD
|
||||||
|
(v2.right as NumericLiteral).number shouldBe 399
|
||||||
|
|
||||||
|
val v3 = (st[4] as Assignment).value as TypecastExpression
|
||||||
|
v3.type shouldBe DataType.UWORD
|
||||||
|
val v3e = v3.expression as BinaryExpression
|
||||||
|
v3e.operator shouldBe "*"
|
||||||
|
(v3e.left as IdentifierReference).nameInSource shouldBe listOf("cx16","r0L")
|
||||||
|
(v3e.right as NumericLiteral).type shouldBe DataType.UBYTE
|
||||||
|
(v3e.right as NumericLiteral).number shouldBe 5
|
||||||
|
|
||||||
|
val v4 = (st[5] as Assignment).value as BinaryExpression
|
||||||
|
v4.operator shouldBe "*"
|
||||||
|
val v4t = v4.left as TypecastExpression
|
||||||
|
v4t.type shouldBe DataType.UWORD
|
||||||
|
(v4t.expression as IdentifierReference).nameInSource shouldBe listOf("cx16","r0L")
|
||||||
|
(v4.right as NumericLiteral).type shouldBe DataType.UWORD
|
||||||
|
(v4.right as NumericLiteral).number shouldBe 5
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
@ -464,7 +464,9 @@ private fun IntegerliteralContext.toAst(): NumericLiteralNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
if(literalText.length>8)
|
if(literalText.length>16)
|
||||||
|
datatype = DataType.LONG
|
||||||
|
else if(literalText.length>8)
|
||||||
datatype = DataType.UWORD
|
datatype = DataType.UWORD
|
||||||
try {
|
try {
|
||||||
integer = literalText.toInt(2)
|
integer = literalText.toInt(2)
|
||||||
@ -473,7 +475,9 @@ private fun IntegerliteralContext.toAst(): NumericLiteralNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
16 -> {
|
16 -> {
|
||||||
if(literalText.length>2)
|
if(literalText.length>4)
|
||||||
|
datatype = DataType.LONG
|
||||||
|
else if(literalText.length>2)
|
||||||
datatype = DataType.UWORD
|
datatype = DataType.UWORD
|
||||||
try {
|
try {
|
||||||
integer = literalText.toInt(16)
|
integer = literalText.toInt(16)
|
||||||
@ -558,7 +562,7 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi
|
|||||||
|
|
||||||
if (rangefrom!=null && rangeto!=null) {
|
if (rangefrom!=null && rangeto!=null) {
|
||||||
val defaultstep = if(rto.text == "to") 1 else -1
|
val defaultstep = if(rto.text == "to") 1 else -1
|
||||||
val step = rangestep?.toAst() ?: NumericLiteral(DataType.UBYTE, defaultstep.toDouble(), toPosition())
|
val step = rangestep?.toAst() ?: NumericLiteral.optimalInteger(defaultstep, toPosition())
|
||||||
return RangeExpression(rangefrom.toAst(), rangeto.toAst(), step, toPosition())
|
return RangeExpression(rangefrom.toAst(), rangeto.toAst(), step, toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,13 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
|
|||||||
else -> throw ExpressionError("can only take bitwise inversion of int", constval.position)
|
else -> throw ExpressionError("can only take bitwise inversion of int", constval.position)
|
||||||
}
|
}
|
||||||
"not" -> NumericLiteral.fromBoolean(constval.number==0.0, constval.position)
|
"not" -> NumericLiteral.fromBoolean(constval.number==0.0, constval.position)
|
||||||
"^" -> NumericLiteral(DataType.UBYTE, (constval.number.toInt() ushr 16 and 255).toDouble(), constval.position) // bank
|
"^" -> {
|
||||||
|
val const = constval.number.toInt()
|
||||||
|
return if(const>0xffffff)
|
||||||
|
null // number is more than 24 bits; bank byte exceeds 255
|
||||||
|
else
|
||||||
|
NumericLiteral(DataType.UBYTE, (const ushr 16 and 255).toDouble(), constval.position) // bank
|
||||||
|
}
|
||||||
"<<" -> NumericLiteral(DataType.UWORD, (constval.number.toInt() and 65535).toDouble(), constval.position) // address
|
"<<" -> NumericLiteral(DataType.UWORD, (constval.number.toInt() and 65535).toDouble(), constval.position) // address
|
||||||
else -> throw FatalAstException("invalid operator")
|
else -> throw FatalAstException("invalid operator")
|
||||||
}
|
}
|
||||||
@ -226,7 +232,7 @@ class BinaryExpression(
|
|||||||
dt
|
dt
|
||||||
} else
|
} else
|
||||||
dt
|
dt
|
||||||
} catch (x: FatalAstException) {
|
} catch (_: FatalAstException) {
|
||||||
InferredTypes.unknown()
|
InferredTypes.unknown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,6 +262,25 @@ class BinaryExpression(
|
|||||||
// word + word -> word
|
// word + word -> word
|
||||||
// a combination with a float will be float (but give a warning about this!)
|
// a combination with a float will be float (but give a warning about this!)
|
||||||
|
|
||||||
|
// if left or right is a numeric literal, and its value fits in the type of the other operand, use the other's operand type
|
||||||
|
// EXCEPTION: if the numeric value is a word and the other operand is a byte type (to allow v * $0008 for example)
|
||||||
|
if (left is NumericLiteral) {
|
||||||
|
if(!(leftDt in WordDatatypes && rightDt in ByteDatatypes)) {
|
||||||
|
val optimal = NumericLiteral.optimalNumeric(rightDt, null, left.number, left.position)
|
||||||
|
if (optimal.type != leftDt && optimal.type isAssignableTo rightDt) {
|
||||||
|
return optimal.type to left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (right is NumericLiteral) {
|
||||||
|
if(!(rightDt in WordDatatypes && leftDt in ByteDatatypes)) {
|
||||||
|
val optimal = NumericLiteral.optimalNumeric(leftDt, null, right.number, right.position)
|
||||||
|
if (optimal.type != rightDt && optimal.type isAssignableTo leftDt) {
|
||||||
|
return optimal.type to right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return when (leftDt) {
|
return when (leftDt) {
|
||||||
DataType.BOOL -> {
|
DataType.BOOL -> {
|
||||||
return if(rightDt==DataType.BOOL)
|
return if(rightDt==DataType.BOOL)
|
||||||
@ -508,6 +533,18 @@ class NumericLiteral(val type: DataType, // only numerical types allowed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
when(type) {
|
||||||
|
DataType.UBYTE -> require(numbervalue in 0.0..255.0)
|
||||||
|
DataType.BYTE -> require(numbervalue in -128.0..127.0)
|
||||||
|
DataType.UWORD -> require(numbervalue in 0.0..65535.0)
|
||||||
|
DataType.WORD -> require(numbervalue in -32768.0..32767.0)
|
||||||
|
DataType.LONG -> require(numbervalue in -2147483647.0..2147483647.0)
|
||||||
|
DataType.BOOL -> require(numbervalue==0.0 || numbervalue==1.0)
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val isSimple = true
|
override val isSimple = true
|
||||||
override fun copy() = NumericLiteral(type, number, position)
|
override fun copy() = NumericLiteral(type, number, position)
|
||||||
|
|
||||||
@ -515,23 +552,11 @@ class NumericLiteral(val type: DataType, // only numerical types allowed
|
|||||||
fun fromBoolean(bool: Boolean, position: Position) =
|
fun fromBoolean(bool: Boolean, position: Position) =
|
||||||
NumericLiteral(DataType.BOOL, if(bool) 1.0 else 0.0, position)
|
NumericLiteral(DataType.BOOL, if(bool) 1.0 else 0.0, position)
|
||||||
|
|
||||||
fun optimalNumeric(origType1: DataType, origType2: DataType?, value: Number, position: Position) : NumericLiteral {
|
fun optimalNumeric(origType1: DataType, origType2: DataType?, value: Number, position: Position) : NumericLiteral =
|
||||||
val optimal = optimalNumeric(value, position)
|
fromOptimal(optimalNumeric(value, position), origType1, origType2, position)
|
||||||
val largestOrig = if(origType2==null) origType1 else if(origType1.largerThan(origType2)) origType1 else origType2
|
|
||||||
return if(largestOrig.largerThan(optimal.type))
|
|
||||||
NumericLiteral(largestOrig, optimal.number, position)
|
|
||||||
else
|
|
||||||
optimal
|
|
||||||
}
|
|
||||||
|
|
||||||
fun optimalInteger(origType1: DataType, origType2: DataType?, value: Int, position: Position): NumericLiteral {
|
fun optimalInteger(origType1: DataType, origType2: DataType?, value: Int, position: Position): NumericLiteral =
|
||||||
val optimal = optimalInteger(value, position)
|
fromOptimal(optimalInteger(value, position), origType1, origType2, position)
|
||||||
val largestOrig = if(origType2==null) origType1 else if(origType1.largerThan(origType2)) origType1 else origType2
|
|
||||||
return if(largestOrig.largerThan(optimal.type))
|
|
||||||
NumericLiteral(largestOrig, optimal.number, position)
|
|
||||||
else
|
|
||||||
optimal
|
|
||||||
}
|
|
||||||
|
|
||||||
fun optimalNumeric(value: Number, position: Position): NumericLiteral {
|
fun optimalNumeric(value: Number, position: Position): NumericLiteral {
|
||||||
val digits = floor(value.toDouble()) - value.toDouble()
|
val digits = floor(value.toDouble()) - value.toDouble()
|
||||||
@ -570,6 +595,23 @@ class NumericLiteral(val type: DataType, // only numerical types allowed
|
|||||||
else -> throw FatalAstException("unsigned integer overflow: $value")
|
else -> throw FatalAstException("unsigned integer overflow: $value")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun fromOptimal(optimal: NumericLiteral, origType1: DataType, origType2: DataType?, position: Position): NumericLiteral {
|
||||||
|
var largestOrig = if(origType2==null) origType1 else if(origType1.largerThan(origType2)) origType1 else origType2
|
||||||
|
return if(largestOrig.largerThan(optimal.type)) {
|
||||||
|
if(optimal.number<0 && largestOrig !in SignedDatatypes) {
|
||||||
|
when(largestOrig){
|
||||||
|
DataType.BOOL -> {}
|
||||||
|
DataType.UBYTE -> largestOrig = DataType.BYTE
|
||||||
|
DataType.UWORD -> largestOrig = DataType.WORD
|
||||||
|
else -> throw FatalAstException("invalid dt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NumericLiteral(largestOrig, optimal.number, position)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
optimal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val asBooleanValue: Boolean = number != 0.0
|
val asBooleanValue: Boolean = number != 0.0
|
||||||
@ -655,13 +697,13 @@ class NumericLiteral(val type: DataType, // only numerical types allowed
|
|||||||
}
|
}
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
if(targettype==DataType.UBYTE) {
|
if(targettype==DataType.UBYTE) {
|
||||||
if(number in -128.0..0.0)
|
if(number in -128.0..0.0 && !implicit)
|
||||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUByte().toDouble(), position))
|
return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUByte().toDouble(), position))
|
||||||
else if(number in 0.0..255.0)
|
else if(number in 0.0..255.0)
|
||||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
||||||
}
|
}
|
||||||
if(targettype==DataType.UWORD) {
|
if(targettype==DataType.UWORD) {
|
||||||
if(number in -32768.0..0.0)
|
if(number in -32768.0..0.0 && !implicit)
|
||||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUShort().toDouble(), position))
|
return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUShort().toDouble(), position))
|
||||||
else if(number in 0.0..65535.0)
|
else if(number in 0.0..65535.0)
|
||||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
||||||
@ -689,13 +731,13 @@ class NumericLiteral(val type: DataType, // only numerical types allowed
|
|||||||
if(targettype==DataType.BYTE && number >= -128 && number <=127)
|
if(targettype==DataType.BYTE && number >= -128 && number <=127)
|
||||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
||||||
if(targettype==DataType.UBYTE) {
|
if(targettype==DataType.UBYTE) {
|
||||||
if(number in -128.0..0.0)
|
if(number in -128.0..0.0 && !implicit)
|
||||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUByte().toDouble(), position))
|
return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUByte().toDouble(), position))
|
||||||
else if(number in 0.0..255.0)
|
else if(number in 0.0..255.0)
|
||||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
||||||
}
|
}
|
||||||
if(targettype==DataType.UWORD) {
|
if(targettype==DataType.UWORD) {
|
||||||
if(number in -32768.0 .. 0.0)
|
if(number in -32768.0 .. 0.0 && !implicit)
|
||||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUShort().toDouble(), position))
|
return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUShort().toDouble(), position))
|
||||||
else if(number in 0.0..65535.0)
|
else if(number in 0.0..65535.0)
|
||||||
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
return ValueAfterCast(true, null, NumericLiteral(targettype, number, position))
|
||||||
|
@ -102,7 +102,7 @@ msb (x)
|
|||||||
can do that using ``bankof(x)``.
|
can do that using ``bankof(x)``.
|
||||||
|
|
||||||
bankof (x)
|
bankof (x)
|
||||||
Get the 'bank' byte from the value x. This means bits 16-24 of that value: bankof($1234567) = $12.
|
Get the 'bank' byte from the value x. This means bits 16-24 of that value: bankof($123456) = $12.
|
||||||
(To get the 16 bit address out of a value simply use ``x & $ffff``)
|
(To get the 16 bit address out of a value simply use ``x & $ffff``)
|
||||||
If x is a word or smaller, bankof(x) will always be zero.
|
If x is a word or smaller, bankof(x) will always be zero.
|
||||||
You can consider this function equivalent to the expression ``lsb(x >> 16)``.
|
You can consider this function equivalent to the expression ``lsb(x >> 16)``.
|
||||||
|
@ -3,7 +3,7 @@ TODO
|
|||||||
|
|
||||||
make a compiler switch to disable footgun warnings
|
make a compiler switch to disable footgun warnings
|
||||||
|
|
||||||
what to do with bankof(): keep it? add another syntax like \`value or ^value to get the bank byte?
|
-> added bankof() to get the bank byte of a large integer
|
||||||
-> added msw() and lsw() . note: msw() on a 24 bits constant can ALSO be used to get the bank byte because the value, while a word type, will be <=255
|
-> added msw() and lsw() . note: msw() on a 24 bits constant can ALSO be used to get the bank byte because the value, while a word type, will be <=255
|
||||||
-> added unary ^ operator as alternative to bankof()
|
-> added unary ^ operator as alternative to bankof()
|
||||||
-> added unary << operator as alternative to lsw() / lsb(x>>16)
|
-> added unary << operator as alternative to lsw() / lsb(x>>16)
|
||||||
|
@ -190,13 +190,26 @@ which is the PETSCII value for that character. You can prefix it with the desire
|
|||||||
|
|
||||||
**bytes versus words:**
|
**bytes versus words:**
|
||||||
|
|
||||||
- When an integer value ranges from 0..255 the compiler sees it as a ``ubyte``. For -128..127 it's a ``byte``.
|
Prog8 tries to determine the data type of integer values according to the table below,
|
||||||
- When an integer value ranges from 256..65535 the compiler sees it as a ``uword``. For -32768..32767 it's a ``word``.
|
and sometimes the context in which they are used.
|
||||||
- When a hex number has 3 or 4 digits, for example ``$0004``, it is seen as a ``word`` otherwise as a ``byte``.
|
|
||||||
- When a binary number has 9 to 16 digits, for example ``%1100110011``, it is seen as a ``word`` otherwise as a ``byte``.
|
|
||||||
- If the number fits in a byte but you really require it as a word value, you'll have to explicitly cast it: ``60 as uword``
|
|
||||||
or you can use the full word hexadecimal notation ``$003c``.
|
|
||||||
|
|
||||||
|
========================= =================
|
||||||
|
value datatype
|
||||||
|
========================= =================
|
||||||
|
-128 .. 127 byte
|
||||||
|
0 .. 255 ubyte
|
||||||
|
-32768 .. 32767 word
|
||||||
|
0 .. 65535 uword
|
||||||
|
-2147483647 .. 2147483647 long (only for const)
|
||||||
|
========================= =================
|
||||||
|
|
||||||
|
If the number fits in a byte but you really require it as a word value, you'll have to explicitly cast it: ``60 as uword``
|
||||||
|
or you can use the full word hexadecimal notation ``$003c``. This is useful in expressions where you want a calcuation
|
||||||
|
to be done on word values, and don't want to explicitly have to cast everything all the time. For instance::
|
||||||
|
|
||||||
|
ubyte column
|
||||||
|
uword offset = column * 64 ; does (column * 64) as uword, wrong result?
|
||||||
|
uword offset = column * $0040 ; does (column as uword) * 64 , a word calculation
|
||||||
|
|
||||||
Only for ``const`` numbers, you can use larger values (32 bits signed integers). The compiler can handle those
|
Only for ``const`` numbers, you can use larger values (32 bits signed integers). The compiler can handle those
|
||||||
internally in expressions. As soon as you have to actually store it into a variable,
|
internally in expressions. As soon as you have to actually store it into a variable,
|
||||||
@ -226,8 +239,6 @@ This saves a lot of memory and may be faster as well.
|
|||||||
Floating point numbers
|
Floating point numbers
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
You can use underscores to group digits to make long numbers more readable.
|
|
||||||
|
|
||||||
Floats are stored in the 5-byte 'MFLPT' format that is used on CBM machines.
|
Floats are stored in the 5-byte 'MFLPT' format that is used on CBM machines.
|
||||||
Floating point support is available on the c64 and cx16 (and virtual) compiler targets.
|
Floating point support is available on the c64 and cx16 (and virtual) compiler targets.
|
||||||
On the c64 and cx16, the rom routines are used for floating point operations,
|
On the c64 and cx16, the rom routines are used for floating point operations,
|
||||||
@ -243,6 +254,10 @@ to worry about this yourself)
|
|||||||
|
|
||||||
The largest 5-byte MFLPT float that can be stored is: **1.7014118345e+38** (negative: **-1.7014118345e+38**)
|
The largest 5-byte MFLPT float that can be stored is: **1.7014118345e+38** (negative: **-1.7014118345e+38**)
|
||||||
|
|
||||||
|
You can use underscores to group digits in floating point literals to make long numbers more readable:
|
||||||
|
any underscores in the number are ignored by the compiler.
|
||||||
|
For instance ``30_000.999_999`` is a valid floating point number 30000.999999.
|
||||||
|
|
||||||
|
|
||||||
Arrays
|
Arrays
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
@ -28,7 +28,7 @@ adpcm {
|
|||||||
; belong to the left channel and -if it's stereo- the next 4 bytes belong to the right channel.
|
; belong to the left channel and -if it's stereo- the next 4 bytes belong to the right channel.
|
||||||
|
|
||||||
|
|
||||||
ubyte[] t_index = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]
|
byte[] t_index = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]
|
||||||
uword[] @split t_step = [
|
uword[] @split t_step = [
|
||||||
7, 8, 9, 10, 11, 12, 13, 14,
|
7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
16, 17, 19, 21, 23, 25, 28, 31,
|
16, 17, 19, 21, 23, 25, 28, 31,
|
||||||
@ -92,7 +92,7 @@ adpcm {
|
|||||||
; elif predicted < -32767:
|
; elif predicted < -32767:
|
||||||
; predicted = - 32767
|
; predicted = - 32767
|
||||||
|
|
||||||
index += t_index[nibble]
|
index += t_index[nibble] as ubyte
|
||||||
if_neg
|
if_neg
|
||||||
index = 0
|
index = 0
|
||||||
else if index >= len(t_step)-1
|
else if index >= len(t_step)-1
|
||||||
@ -128,7 +128,7 @@ adpcm {
|
|||||||
; elif predicted < -32767:
|
; elif predicted < -32767:
|
||||||
; predicted = - 32767
|
; predicted = - 32767
|
||||||
|
|
||||||
index_2 += t_index[nibble]
|
index_2 += t_index[nibble] as ubyte
|
||||||
if_neg
|
if_neg
|
||||||
index_2 = 0
|
index_2 = 0
|
||||||
else if index_2 >= len(t_step)-1
|
else if index_2 >= len(t_step)-1
|
||||||
|
@ -4,16 +4,28 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
@($2005) = 0
|
ubyte @shared ub = -1
|
||||||
txt.print_ub(get_indexed_byte($2000, 5))
|
uword @shared uw = -5555
|
||||||
txt.nl()
|
|
||||||
@($2005) = 123
|
txt.print_ubhex(bankof($123456), true)
|
||||||
txt.print_ub(get_indexed_byte($2000, 5))
|
txt.spc()
|
||||||
|
txt.print_ubhex(msw($123456), true)
|
||||||
|
txt.spc()
|
||||||
|
txt.print_ubhex(^$123456, true)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
}
|
txt.print_uwhex(<<$1234567, true)
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uwhex(lsw($1234567), true)
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uwhex($1234567 & $ffff, true)
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
sub get_indexed_byte(uword pointer @R0, ubyte index @R1) -> ubyte {
|
txt.print_uwhex(<<$123456, true)
|
||||||
return @(cx16.r0 + cx16.r1L)
|
txt.spc()
|
||||||
|
txt.print_uwhex(lsw($123456), true)
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uwhex($123456 & $ffff, true)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user