The T++ Programming Language

Before reading this, it is suggested you familiarise yourself with the compiler and toolchain environment here.

T++ is a high level programming language for the R3X runtime, it is highly imperative, and is suitable for almost every task. The language features a relatively simple syntax with support for calling functions from dynamic libraries (both native and virtual), function calls, strings, memory management and lots which is not mentioned. Granted, it is a hobby project and hence is not as powerful or good as some of the mainstream languages like Java or C#, but from a not-so-professional perspective, it is good enough. Considerable effort has been made to improve the syntax and the overall language, which is still a WIP.

Type System

One very improtant thing to note here is that T++ is techinically typeless, meaning there is *no* type safety, it is unlikely that type safety is going to be added in the near future.

Keywords

Keywords form the base of any programming language, and T++ is no exception to this rule (of course). The following is the list of keywords available in the T++ programming language:

Language and syntax

R3X follows an imperative style, along with newlines to differentiate between statements. (with the exception of if).

Function calls

Functions must be defined before they are to be called. There is unfortunately, no support for prototypes (like C) here, yet. To call a function, the '@' character must precede the function name followed by arguments enclosed within '(' and ')'. An example is given below:
...
function add2numbers(2)
	let number1 = $1
	let number2  = $2
	return number1 + number2
endf
...
function main(0)
	let my_num = @add2numbers(2,5)
	// my_num = 7
	// the below function call's return value will be trashed, in case it's not needed
	@add2numbers(40, 45)
	...
endf
...
However, this only supports internal (and native/external dynamic) functions. If you want to call an address, you must use raw_call.
@raw_call(function_address, number_of_arguments, arg1, arg2, arg3, ...).
function_address shall be an expression that equates to the address that needs to be called, number_of_arguments shall be the number of arguments to be passed, then follows the list of expressions equating to the arguments that need to be passed. An example is given below:
	...
	arg2 = 5
	arg3 = 28
	// call address 0x140000 with 3 arguments
	@raw_call(0x140000, 3, 3*5, arg2, arg3+6)
	...
Note: All programs must have a main function. Dynamic libraries don't have a main function on the other hand.

Function Arguments

Function arguments can be accessed by prefixing a '$' infront of the number of argument. Arguments are 1-indexed, so this means, the first argument can be accessed by '$1'. Note that this NOT permitted to be used in expressions. For example:
let a = $1+2
will translate to:
let a = $3
and not
let a = (first_argument_value) + 2
Hence, it is recommended, to rather have this:
function myfunc (2)
	let arg1 = $1
	let arg2 = $2
	...
	// Now you can use arg1 and arg2 normally in expressions. like:
	let a = arg1 + arg2
	...
endf

Pointers

Pointers are variables that point to a section of memory. Accessing Pointers generally refers to accessing the values at these memory locations pointed by the variables. Since T++ is a typeless language there are no pointer types, this task is rather, accomplished by specific operators. The following are the operators that can be used:
int8_ptr (expression) 	- 8-bit pointer access
int16_ptr(expression) 	- 16-bit pointer access
int32_ptr(expression) 	- 32-bit pointer access
Several examples are given below, including pointer access and assignment:
	...
	// set addr4MB to 0x400000
	let addr4MB = 0x400000
	let whatisat4MB = int8_ptr(whatisat4MB)
	// whatisat4MB contains the value of the byte (8-bit) at 0x400000.
	let int32_ptr(whatistat4MB+4) = 69
	// now 4 bytes after 0x400000 contains the 32-bit integer '69'.
	...

Labels

Labels can be defined by prefixing a colon (':'). An example is given below:
...
:label01
...
:label02
...
:label03
...
Keywords like goto and gosub can be used to jump between labels.

Structures and globals

Structures can be accessed by: [struct name_of_struct]expression.member_name
name_of_struct is the structure name which is given during declaration, expression gives out the pointer to the struct, and member_name is the member name whose value is to be returned. You can use the sizeof(name_of_struct) to return the size of a structure. An example is given below:
struct mystruct(5)
	int8 m1
	int8 m2
	int32 m3
	int16 m4
	int32 m5
	int8 m6
ends
...
	let mystruct_ptr = alloc(sizeof(mystruct))
	// set m3 to 5
	let [struct mystruct]mystruct_ptr.m3 = 5
	// return value of m2.
	let mystruct_val_m2 = [struct mystruct]mystruct_ptr.m2
...
Global variables are also accessed in a similar way, using [global]variable_name
variable_name is the name of the variable whose value is to be accessed. An example is given below:
global myvar
...
	let [global]myvar = 5
	...
	let value_of_var = [global]myvar
...

Address of functions or local variables

Address of functions or local variables can be taken by using the addressof(variable_or_function) operator. variable_or_function refers to the variable/function name whose address is to taken. For functions, they MUST be prefixed with a '@'. An example is given below:
function func1(6)
	...
endf
...
function func2(0)
	let x = 0
	...
	let addressof_x = addressof(x)
	let addressof_func1 = addressof(@func1)
	...
endf
...

Internal functions

There are some internal functions that are provided by the language, these are:

Floats

T++ supports Floating Point (Decimal) members, operations on them can be done through using special operators. The following is a list of all floating point operations available.
NOTES:
• Declaration of floating point numbers must be done like this (i.e. have at least 1 digit after the decimal point):
let A = 30.0 // "let A = 30" will set A to an integer, NOT a floating point number.
...
Integers and Floats CANNOT be MULTIPLIED. To be able to do this, you must use two operators conv_f(expression) (which converts integer to floats) and conv_i(expression). An example is given below:
let integernum = 30
let floatnum = 50.5
let result = mul_f(floatnum, conv_f(integernum)) // convert integernum to float and multiply
...
let result = integernum * conv_i(floatnum) // convert floatnum to integer and then multiply (decimal points will be lost!)

Operators and Operator precedence

T++ has no operator precedence, all operations which are to be done first must be enclosed in brackets or done sequentially. The following is a list of all operators present in T++:

Escape sequences

T++ now supports escape sequences. Note that for now they can only be used in strings and are very limited, here is a list of them:
\n					Newline (0x0A)
\r					Carraige Return (0x0D)
\t					TAB Character (0x09)
\\					'\' Character

The Preprocessor

T++ uses GCC as a preprocessor. This means that anything that can be done in the C preprocessor which does not make use of C language features is accomplishable in T++ as well.