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 ByteDatatypes -> 1
in WordDatatypes -> 2 in WordDatatypes -> 2
FLOAT -> CompilationTarget.machine.FLOAT_MEM_SIZE FLOAT -> CompilationTarget.machine.FLOAT_MEM_SIZE
in PassByReferenceDatatypes -> 2 in PassByReferenceDatatypes -> CompilationTarget.machine.POINTER_MEM_SIZE
else -> -9999999 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 referencesIdentifiers(vararg name: String): Boolean = nameInSource.last() in name
override fun inferType(program: Program): InferredTypes.InferredType { override fun inferType(program: Program): InferredTypes.InferredType {
val targetStmt = targetStatement(program.namespace) return when (val targetStmt = targetStatement(program.namespace)) {
return if(targetStmt is VarDecl) { is VarDecl -> InferredTypes.knownFor(targetStmt.datatype)
InferredTypes.knownFor(targetStmt.datatype) is StructDecl -> InferredTypes.knownFor(DataType.STRUCT)
} else { else -> InferredTypes.InferredType.unknown()
InferredTypes.InferredType.unknown()
} }
} }

View File

@ -8,6 +8,7 @@ interface IMachineDefinition {
val FLOAT_MAX_NEGATIVE: Double val FLOAT_MAX_NEGATIVE: Double
val FLOAT_MAX_POSITIVE: Double val FLOAT_MAX_POSITIVE: Double
val FLOAT_MEM_SIZE: Int val FLOAT_MEM_SIZE: Int
val POINTER_MEM_SIZE: Int
val opcodeNames: Set<String> 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_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_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255
override val FLOAT_MEM_SIZE = 5 override val FLOAT_MEM_SIZE = 5
override val POINTER_MEM_SIZE = 2
const val BASIC_LOAD_ADDRESS = 0x0801 const val BASIC_LOAD_ADDRESS = 0x0801
const val RAW_LOAD_ADDRESS = 0xc000 const val RAW_LOAD_ADDRESS = 0xc000

View File

@ -3,6 +3,8 @@ package prog8.functions
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.StructDecl
import prog8.ast.statements.VarDecl
import prog8.compiler.CompilerException import prog8.compiler.CompilerException
import kotlin.math.* 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 "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 "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 "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: // normal functions follow:
"sgn" to FSignature(true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ), "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) }, "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 { private fun builtinStrlen(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1) if (args.size != 1)
throw SyntaxError("strlen requires one argument", position) 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) if(args[0] is ArrayLiteralValue)
return NumericLiteralValue.optimalInteger((args[0] as ArrayLiteralValue).value.size, position) return NumericLiteralValue.optimalInteger((args[0] as ArrayLiteralValue).value.size, position)
if(args[0] !is IdentifierReference) 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) val target = (args[0] as IdentifierReference).targetVarDecl(program.namespace)
?: throw CannotEvaluateException("len", "no target vardecl") ?: throw CannotEvaluateException("len", "no target vardecl")
return when(target.datatype) { return when(target.datatype) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> { 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")
NumericLiteralValue.optimalInteger(arraySize, args[0].position)
}
DataType.ARRAY_F -> {
arraySize = target.arraysize?.size() arraySize = target.arraysize?.size()
if(arraySize==null) if(arraySize==null)
throw CannotEvaluateException("len", "arraysize unknown") throw CannotEvaluateException("len", "arraysize unknown")

View File

@ -724,11 +724,17 @@ reverse(array)
len(x) len(x)
Number of values in the array value x, or the number of characters in a string (excluding the size or 0-byte). 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 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! 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) (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) strlen(str)
Number of bytes in the string. This value is determined during runtime and counts upto 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. 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] Color c = [11,22222,3.1234]
; c64scr.print_ub(c.red) str string = "irmen"
; c64.CHROUT('\n') byte[] ab = [1,2,3]
; c64scr.print_uw(c.green) ubyte[] aub = [1,2,3]
; c64.CHROUT('\n') word[] aw = [11,22,33]
; c64flt.print_f(c.blue) uword[] auw = [11,22,33]
; c64.CHROUT('\n') float[] af = [1.1,2.2,3.3]
uword xx = 4.5678 c64scr.print_ub(sizeof(ab))
ubyte bb = 33 c64.CHROUT('\n')
float ff = 1.234 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 c64scr.print_ub(c.red)
foo2(2.3456) ; TODO truncation warning c64.CHROUT('\n')
foo2(bb) c64scr.print_uw(c.green)
foo2(4.55) ; TODO truncation warning c64.CHROUT('\n')
c64flt.print_f(c.blue)
c64.CHROUT('\n')
;foo("zzz", 8.777) ubyte size = sizeof(Color)
;len(13) c64scr.print_ub(size)
c64.CHROUT('\n')
; uword size = len(Color) c64scr.print_ub(sizeof(Color))
; c64scr.print_uw(size) c64.CHROUT('\n')
; c64.CHROUT('\n') c64scr.print_ub(sizeof(c))
c64.CHROUT('\n')
; c64scr.print_ub(len(Color)) c64scr.print_ub(sizeof(c.red))
; c64.CHROUT('\n') c64.CHROUT('\n')
; c64scr.print_ub(len(c)) c64scr.print_ub(sizeof(c.green))
; c64.CHROUT('\n') c64.CHROUT('\n')
; c64scr.print_ub(len(c.green)) c64scr.print_ub(sizeof(c.blue))
; c64.CHROUT('\n') c64.CHROUT('\n')
}
sub foo(ubyte aa, word ww) {
ww += aa
}
asmsub foo2(ubyte aa @Pc) {
%asm {{
rts
}}
} }
} }