Cicada ---> Online Help Docs ---> Reference

Predefined functions and variables

Cicada comes prepackaged with a number of C-coded and scripted functions. The C-coded functions are come from the ciclib.c source file, and they are defined in exactly the same way as user-defined C functions/wrappers. The scripted functions come from a defs.cicada script (which is distributed in stringified form as defs.c), a number of which are just wrappers for the C-coded functions. defs.cicada also predefines some variables and constants. Finally, when Cicada is run interactively, the terminal itself defines a few variables in the user’s workspace.

Table 4 lists the predefined C functions, scripted functions, and other scripted variables. Their descriptions follow in alphabetical order.

Basic constants:


Predefined functions and variables


name f $ > name f $ name f $
newCompiler x x   filePaths     add x x
compile x x   cd x   subtract x x
transform x x+   pwd x   multiply x x
disassemble x     run x   divide x x
trap x x   load/Load x x pow x x
throw x x   save/Save x x min x x
top x x   input x x max x x
size x x   print x x sum x x
type x x   printl x   mean x  
bytecode x x   sprint x   abs x x
member_ID x x   mprint x   floor x x
allNames     X read_string x x ceil x x
do_in x     print_string x x round x x
compile_and_do_in x     cat x   exp x x
go x     readTable x   log x x
jump x     readFile x   cos x x
go_path     X readInput x   sin x x
where       writeTable x   tan x x
what x     saveTable x   acos x x
calculator x   X find x x asin x x
ans     X lowercase x   atan x x
springCleaning x x   uppercase x   random x x
        C_string x   sort x x+
          x   binsearch x  

Table 4: Built-in functions and variables. An ‘x’ in the ‘f’ column indicates that it’s an executable function. An ‘x’ in the ‘$’ column indicates that there is a corresponding C function. A checkmark in the > column indicates that the definition only exists when running from the terminal (all of these are on the left side of the table)


abs(), $abs()

syntax: (numeric) y = abs((numeric) x)

C syntax: $abs((double) x, (double) y)

Returns the absolute value of its argument, which must be a numeric scalars or arrays.


acos(), $acos()

syntax: (numeric) y = acos((numeric) x)

C syntax: $acos((double) x, (double) y)

Returns the inverse cosine of its argument. The argument must be a number on the interval [-1, 1] (a number outside this range will generate the ‘not a number’ value on many machines). The result is on the interval [0, pi]. The arguments may be numeric scalars or arrays.


add(), $add()

syntax: (numeric) z = add((numeric) x, (numeric) y)

C syntax: $add((doubles) x, (doubles) y, (doubles) z)

Computes z = x + y, for scalar or vector numeric data.


allNames:

the list of member names that have been defined so far, including those defined in terminal.cicada. allNames is updated with every new command-line prompt, or every time the user calls compile() with allNames as the fourth argument. This list is used by user.cidada’s go() and what() functions.


ans:

: short for “answer”. This is aliased to whatever the calculator last printed (void if the calculator hasn’t printed anything yet). Use ans like any other variable:


    > 2+5
   
    7
   
    > ans*2
   
    14
   


asin(), $asin()

syntax: (numeric) y = asin((numeric) x)

C syntax: $asin((double) x, (double) y)

Returns the inverse sine of its argument. The argument must be a number on the interval [-1, 1] (a number outside this range will generate the ‘not a number’ value on many platforms). The result is on the interval [-pi/2, pi/2]. The arguments may be numeric scalars or arrays.


atan(), $atan()

syntax: (numeric) y = atan((numeric) x)

C syntax: $atan((double) x, (double) y)

Returns the inverse tangent of the argument, which must be numeric scalars or arrays. The result is an angle in radians on the interval [-pi/2, pi/2].


binsearch()

syntax: binsearch((table) table_to_search, (numeric) value_to_find)

Searches a sorted list for a given value. The list must be numeric (char-typed lists are OK). If the list is not sorted then binsearch() will probably not find the element.


bytecode()

syntax: (string) codeString = bytecode((function) myFunction [, (numeric) memberIndex])

C syntax: $bytecode((function) myFunction, (int) memberNumber, (string) codeString)

Returns the bytecode of a given variable or member. If there is one argument it returns the bytecode of that variable; if there are two then it returns the bytecode of member myFunction[memberIndex]. Member code is never run directly, but it determines the sort of variable a member can point to (because code and type are equivalent in Cicada).

To read the bytecode we need to move the bytecode data from the string into an array of integers using the =! operator. The last integer is always 0, signifying the end of bytecode. If there are multiple codes (due to the inheritance operator) then the codes are concatenated in parent-to-child order in the same string, and each separate code ends in a null integer. bytecode() is the inverse operation to transform().

The bytecode() function return the code for functions, but also many other objects that we don’t normally think of as having code. In fact the only restriction is that myFunction must be some composite object (defined using curly braces). So if we define


    pow :: {
       params :: { x :: y :: double }
       
       code
       
       params = args
       return new(params.x^params.y)
    }
   

then bytecode(pow) returns the bytecode for everything inside pow()’s definition (including the definition of params and the code marker), whereas bytecode(pow.params) is also legal and returns the bytecode corresponding to x :: y :: double.


C_string()

syntax: (string) string bytes = C_string((string) my_string)

Cicada strings are normally stored internally as linked lists. C_string() converts a length-N resizable Cicada string to a N+1-byte C-style string containing a terminating 0 character.


