Merge branch 'refs/heads/master' into structs

# Conflicts:
#	codeCore/src/prog8/code/target/NormalMemSizer.kt
#	codeCore/src/prog8/code/target/VMTarget.kt
#	compiler/src/prog8/compiler/BuiltinFunctions.kt
#	compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt
#	examples/test.p8
This commit is contained in:
Irmen de Jong
2025-05-29 13:39:42 +02:00
22 changed files with 198 additions and 125 deletions
@@ -27,7 +27,7 @@ internal class NormalMemSizer(val floatsize: Int): IMemSizer {
return when {
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> floatsize * (numElements ?: 1)
dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory")
dt.isLong -> 4 * (numElements ?: 1)
dt.isPointer -> 2 // pointer is just a uword
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
else -> 2 * (numElements ?: 1)
@@ -91,39 +91,6 @@ class VMTarget: ICompilationTarget,
zeropage = VirtualZeropage(compilerOptions)
golden = GoldenRam(compilerOptions, UIntRange.EMPTY)
}
override fun memorySize(dt: DataType, numElements: Int?): Int {
if(dt.isPointerArray)
return 2 * numElements!! // array of pointers is just array of uwords
else if(dt.isArray) {
if(numElements==null) return 2 // treat it as a pointer size
return when(dt.sub) {
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2
BaseDataType.FLOAT-> numElements * FLOAT_MEM_SIZE
BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size")
else -> {
if(dt.subType!=null)
TODO("support arrays with struct instances as sub-type")
throw IllegalArgumentException("invalid sub type")
}
}
}
else if (dt.isString) {
return numElements // treat it as the size of the given string with the length
?: 2 // treat it as the size to store a string pointer
}
return when {
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> FLOAT_MEM_SIZE * (numElements ?: 1)
dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory")
dt.isPointer -> 2 // pointer is just a uword
dt.isStructInstance -> TODO("memory size of struct instances")
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
else -> 2 * (numElements ?: 1)
}
}
}
@@ -16,12 +16,6 @@ class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
override val SCRATCH_W2 = 0xfdu // temp storage 2 for a word $fd+$fe
init {
if (options.floats) {
throw InternalCompilerException("C128 target doesn't yet support floating point routines")
// note: in git commit labeled 'c128: remove floats module' the floats.p8 and floats.asm files are removed,
// they could be retrieved again at a later time if the compiler somehow *does* store the fp variables in bank1.
}
if (options.floats && options.zeropage !in arrayOf(
ZeropageType.FLOATSAFE,
ZeropageType.BASICSAFE,
@@ -16,10 +16,6 @@ class PETZeropage(options: CompilationOptions) : Zeropage(options) {
override val SCRATCH_W2 = 0xb8u // temp storage 2 for a word
init {
if (options.floats) {
throw InternalCompilerException("PET target doesn't yet support floating point routines")
}
if (options.floats && options.zeropage !in arrayOf(
ZeropageType.FLOATSAFE,
ZeropageType.BASICSAFE,
@@ -988,7 +988,7 @@ internal class AssignmentAsmGen(
if(!directIntoY(expr.right)) asmgen.out(" pha")
assignExpressionToRegister(expr.right, RegisterOrPair.Y, false)
if(!directIntoY(expr.right)) asmgen.out(" pla")
asmgen.out(" jsr prog8_math.divmod_ub_asm")
asmgen.out(" jsr prog8_math.remainder_ub_asm")
if(target.register==RegisterOrPair.A)
asmgen.out(" cmp #0") // fix the status register
else
@@ -920,7 +920,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
"-" -> asmgen.out(" sec | sbc $otherName")
"*" -> asmgen.out(" ldy $otherName | jsr prog8_math.multiply_bytes")
"/" -> asmgen.out(" ldy $otherName | jsr prog8_math.divmod_ub_asm | tya")
"%" -> asmgen.out(" ldy $otherName | jsr prog8_math.divmod_ub_asm")
"%" -> asmgen.out(" ldy $otherName | jsr prog8_math.remainder_ub_asm")
"<<" -> {
asmgen.out("""
ldy $otherName
@@ -1029,7 +1029,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
val sourceName = asmgen.loadByteFromPointerIntoA(pointervar)
if(value==0)
throw AssemblyError("division by zero")
asmgen.out(" ldy #$value | jsr prog8_math.divmod_ub_asm")
asmgen.out(" ldy #$value | jsr prog8_math.remainder_ub_asm")
asmgen.storeAIntoZpPointerVar(sourceName, false)
}
"<<" -> {
@@ -1207,7 +1207,7 @@ $shortcutLabel:""")
"%" -> {
if(signed)
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
asmgen.out(" ldy $variable | jsr prog8_math.divmod_ub_asm")
asmgen.out(" ldy $variable | jsr prog8_math.remainder_ub_asm")
}
"<<" -> {
asmgen.out("""
@@ -1380,7 +1380,7 @@ $shortcutLabel:""")
"%" -> {
if(signed)
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
asmgen.out(" tay | lda $variable | jsr prog8_math.divmod_ub_asm")
asmgen.out(" tay | lda $variable | jsr prog8_math.remainder_ub_asm")
}
"<<" -> {
asmgen.out("""
@@ -1551,7 +1551,7 @@ $shortcutLabel:""")
asmgen.out("""
lda $name
ldy #$value
jsr prog8_math.divmod_ub_asm
jsr prog8_math.remainder_ub_asm
sta $name""")
}
"<<" -> {
+7 -6
View File
@@ -419,12 +419,13 @@ sys {
const ubyte target = 128 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502
const ubyte SIZEOF_BOOL = 1
const ubyte SIZEOF_BYTE = 1
const ubyte SIZEOF_UBYTE = 1
const ubyte SIZEOF_WORD = 2
const ubyte SIZEOF_UWORD = 2
const ubyte SIZEOF_FLOAT = 5
const ubyte SIZEOF_BOOL = sizeof(bool)
const ubyte SIZEOF_BYTE = sizeof(byte)
const ubyte SIZEOF_UBYTE = sizeof(ubyte)
const ubyte SIZEOF_WORD = sizeof(word)
const ubyte SIZEOF_UWORD = sizeof(uword)
const ubyte SIZEOF_LONG = sizeof(long)
const ubyte SIZEOF_FLOAT = sizeof(float)
const byte MIN_BYTE = -128
const byte MAX_BYTE = 127
const ubyte MIN_UBYTE = 0
+7 -6
View File
@@ -439,12 +439,13 @@ sys {
const ubyte target = 64 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502
const ubyte SIZEOF_BOOL = 1
const ubyte SIZEOF_BYTE = 1
const ubyte SIZEOF_UBYTE = 1
const ubyte SIZEOF_WORD = 2
const ubyte SIZEOF_UWORD = 2
const ubyte SIZEOF_FLOAT = 5
const ubyte SIZEOF_BOOL = sizeof(bool)
const ubyte SIZEOF_BYTE = sizeof(byte)
const ubyte SIZEOF_UBYTE = sizeof(ubyte)
const ubyte SIZEOF_WORD = sizeof(word)
const ubyte SIZEOF_UWORD = sizeof(uword)
const ubyte SIZEOF_LONG = sizeof(long)
const ubyte SIZEOF_FLOAT = sizeof(float)
const byte MIN_BYTE = -128
const byte MAX_BYTE = 127
const ubyte MIN_UBYTE = 0
+7 -6
View File
@@ -1515,12 +1515,13 @@ sys {
const ubyte target = 16 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502
const ubyte SIZEOF_BOOL = 1
const ubyte SIZEOF_BYTE = 1
const ubyte SIZEOF_UBYTE = 1
const ubyte SIZEOF_WORD = 2
const ubyte SIZEOF_UWORD = 2
const ubyte SIZEOF_FLOAT = 5
const ubyte SIZEOF_BOOL = sizeof(bool)
const ubyte SIZEOF_BYTE = sizeof(byte)
const ubyte SIZEOF_UBYTE = sizeof(ubyte)
const ubyte SIZEOF_WORD = sizeof(word)
const ubyte SIZEOF_UWORD = sizeof(uword)
const ubyte SIZEOF_LONG = sizeof(long)
const ubyte SIZEOF_FLOAT = sizeof(float)
const byte MIN_BYTE = -128
const byte MAX_BYTE = 127
const ubyte MIN_UBYTE = 0
+22
View File
@@ -241,6 +241,28 @@ divmod_ub_asm .proc
rts
.pend
remainder_ub_asm .proc
; -- divide A by Y, returns remainder in A (unsigned)
; division by zero will result in just the original number.
; This routine specialcases 0,1,2 and otherwise is just a repeated subtraction.
cpy #0
beq _zero
cpy #1
bne +
lda #0
rts
+ cpy #2
bne +
and #1
rts
+ sty P8ZP_SCRATCH_REG
sec
- sbc P8ZP_SCRATCH_REG
bcs -
adc P8ZP_SCRATCH_REG
_zero rts
.pend
divmod_w_asm .proc
; signed word division: make everything positive and fix sign afterwards
sta P8ZP_SCRATCH_W2
+7 -6
View File
@@ -98,12 +98,13 @@ sys {
const ubyte target = 32 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502
const ubyte SIZEOF_BOOL = 1
const ubyte SIZEOF_BYTE = 1
const ubyte SIZEOF_UBYTE = 1
const ubyte SIZEOF_WORD = 2
const ubyte SIZEOF_UWORD = 2
const ubyte SIZEOF_FLOAT = 0 ; undefined, no floats supported
const ubyte SIZEOF_BOOL = sizeof(bool)
const ubyte SIZEOF_BYTE = sizeof(byte)
const ubyte SIZEOF_UBYTE = sizeof(ubyte)
const ubyte SIZEOF_WORD = sizeof(word)
const ubyte SIZEOF_UWORD = sizeof(uword)
const ubyte SIZEOF_LONG = sizeof(long)
const ubyte SIZEOF_FLOAT = sizeof(float)
const byte MIN_BYTE = -128
const byte MAX_BYTE = 127
const ubyte MIN_UBYTE = 0
+7 -6
View File
@@ -7,12 +7,13 @@ sys {
const ubyte target = 255 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502
const ubyte SIZEOF_BOOL = 1
const ubyte SIZEOF_BYTE = 1
const ubyte SIZEOF_UBYTE = 1
const ubyte SIZEOF_WORD = 2
const ubyte SIZEOF_UWORD = 2
const ubyte SIZEOF_FLOAT = 8
const ubyte SIZEOF_BOOL = sizeof(bool)
const ubyte SIZEOF_BYTE = sizeof(byte)
const ubyte SIZEOF_UBYTE = sizeof(ubyte)
const ubyte SIZEOF_WORD = sizeof(word)
const ubyte SIZEOF_UWORD = sizeof(uword)
const ubyte SIZEOF_LONG = sizeof(long)
const ubyte SIZEOF_FLOAT = sizeof(float)
const byte MIN_BYTE = -128
const byte MAX_BYTE = 127
const ubyte MIN_UBYTE = 0
@@ -115,6 +115,19 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
else -> NumericLiteral(BaseDataType.UBYTE, program.memsizer.memorySize(dt.getOrUndef(), null).toDouble(), position)
}
} else {
val identifier = args[0] as? IdentifierReference
if(identifier?.nameInSource?.size==1) {
when(identifier.nameInSource[0]) {
"ubyte" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.UBYTE), position)
"byte" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.BYTE), position)
"uword" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.UWORD), position)
"word" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.WORD), position)
"long" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.LONG), position)
"float" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.FLOAT), position)
"bool" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.BOOL), position)
}
}
// the argument could refer to a struct declaration
val struct = (args[0] as? IdentifierReference)?.targetStructDecl()
if(struct!=null) {
@@ -5,7 +5,9 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.code.core.*
import prog8.code.target.C128Target
import prog8.code.target.Cx16Target
import prog8.code.target.PETTarget
import prog8.code.target.VMTarget
import prog8.compiler.builtinFunctionReturnType
import java.io.CharConversionException
@@ -832,6 +834,9 @@ internal class AstChecker(private val program: Program,
// FLOATS enabled?
if(!compilerOptions.floats && (decl.datatype.isFloat || decl.datatype.isFloatArray) && decl.type != VarDeclType.MEMORY)
err("floating point used, but that is not enabled via options")
else if(compilerOptions.compTarget.name in arrayOf(PETTarget.NAME, C128Target.NAME) && decl.type != VarDeclType.CONST && (decl.datatype.isFloat || decl.datatype.isFloatArray)) {
err("pet32 and c128 target do not support floating point numbers yet")
}
// ARRAY without size specifier MUST have an iterable initializer value
if(decl.isArray && decl.arraysize==null) {
+5 -3
View File
@@ -388,12 +388,13 @@ class TestMemory: FunSpec({
shouldThrow<IllegalArgumentException> {
target.memorySize(BaseDataType.UNDEFINED)
}
shouldThrow<IllegalArgumentException> {
target.memorySize(BaseDataType.LONG)
shouldThrow<NoSuchElementException> {
target.memorySize(DataType.arrayFor(BaseDataType.LONG), 10)
}
target.memorySize(BaseDataType.BOOL) shouldBe 1
target.memorySize(BaseDataType.BYTE) shouldBe 1
target.memorySize(BaseDataType.WORD) shouldBe 2
target.memorySize(BaseDataType.LONG) shouldBe 4
target.memorySize(BaseDataType.FLOAT) shouldBe target.FLOAT_MEM_SIZE
target.memorySize(DataType.BOOL, null) shouldBe 1
@@ -409,13 +410,14 @@ class TestMemory: FunSpec({
target.memorySize(DataType.arrayFor(BaseDataType.BOOL), 10) shouldBe 10
target.memorySize(DataType.arrayFor(BaseDataType.BYTE), 10) shouldBe 10
target.memorySize(DataType.arrayFor(BaseDataType.WORD), 10) shouldBe 20
target.memorySize(DataType.arrayFor(BaseDataType.WORD), 10) shouldBe 20
target.memorySize(DataType.arrayFor(BaseDataType.UWORD), 10) shouldBe 20
target.memorySize(DataType.arrayFor(BaseDataType.FLOAT), 10) shouldBe 10*target.FLOAT_MEM_SIZE
target.memorySize(DataType.arrayFor(BaseDataType.WORD, true), 10) shouldBe 20
target.memorySize(DataType.arrayFor(BaseDataType.UWORD, true), 10) shouldBe 20
target.memorySize(DataType.BOOL, 10) shouldBe 10
target.memorySize(DataType.UWORD, 10) shouldBe 20
target.memorySize(DataType.LONG, 10) shouldBe 40
target.memorySize(DataType.FLOAT, 10) shouldBe 10*target.FLOAT_MEM_SIZE
}
}
+43
View File
@@ -1062,4 +1062,47 @@ main {
st.size shouldBe 3
}
test("allow type name as argument for sizeof()") {
val src="""
%option enable_floats
main {
sub start() {
bool @shared b
float @shared f
word @shared w
const long ll = 9999999
ubyte @shared ub1, ub2
ub1 = sys.SIZEOF_BOOL
ub2 = sys.SIZEOF_WORD
ub1 = sys.SIZEOF_LONG
ub2 = sys.SIZEOF_FLOAT
ub1 = sizeof(true)
ub2 = sizeof(1234)
ub1 = sizeof(12345678)
ub2 = sizeof(9.999)
ub1 = sizeof(b)
ub2 = sizeof(w)
ub1 = sizeof(ll)
ub2 = sizeof(f)
ub1 = sizeof(bool)
ub2 = sizeof(word)
ub1 = sizeof(long)
ub2 = sizeof(float)
}
}"""
val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 27
val assignments = st.dropLast(1).takeLast(16)
assignments.forEach { a ->
(a as Assignment).value shouldBe instanceOf<NumericLiteral>()
}
}
})
@@ -659,6 +659,17 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi
return IfExpression(condition.toAst(), truevalue.toAst(), falsevalue.toAst(), toPosition())
}
if(sizeof_expression!=null) {
val datatype = sizeof_argument().basedatatype()?.toAst()
val expression = sizeof_argument().expression()?.toAst()
val sizeof = IdentifierReference(listOf("sizeof"), toPosition())
val arg = if(expression!=null) expression else {
require(datatype!=null)
IdentifierReference(listOf(datatype.name.lowercase()), toPosition())
}
return FunctionCallExpression(sizeof, mutableListOf(arg), toPosition())
}
val deref = pointerdereference()?.toAst()
if(deref!=null) return deref
+3 -4
View File
@@ -178,10 +178,9 @@ setlsb (x, value)
setmsb (x, value)
Sets the most significant byte of word variable x to a new value. Leaves the LSB untouched.
sizeof (name) ; sizeof (number)
Number of bytes that the object 'name', or the number 'number' occupies in memory.
This is a constant determined by the data type of
the object. For instance, for a variable of type uword, the sizeof is 2.
sizeof (name) ; sizeof (number) ; sizeof(datatype)
The constant number of bytes that the object 'name', the number 'number' or the type 'datatype' occupies in memory.
For instance, for a variable of type uword, the sizeof is 2.
For an 10 element array of floats, it is 50 (on the C64, where a float is 5 bytes).
Note: usually you will be interested in the number of elements in an array, use len() for that.
@@ -23,12 +23,13 @@ sys {
const ubyte target = 8 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502
const ubyte SIZEOF_BOOL = 1
const ubyte SIZEOF_BYTE = 1
const ubyte SIZEOF_UBYTE = 1
const ubyte SIZEOF_WORD = 2
const ubyte SIZEOF_UWORD = 2
const ubyte SIZEOF_FLOAT = 0 ; undefined, no float support
const ubyte SIZEOF_BOOL = sizeof(bool)
const ubyte SIZEOF_BYTE = sizeof(byte)
const ubyte SIZEOF_UBYTE = sizeof(ubyte)
const ubyte SIZEOF_WORD = sizeof(word)
const ubyte SIZEOF_UWORD = sizeof(uword)
const ubyte SIZEOF_LONG = sizeof(long)
const ubyte SIZEOF_FLOAT = 0 ; undefined, no floats supported
const byte MIN_BYTE = -128
const byte MAX_BYTE = 127
const ubyte MIN_UBYTE = 0
@@ -15,11 +15,12 @@ sys {
const ubyte target = 7 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502
const ubyte SIZEOF_BOOL = 1
const ubyte SIZEOF_BYTE = 1
const ubyte SIZEOF_UBYTE = 1
const ubyte SIZEOF_WORD = 2
const ubyte SIZEOF_UWORD = 2
const ubyte SIZEOF_BOOL = sizeof(bool)
const ubyte SIZEOF_BYTE = sizeof(byte)
const ubyte SIZEOF_UBYTE = sizeof(ubyte)
const ubyte SIZEOF_WORD = sizeof(word)
const ubyte SIZEOF_UWORD = sizeof(uword)
const ubyte SIZEOF_LONG = sizeof(long)
const ubyte SIZEOF_FLOAT = 0 ; undefined, no floats supported
const byte MIN_BYTE = -128
const byte MAX_BYTE = 127
+36 -27
View File
@@ -1,39 +1,48 @@
%option enable_floats
%import textio
%import floats
%zeropage basicsafe
main {
^^byte @shared sbptr
^^ubyte @shared ubptr
^^bool @shared bptr
^^word @shared wptr
^^float @shared fptr
struct List {
ubyte value
^^List next
}
sub start() {
^^List l1 = 1000
^^List l2 = 1100
bool @shared b
float @shared f
word @shared w
const long ll = 9999999
txt.print_ub(sizeof(List))
txt.print_ub(sys.SIZEOF_BOOL)
txt.spc()
; txt.print_ub(sizeof(l1^^)
; txt.nl()
txt.print_ub(sizeof(bptr))
txt.print_ub(sys.SIZEOF_WORD)
txt.spc()
txt.print_ub(sizeof(wptr))
txt.print_ub(sys.SIZEOF_LONG)
txt.spc()
txt.print_ub(sizeof(fptr))
txt.print_ub(sys.SIZEOF_FLOAT)
txt.nl()
; txt.print_ub(sizeof(bptr^^))
; txt.spc()
; txt.print_ub(sizeof(wptr^^))
; txt.spc()
; txt.print_ub(sizeof(fptr^^))
; txt.nl()
txt.print_ub(sizeof(true))
txt.spc()
txt.print_ub(sizeof(1234))
txt.spc()
txt.print_ub(sizeof(12345678))
txt.spc()
txt.print_ub(sizeof(9.999))
txt.nl()
txt.print_ub(sizeof(b))
txt.spc()
txt.print_ub(sizeof(w))
txt.spc()
txt.print_ub(sizeof(ll))
txt.spc()
txt.print_ub(sizeof(f))
txt.nl()
txt.print_ub(sizeof(bool))
txt.spc()
txt.print_ub(sizeof(word))
txt.spc()
txt.print_ub(sizeof(long))
txt.spc()
txt.print_ub(sizeof(float))
txt.nl()
}
}
+5
View File
@@ -198,6 +198,7 @@ postincrdecr : assign_target operator = ('++' | '--') ;
expression :
'(' expression ')'
| sizeof_expression = 'sizeof' '(' sizeof_argument ')'
| functioncall
| left = expression EOL? bop = '.' EOL? right = expression // "scope traversal operator"
| <assoc=right> prefix = ('+'|'-'|'~') expression
@@ -226,6 +227,10 @@ expression :
| pointerdereference
;
sizeof_argument: basedatatype | expression ;
arrayindexed:
scoped_identifier arrayindex
;