'hack' to allow unsigned long constants such as $ffffffff to be assigned to longs without casts

This commit is contained in:
Irmen de Jong
2025-10-20 00:33:40 +02:00
parent e5939be0bd
commit ebc738b132
6 changed files with 90 additions and 43 deletions

View File

@@ -58,9 +58,9 @@ What does Prog8 provide?
- all advantages of a higher level language over having to write assembly code manually - all advantages of a higher level language over having to write assembly code manually
- programs run very fast because it's compiled to native machine code - programs run very fast because it's compiled to native machine code
- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS - compiled code is very small; much smaller than equivalent C code compiled with CC65, and usually runs faster as well
- modularity, symbol scoping, subroutines. No need for forward declarations. - modularity, symbol scoping, subroutines. No need for forward declarations.
- various data types other than just bytes (16-bit words, floats, strings) - various data types other than just bytes (16-bit words, long integers, floats, strings)
- Structs and typed pointers - Structs and typed pointers
- floating point math is supported on certain targets - floating point math is supported on certain targets
- access to most Kernal ROM routines as external subroutine definitions you can call normally - access to most Kernal ROM routines as external subroutine definitions you can call normally
@@ -82,7 +82,7 @@ What does Prog8 provide?
- supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16 (also available on other targets) - supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16 (also available on other targets)
- encode strings and characters into petscii or screencodes or even other encodings - encode strings and characters into petscii or screencodes or even other encodings
- Automatic ROM/RAM bank switching on certain compiler targets when calling routines in other banks - Automatic ROM/RAM bank switching on certain compiler targets when calling routines in other banks
- 50 Kb of available program RAM size on the C64 by default; because Basic ROM is banked out altogether - 50 Kb of available program RAM size on the C64 by default (41 Kb on the C128) because Basic ROM is banked out by default
*Rapid edit-compile-run-debug cycle:* *Rapid edit-compile-run-debug cycle:*

View File

@@ -132,7 +132,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
expr)) expr))
} }
if(rightCv!=null && rightCv.number<0) { if(rightCv!=null && rightCv.number<0) {
val value = if(leftDt.isBytes) 256+rightCv.number else if(leftDt.isWords) 65536+rightCv.number else 0xffffffffL+rightCv.number val value = if(leftDt.isBytes) 256+rightCv.number else if(leftDt.isWords) 65536+rightCv.number else (0x100000000L+rightCv.number).toLong().toInt().toDouble()
return listOf(IAstModification.ReplaceNode( return listOf(IAstModification.ReplaceNode(
expr.right, expr.right,
NumericLiteral(leftDt.getOrUndef().base, value, expr.right.position), NumericLiteral(leftDt.getOrUndef().base, value, expr.right.position),

View File

@@ -17,6 +17,7 @@ import prog8.code.core.BaseDataType
import prog8.code.core.Position import prog8.code.core.Position
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8.code.target.Cx16Target import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget
import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText import prog8tests.helpers.compileText
@@ -464,4 +465,34 @@ main {
}""" }"""
compileText(Cx16Target(), true, src, outputDir, writeAssembly = false) shouldNotBe null compileText(Cx16Target(), true, src, outputDir, writeAssembly = false) shouldNotBe null
} }
test("const long with large unsigned long values should be converted to signed longs") {
val src = $$"""
main {
sub start() {
long @shared l1 = $e1fa84c6
long @shared l2 = -1
long @shared l3 = $ffffffff
long @shared l4 = $7fffffff
l1 ^= -1
l2 ^= $ffffffff
l3 ^= $7fffffff
}
}"""
compileText(Cx16Target(), true, src, outputDir, writeAssembly = false) shouldNotBe null
val result = compileText(VMTarget(), true, src, outputDir, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 12
val a = st.filterIsInstance<Assignment>()
(a[0].value as NumericLiteral).number shouldBe -503675706.0
(a[1].value as NumericLiteral).number shouldBe -1.0
(a[2].value as NumericLiteral).number shouldBe -1.0
(a[3].value as NumericLiteral).number shouldBe 0x7fffffffL.toDouble()
((a[4].value as BinaryExpression).right as NumericLiteral).number shouldBe -1.0
((a[5].value as BinaryExpression).right as NumericLiteral).number shouldBe -1.0
((a[6].value as BinaryExpression).right as NumericLiteral).number shouldBe 0x7fffffffL.toDouble()
}
}) })

View File

@@ -385,6 +385,13 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
BIN_INTEGER -> makeLiteral(integerPart.substring(1), 2) BIN_INTEGER -> makeLiteral(integerPart.substring(1), 2)
else -> throw FatalAstException(terminal.text) else -> throw FatalAstException(terminal.text)
} }
// 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) {
val signedLong = integer.first.toLong().toInt()
return NumericLiteral(integer.second, signedLong.toDouble(), ctx.toPosition())
}
return NumericLiteral(integer.second, integer.first, ctx.toPosition()) return NumericLiteral(integer.second, integer.first, ctx.toPosition())
} }