calculator:

is a function that prints the results of incomplete expressions at the command line. An incomplete expression is one that is not assigned to a variable, or used in any other way. For example, if the user types


    a = 5 + 2
   

then nothing will be printed, regardless of whether calculator is on or off. However, if the user were to enter just


    5 + 2
   

then the answer ‘7’ will be printed, thanks to the calculator.

To be completely technical, the calculator prints the data of all hidden members created by the user. Since these members will never be used again, the terminal removes them after each command from the user, but only after asking the calculator to print them first. The calculator is only a printing function, not a calculator per-se.

By default, the calculator is aliased to defs.cicada’s sprint() function. We can change the output style by aliasing it to another printing function:


    > calculator = @mprint
   

Or, if calculator is getting annoying (e.g. printing the output of functions we don’t care about, or that return enormous blocks of data), we can turn it off altogether:


    > calculator = @nothing
   


cat()

syntax: (string) concatenated string = cat((variables) var1, var2, ...)

Returns a string which is the concatenation of the arguments. This is just a convenient implementation of the print_string() function: s = cat(v1, v2) is equivalent to print_string(s, v1, v2).


cd()

syntax: cd((string) filepath)

The easiest way to change Cicada’s file-search directory. cd() resizes the filePaths[] array to size 1 and sets that to the string given as its argument.


ceil(), $ceil()

syntax: (numeric) y = ceil((numeric) x)

C syntax: $ceil((double) x, (double) y)

Returns the nearest integer that is as high as or higher than the argument, which must be numeric. For example, ceil(5.6) returns 6, ceil(-5.6) returns -5, and ceil(2) returns 2. Both arguments may also be arrays


compile()

syntax: (string) script_bytecode = compile((string) script [, (string) char_positions [, member_names]] [, code, compilerID = (int), filename = (string)])

C syntax: $compile((int) compilerID, (string) script, (string) filename, (string) script_bytecode, (string) char_positions, (int) num_member_names)

Before Cicada can execute a script, that script must be compiled into a binary form called bytecode that is much easier to execute than the raw text. The built-in compile() function does this job. Given a string containing a Cicada script (script), compile() returns a second string (script_bytecode) containing Cicada bytecode. The bytecode is not machine code -- it is only used by Cicada.

A basic compile() call looks like:


    myBytecode := compile("x = 3")
   

This command produces bytecode from a given script. Optionally, the compiler ID can be set to the return value from a newCompiler() call. Each compiler keeps a record of all variable names, so if x had been defined with bytecode produced by the current compiler then this command will run just fine. The scripted function calls $getMemberNames() to maintain the allNames list.

A compilation error will actually crash the script running the compile() command. To prevent this we can enclose the compile() call inside of the trap() function. If we want to print out the error message, we can write a semicolon or code marker at the beginning of trap()’s arguments.


    > trap(; compile("x = "))
   
    Error: right-hand argument expected
   
    x =
     ^
   

The optional second filename argument causes any error message to reference that file name.


    > trap(; compile("x = "; filename = "myFile.txt"))
   
    Error: right-hand argument expected in file myFile.txt
   

Often a script will compile but cause an error when it runs. In order to properly flag runtime error messages we must collect another piece of information: the character position in the original script of each bytecode word. This lets the error message flag the offending line in the original script. The character positions are stored inside of any string that is passed as an optional third argument to compile(). Both that string and the original Cicada script will be passed to transform(), the function that actually allows compiled bytecode to be run.

In some cases we may want to avoid using compile(), but instead hand-code the bytecode and load it in using transform(). After all, compile() is only a string operation: it converts a readable script into a string containing binary bytecode.


compile_and_do_in()

syntax: compile_and_do_in((composite) target [, search path [, code_args [, bytecode_mod_args]]] , code, (string) base script string [, code, code modifying bytecode[]])

Compiles a script, optionally modifies it, and then executes the script in the provided directory. This is equivalent to do_in() except that the script is stored as an uncompiled string rather than compiled code. We write the arguments just as we did for do_in(), except with an extra pair of double-quotes around the code to compile (even though it’s in the coding section of the arguments). The analog of the do_in() example would be:


    compile_and_do_in(root; "al := @var1"; bytecodeWords[2] = that + 128)
   


cos(), $cos()

syntax: (numeric) y = cos((numeric) x)

C syntax: $cos((double) x, (double) y)

Returns the cosine of its argument. The argument must be numeric scalars or arrays..


disassemble()

syntax: [(string) disassembly = ] disassemble((string) compiled_code [ , (string array) name_space [ , (int) start_position ] ] [ , code, (bool) expandFunctions, (int) flagPosition = values ])

The disassemble() function returns a textual interpretation of compiled Cicada bytecode. The first argument is a string containing the bytecode. The optional second argument allows the user to pass a different namespace (a string array) other than allNames[], or * to avoid printing member names. The function will return the ‘disassembly’ as a readable string. Used by the author to satisfy the odd craving for a rush of bytecode:


    > disassemble(compile("x = that + 2", *, *, allNames))
   

