/Develop/Projects/Vcc/ |
|
k1.spdns.de / Develop / Projects / Vcc / |
intro | invocation | preprocessor | types | functions | operators | instructions
All user-defined data types are composed from these basic data types:
Depending on the target not all sizes may be available.
void no value
int8 8 bit signed integer
int16 16 bit signed integer
int32 32 bit signed integer
int64 64 bit signed integer
uint8 8 bit unsigned integer
uint16 16 bit unsigned integer
uint32 32 bit unsigned integer
uint64 64 bit unsigned integer
float32 32 bit floating point number
float64 64 bit floating point number
float128 128bit floating point number
byte int8 or int16 natural byte size of target machine
short int16
int int16 or int32 default data size for integer arithmetics
long int32 or int64
int_p int16 … int64 size of pointers (addresses)
ubyte uint8 or uint16
char enum uint8 or uint16
ushort uint16
uint uint16 or uint32
ulong uint32 or uint64
uint_p uint16 … uint64
str array of char
float float64 default size for floating point numbers
tbool enum tuint
Allocated data types can be passed 'by value', 'by reference' or 'by ident'.
void foo_by_value ( int[] ) // all data is copied. Recursively.
void foo_by_reference( int[]& ) // a pointer to the array variable is passed.
void foo_by_ident ( int[]¢ ) // a pointer to the array data itself is passed.
vicci/vcc handles all structs and arrays as dynamically allocated objects. An array or struct variable is a pointer to the dynamically allocated contents.
Frequently it is sufficient to pass only the pointer to the allocated data ('int[]¢') to a function. Then two (or, consequently, more) pointers point to that data. But only one pointer has no '¢' attribute: the original owner. If you define a function argument with the '¢' attribute then the compiler does not copy the data at start of the function and it does not destroy it on return.
Access to that data is reduced by one pointer resolution stage (compared to '&').
Disadvantage: You can only modify the data contained in that struct or array, not the struct or array variable itself (by assigning it another/new struct or array). Especially if the variable contained a NULL pointer then you cannot change it if you have passed it 'by ident'.
Warning: If you assign a new struct/array to your local '¢' variable then the new data is automatically immediately destroyed, leaving a void pointer!
Note: While it is frequently desirable to pass data by ident to your function, it is more safe to return a copy from the function, e.g. if the identity would refer to a local variable which is destroyed during return. Then the returned pointer would be void.
Arrays are always allocated dynamically.
int[5] a; // array with initial size
int[] b; // initially empty array
Initially empty arrays are created empty by simply setting the variable to null.
They can be resized later or created with an initial size too:
int[] b = alloc int[](5)
They can be assigned initial data:
int[] b = { 2,3,5,7 }
If an array itself contains allocated data, then the compiler (recursively) inits, copies and kills them as needed.
Arrays can be resized:
void resize(T¢, uint) // built-in
void grow(T¢, uint) // built-in
void shrink(T¢, uint) // built-in
shrink(T¢,uint) shrinks an array to the new size, destroying the contents with kill(T¢) as needed, except if the array is already smaller than requested.
grow(T¢,uint) grows an array to the new size, initializing the new data with init(T¢) if needed, except if the array is already larger than requested.
resize(T¢,uint) resizes an array to the new length, either growing or shrinking it.
Structured data types are always allocated dynamically.
Struct types must be declared with the instruction type:
type Foo =
{
int a,b,c
str txt
}
Member functions can be added later in the scope of a type:
scope Foo
{
int sum ( Foo¢ s ) = inline { return s.a + s.b + s.count(txt) }
}
The first argument for a member function of type T must be of type T, T¢, T& or const thereof.
Access to data members must use the name of 'this' struct.
Invocing a member function is as usual:
int summe = foo.sum()
Struct variables can be created with their default initialization (mostly all data set to zero) or with explicitely setting all non-zero data members:
Foo foo;
foo = (Foo){ a=47, b=1, txt="Hallo!" }
The compiler recognizes and uses and, if required and not yet defined, implicitely creates three basic functions for a struct:
void init( T¢ )
void copy( T¢ )
void kill( T¢ )
init(T¢) is used to initialize a new struct. The struct has already been cleared to zero before init(T¢) is called. init(T¢) now should allocate all allocated data members and initialize any non-zero data.
scope Foo{
void init(Foo¢ a) { a.txt := "Vote Foo For President!" }
}
operator := can be used instead of operator = because the destination of the assignment contains null and needs not to be destroyed.
If struct T is a subclass of another class, then init(T¢) must also call init(T¢) of the super class. This is not automatically done.
The default init(T¢) created by the compiler allocates and initializes all data members which are structs and arrays with initial count.
Note: The default init(T¢) currently runs into an infinite recursion if a struct contains members of it's own type. Then you must define an own init(T¢).
copy(T¢) is used to initialize a struct with a copy of another struct. Before calling copy(T¢) the compiler has already made a flat copy of the source. A custom copy(T¢) function must reallocate all allocated data. Failing to do so will result in allocated data members 'owning' the same data as the source struct's data members!
operator := must be used instead of operator = to assign the new data to a data member, because operator = would destroy the old contents of the data member, thinking the data was owned by it.
scope Foo{
void copy(Foo¢ s) { s.myarray := s.myarray } // this actually duplicates it!
}
myarray is duplicated, because operator := (like operator =) requires Foo as value, but peeking myarray only delivers Foo¢.
If struct T is a subclass of another class, then copy(T¢) must also call copy(T¢) of the super class.
kill(T¢) is called to destroy a struct before it is disposed. A custom kill(T¢) must destroy and deallocated all allocated data members. Failing to do so will result in leaked memory.
scope Foo{
void kill(Foo¢ a) { s.myarray = null } // this actually disposes it!
}
If struct T is a subclass of another class, then kill(T¢) must also call kill(T¢) of the super class.
A struct type can contain itself. But then you must define a default creator, because the built-in default creator will run into an infinite recursion. Built-in copy creator and destructor will work, they are NULL-safe.
type Foo =
{
Foo left,right
int value
}
scope Foo
{
Foo init(){}
}
TODO
TODO
TODO
TODO
Name | Letzte Änderung | Länge | |||
---|---|---|---|---|---|
lib-Z80-Rop/ | 2020-11-30 15:50 | 21 | |||
lib-Z80-Vss/ | 2017-11-12 09:55 | 452 | |||
lib/ | 2019-10-30 17:02 | 3 | |||
Libraries/ | 2019-10-30 17:11 | 6 | |||
OSX-Qt40/ | 2019-10-30 17:02 | 5 | |||
OSX/ | 2020-09-05 12:54 | 6 | |||
Source/ | 2019-10-30 17:02 | 11 | |||
Tests/ | 2019-10-30 17:02 | 9 | |||
LICENSE | 2019-10-30 17:25 | 1323 | |||
README.md | 2019-10-30 17:25 | 288 | |||
TODO.txt | 2020-10-18 12:42 | 340 |