added sizeof() function

This commit is contained in:
Irmen de Jong 2020-08-20 13:50:28 +02:00
parent 774897260e
commit edfd9d55ba
7 changed files with 92 additions and 51 deletions

View File

@ -58,7 +58,7 @@ enum class DataType {
in ByteDatatypes -> 1
in WordDatatypes -> 2
FLOAT -> CompilationTarget.machine.FLOAT_MEM_SIZE
in PassByReferenceDatatypes -> 2
in PassByReferenceDatatypes -> CompilationTarget.machine.POINTER_MEM_SIZE
else -> -9999999
}
}

View File

@ -716,11 +716,10 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
override fun referencesIdentifiers(vararg name: String): Boolean = nameInSource.last() in name
override fun inferType(program: Program): InferredTypes.InferredType {
val targetStmt = targetStatement(program.namespace)
return if(targetStmt is VarDecl) {
InferredTypes.knownFor(targetStmt.datatype)
} else {
InferredTypes.InferredType.unknown()
return when (val targetStmt = targetStatement(program.namespace)) {
is VarDecl -> InferredTypes.knownFor(targetStmt.datatype)
is StructDecl -> InferredTypes.knownFor(DataType.STRUCT)
else -> InferredTypes.InferredType.unknown()
}
}

View File

@ -8,6 +8,7 @@ interface IMachineDefinition {
val FLOAT_MAX_NEGATIVE: Double
val FLOAT_MAX_POSITIVE: Double
val FLOAT_MEM_SIZE: Int
val POINTER_MEM_SIZE: Int
val opcodeNames: Set<String>

View File

@ -14,6 +14,7 @@ object C64MachineDefinition: IMachineDefinition {
override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255
override val FLOAT_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255
override val FLOAT_MEM_SIZE = 5
override val POINTER_MEM_SIZE = 2
const val BASIC_LOAD_ADDRESS = 0x0801
const val RAW_LOAD_ADDRESS = 0xc000

View File

@ -3,6 +3,8 @@ package prog8.functions
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.StructDecl
import prog8.ast.statements.VarDecl
import prog8.compiler.CompilerException
import kotlin.math.*
@ -35,6 +37,7 @@ val BuiltinFunctions = mapOf(
"sum" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinSum) }, // type depends on args
"abs" to FSignature(true, listOf(FParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument
"len" to FSignature(true, listOf(FParam("values", IterableDatatypes)), null, ::builtinLen), // type is UBYTE or UWORD depending on actual length
"sizeof" to FSignature(true, listOf(FParam("object", DataType.values().toSet())), DataType.UBYTE, ::builtinSizeof),
// normal functions follow:
"sgn" to FSignature(true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ),
"sin" to FSignature(true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sin) },
@ -240,6 +243,42 @@ private fun builtinAbs(args: List<Expression>, position: Position, program: Prog
}
}
private fun builtinSizeof(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
// 1 arg, type = anything, result type = ubyte
if(args.size!=1)
throw SyntaxError("sizeof requires one argument", position)
if(args[0] !is IdentifierReference)
throw SyntaxError("sizeof argument should be an identifier", position)
val dt = args[0].inferType(program)
if(dt.isKnown) {
val target = (args[0] as IdentifierReference).targetStatement(program.namespace)
?: throw CannotEvaluateException("sizeof", "no target")
fun structSize(target: StructDecl) =
NumericLiteralValue(DataType.UBYTE, target.statements.map { (it as VarDecl).datatype.memorySize() }.sum(), position)
return when {
dt.typeOrElse(DataType.STRUCT) in ArrayDatatypes -> {
val length = (target as VarDecl).arraysize!!.size() ?: throw CannotEvaluateException("sizeof", "unknown array size")
val elementDt = ArrayElementTypes.getValue(dt.typeOrElse(DataType.STRUCT))
numericLiteral(elementDt.memorySize() * length, position)
}
dt.istype(DataType.STRUCT) -> {
when (target) {
is VarDecl -> structSize(target.struct!!)
is StructDecl -> structSize(target)
else -> throw CompilerException("weird struct type $target")
}
}
dt.istype(DataType.STR) -> throw SyntaxError("sizeof str is undefined, did you mean len?", position)
else -> NumericLiteralValue(DataType.UBYTE, dt.typeOrElse(DataType.STRUCT).memorySize(), position)
}
} else {
throw SyntaxError("sizeof invalid argument type", position)
}
}
private fun builtinStrlen(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
throw SyntaxError("strlen requires one argument", position)
@ -262,18 +301,12 @@ private fun builtinLen(args: List<Expression>, position: Position, program: Prog
if(args[0] is ArrayLiteralValue)
return NumericLiteralValue.optimalInteger((args[0] as ArrayLiteralValue).value.size, position)
if(args[0] !is IdentifierReference)
throw SyntaxError("len argument should be an identifier, but is ${args[0]}", position)
throw SyntaxError("len argument should be an identifier", position)
val target = (args[0] as IdentifierReference).targetVarDecl(program.namespace)
?: throw CannotEvaluateException("len", "no target vardecl")
return when(target.datatype) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> {
arraySize = target.arraysize?.size()
if(arraySize==null)
throw CannotEvaluateException("len", "arraysize unknown")
NumericLiteralValue.optimalInteger(arraySize, args[0].position)
}
DataType.ARRAY_F -> {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> {
arraySize = target.arraysize?.size()
if(arraySize==null)
throw CannotEvaluateException("len", "arraysize unknown")

View File

@ -724,11 +724,17 @@ reverse(array)
len(x)
Number of values in the array value x, or the number of characters in a string (excluding the size or 0-byte).
Note: this can be different from the number of *bytes* in memory if the datatype isn't a byte.
Note: this can be different from the number of *bytes* in memory if the datatype isn't a byte. See sizeof().
Note: lengths of strings and arrays are determined at compile-time! If your program modifies the actual
length of the string during execution, the value of len(string) may no longer be correct!
(use strlen function if you want to dynamically determine the length)
sizeof(name)
Number of bytes that the object 'name' 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.
For an 10 element array of floats, it is 50 (on the C-64, where a float is 5 bytes).
Note: usually you will be interested in the number of elements in an array, use len() for that.
strlen(str)
Number of bytes in the string. This value is determined during runtime and counts upto
the first terminating 0 byte in the string, regardless of the size of the string during compilation time.

View File

@ -15,44 +15,45 @@ main {
Color c = [11,22222,3.1234]
; c64scr.print_ub(c.red)
; c64.CHROUT('\n')
; c64scr.print_uw(c.green)
; c64.CHROUT('\n')
; c64flt.print_f(c.blue)
; c64.CHROUT('\n')
str string = "irmen"
byte[] ab = [1,2,3]
ubyte[] aub = [1,2,3]
word[] aw = [11,22,33]
uword[] auw = [11,22,33]
float[] af = [1.1,2.2,3.3]
uword xx = 4.5678
ubyte bb = 33
float ff = 1.234
c64scr.print_ub(sizeof(ab))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(aub))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(aw))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(auw))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(af))
c64.CHROUT('\n')
c64.CHROUT('\n')
c64.CHROUT('\n')
foo(1.234, 4.456) ; TODO truncation warning
foo2(2.3456) ; TODO truncation warning
foo2(bb)
foo2(4.55) ; TODO truncation warning
c64scr.print_ub(c.red)
c64.CHROUT('\n')
c64scr.print_uw(c.green)
c64.CHROUT('\n')
c64flt.print_f(c.blue)
c64.CHROUT('\n')
;foo("zzz", 8.777)
;len(13)
; uword size = len(Color)
; c64scr.print_uw(size)
; c64.CHROUT('\n')
; c64scr.print_ub(len(Color))
; c64.CHROUT('\n')
; c64scr.print_ub(len(c))
; c64.CHROUT('\n')
; c64scr.print_ub(len(c.green))
; c64.CHROUT('\n')
}
sub foo(ubyte aa, word ww) {
ww += aa
}
asmsub foo2(ubyte aa @Pc) {
%asm {{
rts
}}
ubyte size = sizeof(Color)
c64scr.print_ub(size)
c64.CHROUT('\n')
c64scr.print_ub(sizeof(Color))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(c))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(c.red))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(c.green))
c64.CHROUT('\n')
c64scr.print_ub(sizeof(c.blue))
c64.CHROUT('\n')
}
}