By passing a third argument, the disassembler can be used to skip over a bytecode expression. In this case the disassembler will only disassemble up to the end of the expression, and if the starting word index was passed in a variable then that variable will be updated to the beginning of the next expression. For example, we can use this feature to write a function that finds the Nth command in a compiled expression.


    go_to_Nth_sentence :: {
       
       code
       
       code_string := args[1]
       N := args[2]
       
       code_index := 1
       for (n :: int) in <1, N-1> &
           disassemble( code_string, *, code_index )
       
       return new(code_index)
    }
   

When run in this ‘skip’ mode, disassemble() does not return any bytecode string. If you want the output string you should first find the end of the expression that start_position begins, then do a full disassembly on just that expression.

The expandFunctions option determines whether inlined code definitions (as in, objects defined within curly braces) are disassembled (true is the default), or skipped with an ellipsis if false. If flagPosition is set to an integer value then the disassembler will flag that bytecode word, which is useful for marking errors.


divide(), $divide()

syntax: (numeric) z = divide((numeric) x, (numeric) y)

C syntax: $divide((doubles) x, (doubles) y, (doubles) z)

Computes z = x / y, for scalar or vector numeric data.


do_in()

syntax: do_in((composite) target [, search path [, code_args [, bytecode_mod_args]]] , code, base script [, code, code modifying bytecodeWords[]])

The do_in() tool allows one to run code in a specified location and with a specified search path, and gives the option of manually modifying the bytecode before it is run. The idea is that it is easier to write bytecode by perturbing a compiled script than to write everything from scratch.

The first argument to do_in() is the variable to run the code inside. The optional second argument gives a customizable search path, and it exactly mirrors the optional third argument to transform() (see the reference on transform() for how to specify a path). The third and fourth arguments, if given, are passed as args[1] for the script to be run and the bytecode-modifying script respectively.

Following the first code marker we give the text of the script that we want to run, or the closest that the Cicada compiler can achieve. Often this is all we need. On occasion we may wish to modify the compiled bytecode of the baseline script before it executes, perhaps to achieve something that is unscriptable. do_in() accommodates this need by running, in unusual fashion, the code following an optional second code marker/semicolon in its argument list (if that exists) after compilation but before execution. At that time the compiled baseline script will be stored in an array entitled bytecodeWords of integers, and we may alter in any way whatsoever provided the bytecode comes out legitimate. In the extreme case we can give no baseline script and simply alias bytecodeWords[] to an existing integer array that is already filled with bytecode.

Here we show how to use do_in() to create an unjammable alias to some variable var1, which cannot be done using ordinary Cicada scripting.


    do_in(
       root
       
       code
       
       al := @var1
       
       code
       
       bytecodeWords[2] = that + 128   | add an unjammable flag
    )
   
   


exp(), $exp()

syntax: (numeric) y = exp((numeric) x)

C syntax: $exp((double) x, (double) y)

Returns the exponential (base e) of its argument. The arguments must be numeric scalars or arrays.


filePaths[]:

a string array of pathnames to folders. Load(), Save(), and run() will search each of these paths when looking for a file. The terminal preloads an empty path, which usually implies the Cicada directory. We can change the search paths just by manipulating this set: e.g. filePaths[+2] = "/Desktop/".


find()

syntax: (numeric) result = find((strings) search_in, search_for [, code, mode = -1/0/1 [, code, startPosition = (numeric)]])

C syntax: $find((string) search_in, (string) search_for, (int) mode, (int) starting_position, (int) result)

Finds an instance of, or counts the number of instances of, a substring (argument 2) within another string (argument 1). If find() is used in search mode, it returns the character position (where 1 denotes the first character) where the substring was first found, and 0 if it was not found anywhere. If find() is run in count mode, it returns the number of instances of the substring found within the larger string.

The optional third argument controls the mode that find() is run in: it needs to be -1, 0 or 1. If a mode is not specified then it defaults to mode 1, which denotes a forward search; i.e. it will return the first instance of the substring that it finds. Mode -1 corresponds to a reverse search, which will find the last instance of the substring. Mode 0 is the count mode.

By default, a forward search begins from the first character, and a reverse search begins with the last character. A count proceeds forward from the first character. The starting character can be changed by specifying a starting position in the fourth argument. A mode has to be given in order for a starting position to be specified.


floor(), $floor()

syntax: (numeric) y = floor((numeric) x)

C syntax: $floor((double) x, (double) y)

Returns the nearest integer that is as low as or lower than the (numeric) argument. For example, floor(2.3) returns 2, floor(-2.3) returns -3, and floor(-4) returns -4. The arguments may be numeric scalars or arrays.


go()

syntax: go([ code, ] path)

Cicada’s go() function changes the working variable for commands entered from the prompt. A search path is dragged along behind that leads eventually back to root (the original workspace). To see how this works, type:


    > a :: { b := 2 }
   
    > go(a)
   
    > b   | we are now in 'a', so this is legal
   
    2
   
    > a   | search path extends back to root, so we can see 'a' as a member
   
    { 2 }
   

