C-Talk support integer, real, string, associative array, thread and mutex types.
There is no structures, classes, unions and pointers. Structures can be
emulated by associative array, for example the expression x.foo
is
equivalent to x["foo"]
and access element of associative array with
key "foo"
.
C-Talk provides very simple interface with C and C++. Programmer can easily define various primitives which can be called from the C-Talk as normal functions.
C-Talk is intented to be used in the same area as Perl, VB-Script, Java-Script languages. It is for the people who are familiar with C and prefer it's syntax to something else. The other advantage of C-Talk is that it is open source free software. It is distributed under MIT license - almost no restrictions on using this language in any project (unlike GPL). Also C-Talk is very simple and compact language, only - 6000 lines of code. It very simple to extend the language with new primitives and types needed for your application.
program: import-list {stmt} import-list: "import" module {"," module} module: identifier func-def: "function" func-name "(" params-list ")" block-stmt func-name: identifier params-list: empty | intentifier { "," intentifier } stmt: ";" | expr ";" | block-stmt | while-stmt | do-while-stmt | for-stmt | if-stmt | break-stmt | continue-stmt | return-stmt | throw-stmt | try-catch-stmt while-stmt: "while" "(" condition ")" stmt do-while-stmt: "do" stmt "while" "(" condition ")" ";" for-stmt: "for" "(" opt-expr ";" opt-expr ";" opt-expr ")" stmt if-stmt: "if" "(" condition ")" stmt ["else" stmt] condition: expr opt-expr: empty | expr break-stmt: "break" ";" continue-stmt: "continue" ";" throw-stmt: "throw" expr ";" return-stmt: "return" opt-expr ";" try-catch-stmt: "try" stmt "catch" "(" exception-var ")" stmt exception-var: identifier block-stmt: "{" { stmt } "}" expr: literal | func-call | start-thread | binary-expr | unary-expr | "(" expr ")" | | variable | index-expr | env-var literal: string | integer | real | array-constructor variable: identifier index-expr: expr "[" expr "]" | expr "." identifier env-var: "$" identifier array-constructor: "[" empty | array-elem { "," array-elem } "]" array-elem: expr [":"] func-call: expr "(" expr-list ")" start-thread: "par" func-call expr-list: empty | expr { "," expr } binary-expr: expr bin-op expr unary-expr: unary-op expr bin-op: "+" | "-" | "/" | "*" | ">>" | "<<" | ">>>" | "|" | "&" | "^" | | "+=" | "-=" | "/=" | "*=" | ">>=" | "<<=" | "|=" | "&=" | "^=" | "=" | "==" | ">" | ">=" | "<" | "<=" | "!=" unary-op: "~" | "!" | "-" | "+"Syntax of identifiers, comments, string, integer and real literals is the same as in C, with the exception that in C-Talk there is no difference between character and string literals. The table below summarize differences between C and C-Talk syntax
"function"
keyword
"ok"
and 'ok'
means the same string character constant
a.x
is syntax sugar for a["x"]
and is treated as associative
array access operation
"par"
construction for starting thread
Example | Description |
---|---|
s = "ok" | relation operations |
s + "cxx" | concatenation of strings |
indexOf(s, "xxx") | index of first occurrence of substring |
lastIndexOf(s, "xxx") | index of first occurance of substring |
substring(s, star | os, end-pos) - extract substring |
toLower(s) | convert to lower case |
toUpper(s) | convert to upper case |
trim(s) | remove trailing spaces |
startsWith(s, prefix) | check if string has specified prefix |
endsWith(s, suffix) | check if string has specified suffix |
string(x) | convert argument to string |
integer("100") | convert string to integer |
real("5.5") | convert string to real |
length(x) | length of string |
a[x] = y | store element |
x = a[y] | fetch element |
x = [0:"red", 1:"green", 2:"blue"] | array constructor |
x += ['one':1, 'two':2] | concatenate arrays |
a - x | remove element(s) from the array, x can be array or key of element |
length(a) | length of array |
cloneArray(a) | create a copy of the array |
deleteArray(a) | deallocate array |
clearArray(a) | truncate array to size 0 |
getKeys(a) | get array of keys |
m = createMutex() | create mutex |
lockMutex(m) | lock mutex |
unlockMutex(m) | unlock mutex |
deleteMutex(m) | delete mutex |
m = getMessage(t) | get message from thread queue |
putMessage(t, m) | put message in thread queue |
t = currentThread() | get reference to current thread |
f = createFile("test.txt", "r") | create file with specified name and access mode |
deleteFile(f) | close file |
flushFile(f) | flush buffers |
printFile(f, "x=", x) | print varying number of arguments to the file |
printlnFile(f, "x=", x) | the same as above but append '\n' |
print("x=", x) | print varying number of arguments to the console |
println("x=", x) | the same as above but append '\n' |
input("> ") | input string from console or specified file, the single optional argument of this function should be file or propmt string |
isString(x) | checks if argument is string |
isArray(x) | checks if argument is array |
isInteger(x) | checks if argument is integer |
isReal(x) | checks if argument is real |
isNull(x) | checks if argument is null |
isFunction(x) | checks if argument is function |
isPrimitive(x) | checks if argument is primitive |
isMutex(x) | checks if argument is mutex |
isFile(x) | checks if argument is file |
getType(x) | returns argument's type code (integer as defined in ctalk.h) |
getTypeName(x) | returns argument's type name |
rc = execute("cp f.dbs f.sav") | execute shell command and wait for result |
t = time() | get current system time (seconds) |
assert(i >= 0) | check the assert condition, throw exception if predicate is false |
loadDLL("test.dll") | load dynamic linking library |
loadModule("test.ctk") | load C-Talk module |
chdir(path) | change current directory |
dir = pwd() | get name of working directory |
sleep(seconds) | sleep specified amount of seconds |
options("socket") | when called without argumetns, returns array of command line options, or gets value of specified option |
printExceptionStackTrace() | print stack trace for the frame where exception was thrown, till the frame where it is catched |
$ ctalk file-1 file-2 ...The loaded module is first compiled to byte code and the all global-level statements are executed. For example, the result of following program execution:
hello = "Hello World"; foo(hello); foo(s) { println(s); }will be printing of "Hello World" line at the screen
CtkObject foo_func(int nArgs, CtkObject args[]) { ... } REGISTER(foo_func, "foo");The code above defines the function "foo_func" and registers it as C-Talk primitive "foo". Now C-Talk program can call "foo()" function in the same way as it was declared in C-Talk. The C-Talk C-interface library provides methods for creating objects of C-Talk types, converting
CtkObject
with type checking to primitive C
types, operations with C-Talk types (such as strings, arrays and mutexes),
throwing C-Talk exceptions. Macros IS_XXX can be used to check object type,
macros TO_XXX perform conversion to the specified type or throw exception if type
doesn't match, macro MAKE_XXX create object with specified type and value,
mcaros CHECK_PRIMITIVE_N_ARGS and CHECK_PRIMITIVE_ARGUMENT can be used to check number
of passed arguments and type of each argument.
C-Talk provide even more convinient weay for checking types passed arguments.
Function ctkParseArguments
takes format string and optional list of arguments palceholder and
perform necessary checks and conversions.
void ctkParseArguments(int nArgs, CtkObject* args, char const* format, ...);
Format symbol | Expected C-Talk type of argument | Type of placeholder for parameter value |
---|---|---|
o | any | CtkObject |
i | CTK_INTEGER | ctk_integer |
r | CTK_REAL | ctk_real |
p | CTK_RAW_POINTER or CTK_NULL | void* |
P | CTK_RAW_POINTER | CtkObject |
s | CTK_STRING or CTK_NULL | char* |
S | CTK_STRING | CtkObject |
a | CTK_ARRAY or CTK_NULL | CtkArray* |
A | CTK_ARRAY | CtkObject |
f | CTK_FILE or CTK_NULL | CtkFile* |
F | CTK_FILE | CtkObject |
m | CTK_MUTEX or CTK_NULL | CtkMutex* |
M | CTK_MUTEX | CtkObject |
t | CTK_THREAD or CTK_NULL | CtkThread* |
T | CTK_THREAD | CtkObject |
l | CTK_FUNCTION or CTK_NULL | CtkFunction* |
L | CTK_FUNCTION | CtkObject |
u | CTK_USER_TYPE or CTK_NULL | void* |
U | CTK_USER_TYPE | CtkObject |
Example:
CtkObject myPrimitive(int nArgs, CtkObject* args) { char* s; ctk_integer i; ctk_real r; CtkObject o; ctkParseArguments(nArgs, args, "siro", &s, &i, &r, &o); ... }
loadDLL
method.
The single parameter of this function contains name of loaded DLL.
If this name contains no extension, then default OS extension will be added
(".dll" at windows, ".so" at Unix).When DLL is loaded, all primitives registered in this DLL becomes available. But since these primitives descriptors were not available at compilation time, you can invoke these primitives in the module loaded the DLL only by specifying function name as string:
loadDLL("mydll"); "myfunc"("hello world");If you want to access primitives defined in DLL in normal way, you should place you code in separate module and load it after loading of DLL:
loadDLL("mydll"); loadModule("mymodule"); ----------------------- mymodule.ctk: ----------------------- myfunc("hello world");C-Talk is also able to transparently call DLL functions. The only restriction is that these functions should not have more than 5 formal parameters, parameter type should be
int
, char*
or pointer to any user defined type
and function should return loadDLL("User32"); "MessageBoxA"(0, "Correct text", "MsgBox Sample", 0);If you want to write
MessageBoxA()
instead of "MessageBoxA"()
,
you should place your code in separate module and load it after loading of DLL.
DLL function called in this way is assumed to return value of raw pointer type.
So it can be pointer to any user defined type which you can then pass as argument
to other DLL functions. If the function really returns integer, then you can convert
returned value using integer()
function.