mirror of
https://github.com/irmen/prog8.git
synced 2026-04-21 02:16:41 +00:00
make $8000000 a valid long integer (-2147483648)
This commit is contained in:
@@ -14,8 +14,11 @@ fun Number.toHex(): String {
|
||||
// larger -> "$12345678"
|
||||
// negative values are prefixed with '-'.
|
||||
val integer = this.toLong()
|
||||
if(integer<0)
|
||||
if(integer<0) {
|
||||
if(integer==-2147483648L)
|
||||
return "$80000000" // the exception to the rule, because -$80000000 is not a valid hex number
|
||||
return '-' + abs(integer).toHex()
|
||||
}
|
||||
return when (integer) {
|
||||
in 0 until 16 -> integer.toString()
|
||||
in 0 until 0x100 -> "$"+integer.toString(16).padStart(2,'0')
|
||||
|
||||
@@ -2375,7 +2375,7 @@ internal class AstChecker(private val program: Program,
|
||||
if(value.type==BaseDataType.FLOAT)
|
||||
err("integer value expected instead of float; possible loss of precision")
|
||||
val number=value.number
|
||||
if (number < -2147483647.0 || number > 2147483647.0)
|
||||
if (number < -2147483648.0 || number > 2147483647.0)
|
||||
return err("value '$number' out of range for long")
|
||||
}
|
||||
targetDt.isArray -> {
|
||||
|
||||
@@ -7,10 +7,13 @@ import io.kotest.matchers.doubles.plusOrMinus
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import prog8.code.ast.PtAssignment
|
||||
import prog8.code.ast.PtNumber
|
||||
import prog8.code.core.InternalCompilerException
|
||||
import prog8.code.core.toHex
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.Mflpt5
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8tests.helpers.ErrorReporterForTests
|
||||
import prog8tests.helpers.compileText
|
||||
|
||||
@@ -225,4 +228,35 @@ class TestNumbers: FunSpec({
|
||||
errors.errors[4] shouldContain "out of range"
|
||||
errors.errors[5] shouldContain "byte doesn't match"
|
||||
}
|
||||
|
||||
|
||||
test("biggest long numbers") {
|
||||
val src= $$"""
|
||||
main {
|
||||
sub start() {
|
||||
long @shared l1, l2
|
||||
|
||||
l1 = $7fffffff
|
||||
l2 = $80000000
|
||||
l1 = -2147483648
|
||||
l2 = -2147483649 ; will be truncated
|
||||
l1 = $abcd1234
|
||||
l2 = -$7fffffff
|
||||
l1 = $80000001
|
||||
l2 = -$80
|
||||
}
|
||||
}"""
|
||||
compileText(C64Target(), false, src, outputDir) shouldNotBe null
|
||||
val result = compileText(VMTarget(), false, src, outputDir)!!
|
||||
val st = result.codegenAst!!.entrypoint()!!
|
||||
st.children.size shouldBe 13
|
||||
((st.children[4] as PtAssignment).value as PtNumber).number shouldBe 2147483647
|
||||
((st.children[5] as PtAssignment).value as PtNumber).number shouldBe -2147483648
|
||||
((st.children[6] as PtAssignment).value as PtNumber).number shouldBe -2147483648
|
||||
((st.children[7] as PtAssignment).value as PtNumber).number shouldBe 2147483647
|
||||
((st.children[8] as PtAssignment).value as PtNumber).number shouldBe -1412623820
|
||||
((st.children[9] as PtAssignment).value as PtNumber).number shouldBe -2147483647
|
||||
((st.children[10] as PtAssignment).value as PtNumber).number shouldBe -2147483647
|
||||
((st.children[11] as PtAssignment).value as PtNumber).number shouldBe -128
|
||||
}
|
||||
})
|
||||
|
||||
@@ -347,7 +347,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
in -128..127 -> BaseDataType.BYTE
|
||||
in 0..65535 -> BaseDataType.UWORD
|
||||
in -32768..32767 -> BaseDataType.WORD
|
||||
in -2147483647..2147483647 -> BaseDataType.LONG
|
||||
in -2147483648L..0xffffffffL -> BaseDataType.LONG // TODO "hack" to allow unsigned long constants to be used as values for signed longs, without needing a cast (max value)
|
||||
else -> BaseDataType.FLOAT
|
||||
}
|
||||
}
|
||||
@@ -388,7 +388,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
}
|
||||
|
||||
// TODO "hack" to allow unsigned long constants to be used as values for signed longs, without needing a cast
|
||||
if(integer.second.isLong && integer.first > Integer.MAX_VALUE) {
|
||||
if(integer.second.isLong && integer.first > Integer.MAX_VALUE && integer.first <= 0xffffffff) {
|
||||
val signedLong = integer.first.toLong().toInt()
|
||||
return NumericLiteral(integer.second, signedLong.toDouble(), ctx.toPosition())
|
||||
}
|
||||
|
||||
@@ -687,8 +687,12 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed
|
||||
in -128..127 -> NumericLiteral(BaseDataType.BYTE, dvalue, position)
|
||||
in 0..65535 -> NumericLiteral(BaseDataType.UWORD, dvalue, position)
|
||||
in -32768..32767 -> NumericLiteral(BaseDataType.WORD, dvalue, position)
|
||||
in -2147483647..2147483647 -> NumericLiteral(BaseDataType.LONG, dvalue, position)
|
||||
else -> NumericLiteral(BaseDataType.FLOAT, dvalue, position)
|
||||
else -> {
|
||||
if(dvalue in -2147483648.0 .. 2147483647.0)
|
||||
NumericLiteral(BaseDataType.LONG, dvalue, position)
|
||||
else
|
||||
NumericLiteral(BaseDataType.FLOAT, dvalue, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ Weird Heisenbug
|
||||
|
||||
Future Things and Ideas
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- make $8000000 a valid long integer (-2147483648) this is more involved than you think. To make this work: long \|= $80000000
|
||||
- when implementing unsigned longs: remove the (mulitple) "TODO "hack" to allow unsigned long constants to be used as values for signed longs, without needing a cast"
|
||||
- implement rest of long comparisons in IfElseAsmGen compareLongValues(): expressions operands that might clobber the R14-R15 registers... (github issue 196?)
|
||||
- struct/ptr: implement the remaining TODOs in PointerAssignmentsGen.
|
||||
- struct/ptr: optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0
|
||||
|
||||
@@ -225,7 +225,7 @@ value datatype
|
||||
0 .. 255 ubyte
|
||||
-32768 .. 32767 word
|
||||
0 .. 65535 uword
|
||||
-2147483647 .. 2147483647 long (there is no unsigned long right now)
|
||||
-2147483648 .. 2147483647 long (there is no unsigned long right now)
|
||||
========================= =================
|
||||
|
||||
Numeric expressions usually 'stay within their type' unless a cast is used, see :ref:`arithmetic`.
|
||||
|
||||
+55
-38
@@ -4,55 +4,72 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
long @shared l
|
||||
long @shared l1, l2
|
||||
|
||||
;l = 2147483648
|
||||
|
||||
l = $21111111
|
||||
testdec(l)
|
||||
l = $20000000
|
||||
testdec(l)
|
||||
l = 4026531840
|
||||
testdec(l)
|
||||
txt.nl()
|
||||
|
||||
l = $21111111
|
||||
testinc(l)
|
||||
l = $2fffffff
|
||||
testinc(l)
|
||||
}
|
||||
|
||||
sub testdec(long l) {
|
||||
txt.print_ulhex(l, true)
|
||||
l1 = $7fffffff
|
||||
txt.print_ulhex(l1, true)
|
||||
txt.spc()
|
||||
txt.print_l(l)
|
||||
txt.print_l(l1)
|
||||
txt.nl()
|
||||
|
||||
l++
|
||||
txt.print_ulhex(l, true)
|
||||
l2 = $80000000
|
||||
txt.print_ulhex(l2, true)
|
||||
txt.spc()
|
||||
txt.print_l(l)
|
||||
txt.print_l(l2)
|
||||
txt.nl()
|
||||
|
||||
l--
|
||||
l--
|
||||
txt.print_ulhex(l, true)
|
||||
l1 = -2147483648
|
||||
txt.print_ulhex(l1, true)
|
||||
txt.spc()
|
||||
txt.print_l(l)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub testinc(long l) {
|
||||
txt.print_ulhex(l, true)
|
||||
txt.spc()
|
||||
txt.print_l(l)
|
||||
txt.print_l(l1)
|
||||
txt.nl()
|
||||
|
||||
l++
|
||||
txt.print_ulhex(l, true)
|
||||
l2 = -2147483649 ; will be truncated
|
||||
txt.print_ulhex(l2, true)
|
||||
txt.spc()
|
||||
txt.print_l(l)
|
||||
txt.print_l(l2)
|
||||
txt.nl()
|
||||
|
||||
l1 = $abcd1234
|
||||
txt.print_ulhex(l1, true)
|
||||
txt.spc()
|
||||
txt.print_l(l1)
|
||||
txt.nl()
|
||||
|
||||
l2 = -$7fffffff
|
||||
txt.print_ulhex(l2, true)
|
||||
txt.spc()
|
||||
txt.print_l(l2)
|
||||
txt.nl()
|
||||
|
||||
l1 = $80000001
|
||||
txt.print_ulhex(l1, true)
|
||||
txt.spc()
|
||||
txt.print_l(l1)
|
||||
txt.nl()
|
||||
|
||||
l2 = -$80
|
||||
txt.print_ulhex(l2, true)
|
||||
txt.spc()
|
||||
txt.print_l(l2)
|
||||
txt.nl()
|
||||
|
||||
l2 ^= $80000000
|
||||
txt.print_ulhex(l2, true)
|
||||
txt.spc()
|
||||
txt.print_l(l2)
|
||||
txt.nl()
|
||||
|
||||
l2 = $80
|
||||
txt.print_ulhex(l2, true)
|
||||
txt.spc()
|
||||
txt.print_l(l2)
|
||||
txt.nl()
|
||||
|
||||
l2 |= $80000000
|
||||
txt.print_ulhex(l2, true)
|
||||
txt.spc()
|
||||
txt.print_l(l2)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
dt.isBool -> constant.value.toInt().toString()
|
||||
dt.isFloat -> constant.value.toString()
|
||||
dt.isPointer -> TODO("constant pointer $constant")
|
||||
dt.isInteger -> constant.value.toInt().toHex()
|
||||
dt.isInteger -> constant.value.toLong().toHex()
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
xml.writeCharacters("${constant.typeString} ${constant.name}=$value\n")
|
||||
|
||||
@@ -921,7 +921,7 @@ data class IRInstruction(
|
||||
when (type) {
|
||||
IRDataType.BYTE -> require(immediate in -128..255) { "immediate value out of range for byte: $immediate" }
|
||||
IRDataType.WORD -> require(immediate in -32768..65535) { "immediate value out of range for word: $immediate" }
|
||||
IRDataType.LONG -> require(immediate in -2147483647..2147483647) { "immediate value out of range for long: $immediate" }
|
||||
IRDataType.LONG -> require(immediate in -2147483648..2147483647) { "immediate value out of range for long: $immediate" }
|
||||
IRDataType.FLOAT, null -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,11 +64,11 @@ fun parseIRValue(value: String): Double {
|
||||
return if(value.startsWith("-"))
|
||||
-parseIRValue(value.substring(1))
|
||||
else if(value.startsWith('$'))
|
||||
value.substring(1).toInt(16).toDouble()
|
||||
value.substring(1).toLong(16).toDouble()
|
||||
else if(value.startsWith('%'))
|
||||
value.substring(1).toInt(2).toDouble()
|
||||
value.substring(1).toLong(2).toDouble()
|
||||
else if(value.startsWith("0x"))
|
||||
value.substring(2).toInt(16).toDouble()
|
||||
value.substring(2).toLong(16).toDouble()
|
||||
else if(value.startsWith('_'))
|
||||
throw IRParseException("attempt to parse a label as numeric value")
|
||||
else if(value.startsWith('&'))
|
||||
@@ -154,7 +154,13 @@ fun parseIRCodeLine(line: String): Either<IRInstruction, String> {
|
||||
if (immediateInt == null && immediateFp == null) {
|
||||
if (type == IRDataType.FLOAT && opcode != Opcode.LOADFIELD && opcode != Opcode.STOREFIELD)
|
||||
immediateFp = value
|
||||
else
|
||||
else if(type == IRDataType.LONG) {
|
||||
val immediateLong = value.toLong()
|
||||
if(immediateLong == 0x80000000L) {
|
||||
immediateInt = -2147483648
|
||||
} else
|
||||
immediateInt = immediateLong.toInt()
|
||||
} else
|
||||
immediateInt = value.toInt()
|
||||
} else {
|
||||
address = value.toInt()
|
||||
@@ -210,7 +216,7 @@ fun parseIRCodeLine(line: String): Either<IRInstruction, String> {
|
||||
throw IRParseException("immediate value out of range for word: $immediateInt")
|
||||
}
|
||||
IRDataType.LONG -> {
|
||||
if (immediateInt!=null && immediateInt < -2147483647)
|
||||
if (immediateInt!=null && (immediateInt.toLong() < -2147483648L || immediateInt.toLong() > 0x7fffffffL))
|
||||
throw IRParseException("immediate value out of range for long: $immediateInt")
|
||||
}
|
||||
IRDataType.FLOAT -> {}
|
||||
|
||||
@@ -348,7 +348,7 @@ class PtNumber(type: BaseDataType, val number: Double, position: Position) : PtE
|
||||
BaseDataType.BYTE -> require(number in -128.0..127.0)
|
||||
BaseDataType.UWORD -> require(number in 0.0..65535.0)
|
||||
BaseDataType.WORD -> require(number in -32768.0..32767.0)
|
||||
BaseDataType.LONG -> require(number in -2147483647.0..2147483647.0)
|
||||
BaseDataType.LONG -> require(number in -2147483648.0..2147483647.0)
|
||||
else -> require(type.isNumeric) { "numeric literal type should be numeric: $type" }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user