The search path exactly backtracks the given path. If one types go(a[b].c().d, then the working variable is ‘d’, and the search path goes backwards through (in order): the return variable of ‘c’, then ‘c’ itself, then the b’th element of ‘a’, then ‘a’ itself and finally root. Typing just go() sends one back to the root; typing go(root) is actually not quite as good because it puts root on the path list twice. To see the path, look at the global pwd variable.

go() works by updating the go_paths[] array defined by the terminal. Each command entered from the prompt is transformed and run according to the current state of go_paths, so invoking go() does not take effect until the next entry from the prompt. Thus it was necessary in our example to separate the second and third lines: go(a), sprint(b) would have thrown a member-not-found error. For the same reason, while running a script (via run()), go() will do nothing until the script finishes -- use do_in() instead.

When the user calls go(...), Cicada constructs the argument list before go() itself has a chance to run. Owing to this fact, certain sorts of go-paths will cause an error that go() can do nothing about. For example, go(this[3]) will never work because ‘this’ is construed as the argument variable, not the working variable. To get around this problem, go() gives us the option of writing the path after a code marker or semicolon, as in go(code, this[3]), as those paths are not automatically evaluated. A code marker is also useful if we need to step to a function’s return variable but don’t want the function to run more than once. go(code, a.f().x) will evaluate f() just a single time in the course of go-processing, whereas for technical reasons f() would have run twice had we not included the code marker.

go() at present has many limitations. Each path must begin with a member name or this, and all subsequent steps must consist of step-to-member (a.b) and step-to-index (a[b] and related) operations and function calls (a()). No [+..] or +[..] operators are allowed. The step-to-index operations are particularly dicey because of two nearly contradictory requirements: the path can only step through single indices, and for practical use the path must nearly always span complete members (i.e. all of the indices of an arrays). Although the latter is not a hard requirement, it is really hard to do anything meaningful within a single element of an array, because so many common operations involve creating tokens and hidden variables which can only be done for all elements of the array simultaneously. Even trying to reset the path by typing go() will not work at that point, so in this sticky situation the terminal will eventually bail the user out. The upshot of all this is that go() does not work very well inside of arrays.

jump() is a similar operation to go(), except that go() can shorten a path whereas successive jumps keep appending to the current search path.


go_path[]:

a set of aliases to each composite object in the search path, beginning with root and ending with the current working variable. The terminal uses go_path to form the search path for each command entered by the user. Both go() and jump() work by modifying go_path, and the terminal will reset go_path if it detects a problem. The user can add a small coding section to go_path which the terminal will run if it needs to reset the path; in this coding section do not define any variables or run any functions or problems will start happening.


input()

syntax: (string) str = input(args_to_print)

C syntax: $input((string) str, args_to_print)

Reads in a single line from the C standard input (which is usually the keyboard). input() causes Cicada’s execution to halt until an end-of-line character is read (i.e. the user hits return or enter), at which point execution resumes. The return string contains all characters before, but not including, the end-of-line. Reading in a null character causes the error “I/O error” to be thrown.


jump()

syntax: jump([ code, ] path)

jump() is basically identical to go() except in the way that it handles the first step in a search path. For most details, see the explanation of go() above. The difference between the two functions can be seen by example.


    > a :: { b :: { ... } }
   
    > go(a.b), where
   
    root.a.b
   
    > go(a), where  | starting from a.b
   
    root.a
   
    > go(b), where
   
    root.a.b
   
    > jump(a), where  | again, starting from a.b
   
    root.a.b-->a
   

jump() takes advantage of the fact that search paths in Cicada can twine arbitrarily through memory space; we don’t have to restrict ourselves to paths where each variable is ‘contained in’ the last. A more useful path would be something like root.a.b-->c.d: that would allow us to work inside of ‘d’ while retaining access to ‘a’ and ‘b’, even if those latter lie along a different branch.


load()

syntax: (string) file_string = Load((string or int) file_name)

syntax: (string) file_string = load((string or int) file_name)

C syntax: $load((string or int) file_name, (string) file_string)

Reads a file into a string. If there is an error in opening or reading the file (i.e. if the file was not found), then load() returns “I/O error”, signifying that the error comes from the operating system, not Cicada. The counterpart to load() is save().

Little-L load() only looks for files in the default directory. Big-L Load() extends this function by searching all paths specified in the filePaths[] array.

The filename may be an integer (1-3) rather than a string, in order to load one of the predefined scripts. The scripts are: 1) defs.cicada; 2) terminal.cicada; 3) the user’s script passed to runCicada() (if given, otherwise an error is thrown).


log(), $log()

syntax: (numeric) y = log((numeric) x)

C syntax: $log((double) x, (double) y)

Returns the natural logarithm (base e) of its argument. The argument must be numeric scalars or arrays.


lowercase()

syntax: (string) lowercase_string = lowercase((string) my_string)

Converts a mixed-case string to lowercase.


max(), $minmax()

syntax: (numeric) result = max((numeric list) the_list [, code, rtrn = { index / value / both])

C syntax: $minmax((doubles) the_list, 1, (int) index, (double) value])

Returns the maximum element of a list: its index, value (the default), or both { index, value }.


mean()

syntax: (numeric) result = mean((numeric list) the_list)

C syntax: $mean((doubles) the_list, (double) result)

Returns the average (arithmetic mean) of the elements of a numeric list.


member_ID()

syntax: (numeric) ID = member_ID((composite variable) var, (numeric) member_number)

syntax: $member_ID((composite variable) var, (int) member_number, (int) ID)

Returns the ID number of a given member of a composite variable. The ID is essentially the bytecode representation of the member’s name. Under normal conditions user-defined names are assigned positive ID numbers, whereas hidden members are given unique negative ID numbers. The variable enclosing the member is the first argument, and the member number is the second argument.


min(), $minmax()

