To finish off, we’ll show how to a write a pretty generic Cicada wrapper for our C function. This will let us run our C code by typing something like
z = f(x, y)
rather than
call("myFunctionInC", x, y, z)
The wrapper will also allocate data storage for our function, and prevent us from crashing the C code by passing in bad arguments.
Don’t ask me what our C function does, but here is a pretty generic wrapper for it.
myFunctionWrapper.cicada
f :: {
x :: char
y :: double
answer :: string
calc_table :: [] int
error_code :: int
params :: {
calcSize :: int
doRecalc :: bool }
code
params = { 100, true }
if trap(
{ x, y } = args | mandatory arguments
(params << args)() | optional arguments
) /= passed then (
print("usage: [string] = f(char, double [; calcSize/doRecalc = ...])\n")
return )
calc_table[^params.calcSize]
error_code = call("myFunctionInC", params.doRecalc, x, calc_table, y, answer)
if error_code == 0 then return new(answer)
else (
print("Error ", error_code, " in function f()\n")
return * )
}
We load our wrapper by going to Cicada’s command prompt and typing:
> run("myFunctionWrapper.cicada")
Here are some examples of function calls we can make once we’ve loaded our wrapper:
result := f('a', 5)
print( f('z', 5.78; doRecalc = false) )
result := f('a', 5; calcSize = that*2, doRecalc = false)
We’ll quickly go through the different parts of our wrapper function. First, everything before the code command just defines the variables used by our function. These include the input and output arguments, optional parameters and even a calculation table used internally by our C code. Importantly, by explicitly defining variables that we pass to call() we ensure that our function call will communicate with C properly. For example, when we write f('a', 5) the integer argument 5 will be converted to a floating-point number before handing it off to C, because the input variable x is defined to be of type double.
The executable part of f() begins after the code marker. The first bit of code reads the arguments of the function. (We enclose the actual reading commands in a trap() statement so that we can fail gracefully with an error message if the function wasn’t called properly.) Notice the two sorts of argument that the user passes. The mandatory arguments x and y are copied straightforwardly from the predefined args variable. The optional arguments, stored in params with the default values of 100 and true, can be changed using a very peculiar Cicada trick: f() runs its own arguments , as a function, inside of its own params variable. How this works is explained in the next chapter. For now, we’ll just point out that in calling f() we separate the mandatory and optional parameters using a semicolon (which is effectively a code command), and use ordinary scripting commands separated by commas to change the optional parameters.
Last update: May 11, 2017