View File

@@ -69,7 +69,7 @@ Language Features
- it is a cross-compiler running on modern machines (Linux, MacOS, Windows, ...) - it is a cross-compiler running on modern machines (Linux, MacOS, Windows, ...)
- the compiled programs run very fast, because compilation to highly efficient native machine code. - the compiled programs run very fast, because compilation to highly efficient native machine code.
- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS - compiled code is very compact; it is much smaller and usually also runs faster than equivalent C code compiled with CC65
- provides a convenient and fast edit/compile/run cycle by being able to directly launch - provides a convenient and fast edit/compile/run cycle by being able to directly launch
the compiled program in an emulator and provide debugging information to this emulator. the compiled program in an emulator and provide debugging information to this emulator.
- the language looks like a mix of Python and C so should be quite easy to learn - the language looks like a mix of Python and C so should be quite easy to learn
@@ -78,7 +78,7 @@ Language Features
still able to directly use memory addresses and ROM subroutines, still able to directly use memory addresses and ROM subroutines,
and inline assembly to have full control when every register, cycle or byte matters and inline assembly to have full control when every register, cycle or byte matters
- Variables are all allocated statically, no memory allocation overhead - Variables are all allocated statically, no memory allocation overhead
- Variable data types include signed and unsigned bytes and words, arrays, strings. - Variable data types include signed and unsigned bytes and words, long integers, floats, arrays, and strings.
- Structs and typed pointers - Structs and typed pointers
- Tight control over Zeropage usage - Tight control over Zeropage usage
- Programs can be restarted after exiting (i.e. run them multiple times without having to reload everything), due to automatic variable (re)initializations. - Programs can be restarted after exiting (i.e. run them multiple times without having to reload everything), due to automatic variable (re)initializations.

View File

@@ -9,22 +9,31 @@ main {
} }
sub start() { sub start() {
long @shared l1 = $e1fa84c6
long @shared l2 = -1
long @shared l3 = $ffffffff
long @shared l4 = $7fffffff
l1 ^= -1
l2 ^= $ffffffff
l3 ^= $7fffffff
; cx16.r5L = 10 ; cx16.r5L = 10
; txt.print_l(cx16.r5L as long * $2000) ; txt.print_l(cx16.r5L as long * $2000)
; txt.spc() ; txt.spc()
; txt.print_l(($2000 as long) * cx16.r5L) ; TODO fix long result? or wait till the long consts have landed? ; txt.print_l(($2000 as long) * cx16.r5L) ; TODO fix long result? or wait till the long consts have landed?
; txt.nl() ; txt.nl()
; ^^element myElement = $6000
^^element myElement = $6000 ; myElement.y = $12345678
myElement.y = $12345678 ; long @shared lv = $10101010
long @shared lv = $10101010 ; cx16.r0 = $ffff
cx16.r0 = $ffff ;
; myElement.y += lv+cx16.r0
myElement.y += lv+cx16.r0 ; txt.print_ulhex(myElement.y, true)
txt.print_ulhex(myElement.y, true) ; txt.spc()
txt.spc() ; myElement.y -= lv+cx16.r0
myElement.y -= lv+cx16.r0 ; txt.print_ulhex(myElement.y, true)
txt.print_ulhex(myElement.y, true)
} }
} }