syntax: (numeric) result = min((numeric list) the_list [, code, rtrn = { index / value / both])

C syntax: $minmax((doubles) the_list, -1, (int) index, (double) value])

Returns the minimum element of a list: its index, value (the default), or the combination { index, value}.


mprint()

syntax: mprint([data to print] [ ; (ints) fieldWidth, maxDigits, (string) voidString = values ])

This ‘matrix’ print function prints tables of numbers. Each index of the argument is printed on a separate line; each index of a row prints separately with a number of spaces in between. For example:


    > mprint({ 2, { 3, nothing, 5 }, { 5/2, "Hello" } })
   
    2
    3        *        5        
    2.5      Hello    
   

mprint() has three user-adjustable optional parameters that can be changed in the argument coding section. mprint.fieldWidth controls the number of spaces in each row; it defaults to 12. mprint.maxDigits controls the precision of numbers that are printed out; it defaults to 6. A maxDigits of zero means ‘no limit’. mprint.voidString is the string used to represent void members.


multiply(), $multiply()

syntax: (numeric) z = multiply((numeric) x, (numeric) y)

C syntax: $multiply((doubles) x, (doubles) y, (doubles) z)

Computes z = x * y, for scalar or vector numeric data.


newCompiler()

syntax: (numeric) compilerID = newCompiler((compiledCommandType array) operatorDefs, (int array) opLevelDirections)

C syntax: $newCompiler((compiledCommandType array) operatorDefs, (int array) opLevelDirections, (int) compilerID)

Produces a new compiler from a language specification, and returns the new compiler’s ID number. (The default Cicada compiler has ID number 1). The two arguments are: 1) an array of { string, int, string, string }, one element for each command, containing the command definitions; and 2) an array giving the direction of evaluation for each order-of-operations level. These mirror the cicadaLanguage[] and cicadaLanguageAssociativity[] arrays, respectively, which are defined in cclang.c.

The beginning of defs.cicada has lots of definitions to make a language specification simpler and more readable.


pow(), $pow()

syntax: (numeric) z = pow((numeric) x, (numeric) y)

C syntax: $pow((doubles) x, (doubles) y, (doubles) z)

Computes the power function z = x^y, for scalar or vector numeric data.


print()

syntax: print((vars) v1, v2, ...)

C syntax: $print((vars) v1, v2, ...)

Writes data to the standard output (which is normally the command prompt window). The arguments are printed sequentially and without spaces in between. Numeric arguments are converted to ASCII and printed as legible integers or floating-point numbers. String arguments are written verbatim (byte-for-byte) to the screen, except that unprintable characters are replaced by their hexadecimal equivalents “\AA” (which is also the format in which these characters may be written into a string). Also, carriage returns in strings are written as end-of-line characters, so a PC-style line ending marked by “\0D\n” outputs as a double line-break.

When Cicada is run from the command prompt, defs.cicada loads three further printing functions: printl() (print with line break), sprint() (for printing composite structures), and mprint() (printing arrays). sprint() is the default function for printing expressions typed by the user.


print_string()

syntax: (string) result = print_string((vars) v1, v2, ... [, code, maxFloatingDigits = (numeric)])

syntax: $print_string((string) result, (int) max_floating_digits, (vars) v1, v2, ...)

Writes data to a text string. print_string() is the counterpart to read_string(). Roughly speaking, print_string() is to print() as C’s more elaborate sprintf() is to printf(). The string to write is followed by any number of variables whose data Cicada writes to the string (with no spaces in between). Strings from the source variables get copied into the destination string verbatim. Numeric variables are written as text, and here print_string differs from a forced equate. For example:


    print_string(str, 5, 2.7)
   

sets str to “52.7”, whereas


    str =! { 5, 2.7 }
   

gives something illegible (the raw bytes encoding the two numbers in binary format).

If the first argument is numeric, then it is taken as the minimum field width for numeric and Boolean (but not string or character) variables to be printed; otherwise the default minimum field width is zero. If both the first and second arguments are numeric, then the second argument is the output precision for floating-point variables; otherwise the output precision is determined by the C constant DBL_DIG for double-typed variables. When no precision is specified, print_string prints considerably more digits than does print(), whose precision is set by printFloatFormatString at the top of cmpile.c.


printl()

syntax: printl([data to print])

This function is the same as print() except that it adds an end-of-line character at the end.


pwd()

syntax: pwd()

Prints all file directories (all entries in the filePaths[] array) to the screen.


random()

syntax: (numeric) y = random()

C syntax: random((doubles) y)

Returns pseudo-random numbers uniformly drawn on the interval [0, 1]. To obtain the random number to double-precision, Cicada calls C’s rand() function twice:


   random() = rand()/RAND_MAX + rand()/(RAND_MAX)2

The random number generator is initialized by Cicada to the current clock time each time the program is run, so the generated sequence should not be repeatable. The scripted function returns a scalar; for vectorized random data run the C function.


read_string()

syntax: read_string((string) to_write, (vars) v1, v2, ...)

syntax: $read_string((string) to_write, (vars) v1, v2, ...)

Reads data from an ASCII string into variables. The first argument is the string to read from; following arguments give the variables that will store the data. read_string() is the humble cousin to C’s sscanf() routine (it does not take a format string). The various fields within the string must be separated by white space or end-of-line characters.

read_string() converts ASCII data in the source string into the binary format of Cicada’s memory. Thus numeric fields in the source string need to be written out as text, as in “3.14”. Each string field must be one written word long, so “the quick brown” will be read into three string variables, not one. Composite variables are decomposed into their primitive components, which are read sequentially from the source string. Void members are skipped.

Here is an example of the use of read_string()


    date :: { month :: string, day :: year :: int }
    activity :: string
    read_string("Jan 5 2007  meeting", date, activity)
   

If the string cannot be read into the given variables (i.e. there are too many or too few variables to read), then read_string() throws a type-mismatch warning. Warnings can also be thrown if read_string() cannot read a field that should be numeric, or if there is an overflow in a numeric field.

read_string() is a counterpart to print_string(). However, print_string() does not write spaces in between the fields, so unless spaces are put in explicitly its output cannot be read directly by read_string().


readFile()

syntax: readFile((table) table_array, (string) file_name [ ; (bools) ifHeader, resizeColumns, resizeRows = values])

Identical to readTable(), except reads the table string from a file. Searches all directories in the filePaths[] array.


readInput()

syntax: readInput((table) table_array [ ; (bools) ifHeader, resizeColumns, resizeRows = values])

Identical to readTable(), except reads the table string from the command line input.


readTable()

syntax: readTable((table) table_array, (string) table_text [ ; (bools) ifHeader, resizeColumns, resizeRows = values])

The counterpart to saveTable() is readTable(), which loads data into an array. It reads the data from a string, not a file, and tries to parse the data into the provided table. If the IfHeader variable is set to true, then the first line of text is skipped. Setting the Resize...Index arguments gives readTable() permission to adjust the size of the table to fit the data; in order for this to work the table must be a square array (i.e. not a list of 1-dimensional arrays that can be resized independently). The default values of the optional arguments are false for IfHeader, and true for ResizeFirstIndex and ResizeSecondIndex. An error results in a non-zero value for readTable.errCode and an error message printed to the screen.


round()

syntax: (numeric) rounded_integer = round((numeric) real_number)

C syntax: $round((double) x, (double) y)

Rounds a real number to the nearest integer. For example, 1.499 rounds to 1, 1.5 rounds up to 2, and -1.5 rounds ‘up’ to -1. Arguments may be scalars or arrays.


run()

syntax: (numeric) script_return_value = run((string) filename [, (composite) target])

The essential run() function runs a script stored in a file. run() compiles, transforms and finally runs the code in the current go{} location and search path. Any errors in the process are flagged along with the offending text. run() searches all directories in the filePaths[] array. If there is a direct return from the lowest level of a script (i.e. not within a function or type definition) then the return variable will be handed back to the calling script.

Normally the specified script is run in the user’s workspace. Optionally, we can pass some other variable or function as a second argument to run(), in which case the script runs inside that object instead.

A given script is often run multiple times. By default, when executing a script run() first checks to see whether it has seen that script before, and if so removes any root-level objects that the script defined when it was last run. This is to avoid type-mismatch errors when the script tries redefining those objects. If this is a problem then set run.CleanUp = false. (This parameter is not set within the arguments.) To make sure it knows when a script was rerun, make sure that the Boolean run.caseSensitive is set properly for your file system (it defaults to false meaning that Cicada assumes the file system doesn’t discriminate filename cases).


save()

syntax: Save((string) filename, (string) filedata)

syntax: save((string) file_name, (string) filedata)

C syntax: $save((string) filename, (string) filedata)

Saves the data from the second argument into the file specified in the first argument. There is no return value, although the error “I/O error” will be thrown if the save is unsuccessful.

Save() (capital ‘S’) extends the save() function by searching all paths in the DirectoryNames[] array. This is useful when filename involves a path that may only be found in another directory.

If our data isn’t already in string format, it’s easy to do an on-line conversion:


    save("my_data", (temp_str :: string) =! the_data)
   


saveTable()

syntax: saveTable((string) filename, (table) data [ ; (ints) fieldWidth, maxDigits, (string) voidString = values ])

The saveTable() routine exports data stored a set or array to a file. This routine attempts all file paths when saving, just like the general-purpose Save() function. The optional arguments are the same as those used by the function mprint().


sin(), $sin()

syntax: (numeric) y = sin((numeric) x)

C syntax: $sin((double) x, (double) y)

Returns the sine of its argument, which must be a numeric scalar or array.


size()

syntax: (numeric) var_size = size((var) my_var [, code, storageSize = (bool)])

C syntax: $size((var) my_var, (bool) storageSize, (int) var_size)

Returns the size, in bytes, of the first argument. For composite variables, this is the sum of the sizes of all its members. If two members of a composite variable point to the same data (i.e. one is an alias of the other), then that data will indeed be double-counted unless the optional second argument is set to true (its default value is false).

If a member points back to the composite variable, as in


    a :: {
       self := @this
       data :: int   }
   
    size(a)  | will cause an error
   

then the size of a, including its members and its members’ members, etc., is effectively infinite, and Cicada throws a self-reference error unless the second argument was set to true.


sort()

syntax: sort((table) table_to_sort, { (list) sort_by_list or (numeric) sorting_index } [, code, direction = { increasing / decreasing])

C-1 syntax: $makeLinkList((doubles) list_to_sort, (ints) link_list, (int) direction, (int) first_index, (ints or doubles) sorted_list)

C-2 syntax: $sort((ints) link_list, (int) first_index, (ints or doubles) lists_to_sort, (ints or doubles) sorted_lists)

Sorts a list or table, which is passed as the first argument. If it is a table then a second argument is required: either the column number to sort by, or a separate list to sort against. So the following two sorts are equivalent:


    myTable :: [10] { a :: b :: double }
    for (c1::int) in <1, 10> myTable[c1] = { random(), random() }
   
    sort(myTable, 1)    | sort by first column
    sort(myTable, myTable[].a)
   

The sort-by list will be unaffected.

Whether to sort in increasing or decreasing order can be specified after the semicolon/code marker; the default is ‘increasing’. The column to sort by, whether it is in the same table or in a separate list, must be numeric; sort() will not alphabetize strings (although it will work with character fields).

The Cicada sort() function first calls $makeLinkList(), then attempts $sort() using the link list from the first step. The C-coded $sort() only works if each list to sort is numeric; if that’s not true then $sort() uses a slower scripted sort function that works on more general data types. $sort() can sort multiple lists per function call: i.e. it accepts 2N+2 arguments.


springCleaning()

syntax: springCleaning()

C syntax: $springCleaning()

This function removes all unused objects from Cicada’s memory, in order to free up memory. An object is termed ‘unused’ if it cannot be accessed by the user in any way. For example, if we remove the only member to a function then that function’s internal data can never be accessed unless it is currently running.

Cicada tries to free memory automatically, but unfortunately it is not always able to do so. (The reason is self-referencing loops between objects in memory.) The only way to eliminate these zombies is to comb the whole memory tree, which is what springCleaning() does. When Cicada is run from the command prompt, it disinfects itself with a springCleaning() after every command from the user. But we might want to scrub the memory more often if we are running a lengthy, memory-intensive script that allocates and removes memory frequently. springCleaning() can help unjam arrays, if there is no member leading to the jamb.


sprint()

syntax: sprint([data to print])

sprint() is used for printing composite objects such as variables and functions; the ‘s’ probably originally stood for ‘spaced’, ‘set’, or ‘structure’. This is one of the most useful functions. It prints each member of an object separated by commas, and each composite object is enclosed in braces. Void members are represented by asterisks. The output is in exactly the format that Cicada uses for constructing sets.


    > sprint({ a := 5, b :: { 4, 10, "Hi" }, nothing }, 'q')
   
    { 5, { 4, 10, Hi }, * }, q
   

sprint() is the default calculator (i.e. calculator aliases sprint()).


subtract(), $subtract()

syntax: (numeric) z = subtract((numeric) x, (numeric) y)

C syntax: $subtract((doubles) x, (doubles) y, (doubles) z)

Computes z = x - y, for scalar or vector numeric data.


sum(), $sum()

syntax: (numeric) result = sum((numeric list) the_list)

C syntax: (numeric) $sum((doubles) the_list, (double) result)

Returns the sum of elements of a numeric list.


tan(), $tan()

syntax: (numeric) y = tan((numeric) x)

C syntax: $tan((double) x, (double) y)

Returns the tangent of its numeric argument (scalar or array).


throw()

syntax: throw((numeric) error_code [, (composite) error_script, (numeric) code_number, error_index] [, code, if_warning = (bool)])

C syntax: $throw((int) error_code, (bool) if_warning, (composite) error_script, (int) code_number, (int) error_index)

Causes an error to occur. This stops execution and throws Cicada back to the last enclosing trap() function; if there is none then Cicada either prints an error (if run from the command line) or bails out completely. The first argument is the error code to throw -- these are listed in Table 5. The optional second, third and fourth arguments allow one to specify the function, the part of the function (should be 1 unless the inheritance operator was used) and the bytecode word in that function the error appears to come from. If one sets the optional fifth argument to true, then the error will be thrown as a warning instead.

Although all real errors have error codes in the range 1-50, throw() is happy to cause an error with any integer error code. If the error code is zero then it will seem that throw() is not working, just because 0 is code for ‘no error’. throw() does require that the error code be zero or positive, so it gives a number-out-of-range error if the argument is negative. However, throw(2) also gives an out-of-range-error.. because that’s what error code 2 represents!


top()

syntax: (numeric) vartop = top((composite variable) my_var)

Returns the number of indices of the argument variable. The argument must be a composite variable or equivalent (e.g. set, function, class, etc.). top() does not count hidden members. Therefore the value it returns corresponds to the highest index of the variable that can be accessed, so


    my_var[top(my_var)]
   

is legal (unless the top member is void) whereas


    my_var[top(my_var) + 1]
   

is always illegal (unless we are in the process of defining it). Notice that in both of these cases we can replace the top() function by the top keyword, which is always defined inside of array brackets: e.g. my_var[top+1].

For technical reasons top() is defined inside of cclang.c rather than in defs.cicada. Don’t try to use the C-coded $top(), it just confuses the compiler.


transform()

syntax: [(composite) target_function =] transform((string) bytecode [, (function) target_function ] [, code, codePath = @(set of functions), errInfo.filename/sourceCode/opCharPositions = (string)])

C syntax: $transform((string) bytecode, (function) target_function, (set of functions) codePath, (string) errInfoFilename, (string) errInfoSourceCode, (string) errInfoOpCharPositions)

Copies compiled bytecode stored as a string (1st argument) into the internal code of a target function variable (return value or 2nd argument), without running the code’s constructor. The bytecode is typically generated using the compile() function:


    newFunction :: transform(compile("toAdd := 2; return args[1]+toAdd"))
   

but it is also possible to write the bytecode by hand. This probably won’t work -- the member IDs depend on your workspace history -- but the code looks something like:


    newFunction :: {}
    (newBytecode :: string) =! { 8, 47, 10, 314, 54, 2, 4, &
                         5, 8, 237, 10, -999, 27, 12, 40, 54, 1, 10, 314, 0 }
    transform(newBytecode, newFunction)
   

At this point it is as if we had written


    newFunction :: { toAdd := 2; return args[1]+toAdd }
   

We can now execute the new code by running the target function.


    newFunction(3)       | will return 5
   

When we define a function as the return value of transform(), as in the previous example, the constructor runs automatically. If we don’t want this to happen, we should pass in a target function as the second argument of transform(). If a function appears here, that is not void, then that function’s existing codes are erased and replaced by the transformed code (assuming no error) without running the constructor.

The default search path for the transformed code is the same search path used the function that called transform(), but we can replace this default with a manually-constructed path by passing a set of variables as the optional 3rd argument. For example


    A :: B :: C :: { D :: {} }
    transform(newBytecode, newFunction, { A, C.D, B })
   

causes newFunction()’s search path to go from newFunction to A to C.D and finally end at B.

The optional fourth, fifth and sixth arguments help Cicada to give helpful error messages if the new code crashes when we try to run it. The fourth argument is just the name of the file containing the script, if applicable (otherwise set it to the void). The fifth argument is the original ASCII text of the script, and the sixth is the mapping between bytecode words and script characters that is an optional output of compile(). Here is how we pass all of this information between compile() and transform():


    fileName := "scriptFile.cicada"
    myScript := load(fileName)
    opPositions :: string
   
    scriptBytecode := compile(myScript, fileName, opPositions)
   
    newFunction :: {}
    transform(scriptBytecode, newFunction, { }, fileName, myScript, opPositions)
   

It is certainly possible to pass bogus bytecode to transform() (particularly if we’re trying to write out the binary ourselves). transform() checks the bytecode’s syntax, and if there is a problem then it crashes out with an error message.


trap()

syntax: (numeric) error_code = trap([;[;[;]]] code_to_run)

Runs the code inside the parentheses (i.e. its argument), and returns any error value. Error codes are listed in Table 5. No code marker is needed within a trap() call. Upon error, the argument stops running and the error code is returned; if the argument finishes with no error then the return value is 0. trap() thus prevents a piece of dubious code from crashing a larger script. Note that some egregious errors are caught at compile-time and trap() will not be able to prevent those -- this includes some type-mismatch errors like trap(string = 4).

A trap() call can optionally print out an error message if needed. To do this we add a semicolon (or code marker) immediately at the beginning of its arguments. Two opening semicolons causes trap() to re-throw the error (without printing an error message), effectively redirecting the source of the error to the trap() command. Three opening semicolons causes it to both print any error message and re-throw the error as a thrown-to error -- so code execution will then fall back to the next enclosing trap() and print another message. This can help to trace errors through multiple nested functions.


    trap((a::*) = 2)                  | prevents a crash
    errCode := trap((a::*) = 2)       | returns the type-mismatch error code
    trap( ; (a::*) = 2)               | prints a type-mismatch error but doesn't crash
    trap( ; ; ; (a::*) = 2)           | prints a type-mismatch error, then crashes out
   

Notice that trap() will also print warning messages (minor errors that don’t stop the program). Warning codes are the same as error codes except that they are negated: for example an out-of-range error will return error code 2, but an out of range warning will return -2. If several warnings have been produced, trap() will only print and return the error code for the last one.

The trap() function is actually defined in cclang.c, and has the unique ability to run its arguments in whatever function called trap(), rather than in a private argument variable used by all other built-in and user-defined functions. So variables which are defined within the trap() argument list will be accessible to the rest of the function. Also this and parent have the same meaning inside a trap() command as outside of it. The C-coded $trap() lacks this ability and has the usual run-constructor arguments flag, so just use the scripted function call.


type()

syntax: (numeric) theType = type((variable) var [, (numeric) memberIndex])

C syntax: $type((variable) var, (int) memberNumber, (int) theType)

Returns a number representing the type of the given variable (one argument) or one of its members (if there is a second argument). The variable is the first argument, and the member index is the optional second argument. The types IDs are listed in Table 1. A composite-typed variable or member only returns a ‘5’ even though its full type is properly determined by its code list -- use the bytecode() function to obtain the code list.


uppercase()

syntax: (string) uppercase_string = uppercase((string) my_string)

Converts a mixed-case string to uppercase.


what()

syntax: (string) var_names = what([ (composite) var_to_look_in ])

Returns the names of the variables in the current directory, which is usually root (see go() and jump()). If an argument is provided then what() returns the names of the variables inside that argument variable. Remember that what() requires the parentheses!


where:

the current search path of the user, stored as a string.


writeTable()

syntax: (string) table_string = writeTable((table) data [ ; (ints) fieldWidth, maxDigits, (string) voidString = values ])

writeTable() exports table data as a string. This function takes the same three optional arguments as mprint().


Prev: Define operator flags    Next: C functions for working with whole arguments



Last update: November 12, 2025