1 Introduction
2 Examples
3 Full Syntax Description
3.1 Literal Values4 Error Reporting
3.2 Operators
3.3 Parentheses, Braces, Brackets
3.4 Variables
3.5 Expression Sequences
3.6 Built-in Functions
3.7 User Defined Functions
3.8 Controlling Structures
3.9 Precedences
3.10 A Simple Example
You may enter expressions iteractively, but you can read files into the interpreter as well. The special file called .calc in your home directory is read automatically at startup, if it exists.
Several built-in mathematical functions may be used, like sin and cos. There are also two predefined constants, namely E, and PI. (Mind the case! See example 3.)
Variables are also available, they can be used without any prior declaration. (Their default value is 0, when they're being used uninitialized.) Values can also be strings, these can also be assigned to variables just like numbers. (Example 4 and 5)
Function declaration is also very simple - although somewhat different
than that in C. In Calc, function bodies also are expressions which are
evaluated each time the function is called. Positional arguments of functions
are evaluated exactly once for every function call, no matter how many
times do they appear in the function body. Function calls are exactly like
in C or like for built-in functions. (Examples 6 and 7)
1 | 2 + 3 * 5 ^ 2 | 77 |
2 | 2 * ( 2-3 } | parse error at char 11 |
3 | cos(E) + sin(PI^2) | -1.34204 |
4 | my_var = 12.2 / 5 | 2.44 |
5 | hello_world = "Hello World!" | "Hello World!" |
6 | fun max(a,b) = if (a > b) a else b | 0 |
7 | max(1,2) | 2 |
Figure 2: Snapshot of the example run
If you write something that causes infinite loop, don't worry - you can always terminate the evaluation with the Abort button which becomes sensitive during evaluations. With Calc, you can also keep track of all existing variables and their values, and of functions, user defined and built-in, through Variable List and Function List windows.
Figure 3: Variable and Function Lists
3.1 Literal Values
Literal values are either numbers or strings. Numbers may be entered using the well known IEEE scientific notation, e.g., 12.34, 1.234e1, 1234E-2 etc. Hexadecimal numbers are also accepted if they start with the generally used prefix 0x, e.g., 0xA1F2. Strings can be entered between double quotes. Four escape characters are also accepted: \n, the newline character, \t, the tabulator, \", a double quote and \\, a normal backslash character. Newline is only useful if you would like to display a multi-line message with the built-in function msg. When boole values are needed, numbers are expected, where 0 is FALSE, everything else is TRUE.In some places numbers are expected, elsewhere strings. Numbers are automatically converted to strings whenever necessary, on the other hand, strings are only converted to numbers if they contain an IEEE formed number, and nothing else. Otherwise an error is generated. Conversion might also be forced with tostr and todbl.
- 1.234e1
- 0xA1F2
- "Hello!\nThis is so \"Cool\"!"
Sometimes a calculation might result special values like INF (infinity) and NAN (not a number). These values can be tested with isinf and isnan functions. There is also a third value type, namely invalid value. This is an internal type, and is rarely noticable by the user.
- E
is converted to "2.71828"- " 1.12e3"
is converted to 1120- "This is not a number"
is converted to double expected at char 13.2 Operators
Standard binary and unary mathematical operators, like +, - (negation and subtraction), *, /, ^ (power), % (modulo) can be used as usual. Comparison operators, like <. >, <=, >=, != (not equal), == (is equal) behave exactly like they do in C. Logical negation (!), conjunction (&&) and disjunction (||) also behave like in C, and are lazily evaluated.
3.4 * PI / E > 0 1 a == 1 && b > 0 || !c depends on a, b and c 3.3 Parentheses, Braces, Brackets
Parentheses are used to raise precendece of a subexpression, like in standard mathematics. They are also grouping expression sequences into single expressions (in fact, this does nothing else, than raises the precedence of the semicolon (;) operator). Braces have an additional framing side effect: every variable created inside the brackets is freed automatically at the end of the frame (the closing brace). Therefore braces are often used when defining user functions for enclosing the function body to enable the use of local variables. (This is in fact unnecessary, since a function definiton creates a frame inevitably, even without braces.)
2 * (3 + 4) / (E + 1) 3.76518 fun add_two(a) = { __locvar = a + 2; __locvar } 0 Brackets currenlty behave exactly like parentheses do, but this will change in the near future with the introduction of arrays. Until then, you are kindly asked not to use brackets.
3.4 Variables
Variables are names starting with a letter and containing only alphabetical characters, digits and underscores. They can be used without prior declaration: first value assignment will create a new variable with the given name in the current frame. Value assignment works just like in C using =, +=, -=, etc. operators. Increment and decrement operators (++, --) also exist both in prefix and postfix form.If needed, variables might also be specifically declared with the var keyword. In that case, a new variable is forced to be created under the given name, even when another one already exists. This is useful when writing user functions to force local variables to be really local. The var keyword's syntax is the following:
- var <varname> declares one variable, equivalent to var (<varname>)
- var (<var1>, <var2>, ...) declares several variables at the same time.
A special syntax in connection with variables is also allowed: a literal number followed immediately (optionally separated by whitespaces) by a variable has the same effect as writing the multiplication operator (*) between them. Note that this doesn't apply to the built-in constants, E and PI.
foo = 5 5 bar = 3; bar *= 2.14 6.42 myvar = 2; 3.14 myvar 6.28 a = 5; { a = 2 }; a 2 a = 5; { var a; a = 2 }; a 5 3.5 Expression Sequences
An expression may consist of several subexpressions in succession if they are separated by a semicolon (;). In this case, the value of the whole expression is the value of the last expression in the sequence. This means that sequencing is meaningful only when all the expressions but the last have a side effect. On the other hand, this is a fundamental tool when writing user defined functions.Please note, that the semicolon (;) separates the subexpressions, not like in C where it terminates statements! It can't be added anywhere freely! If you get a parse error message, always check the semicolons first.
a = 2; a *= 3; a -= E; a ^ 2 10.7697 fun foo(a,b) = { a += 2; b *= 3; a/b } 0 3.6 Built-in Functions
Built-in functions are always called using the following syntax:<funname> (<exp1>, <exp2>, ...)where funname is the name of the function and expi is the expression to be evaluated as the ith argument. The following built-in functions exist currently:
- cos, sin, tg (AKA tan), ctg (AKA cot), lg (base 10), ln (natural), exp, abs, sqrt These are standard mathematical functions with the usual behaviour. They all require a single argument, which must be a number.
- log The logarithm of the second argument with the first argument as the logarithm base. Equivalent to ln(arg2) / ln(arg1).
- pow Raises the first argument to the power of the second. Equivalent to arg1 ^ arg2.
- tostr Returns its argument converted into a string value.
- todbl Returns its argument converted into a number, if possible, otherwise NAN.
- isstr, isdbl, isnan, isinf Evaluate to 1 if the single argument is a string, number, NAN or INF, respectively. Otherwise yield 0.
- error Raises a user error, message taken from the single argument. See Error Reporting.
- iserr 1 if the evaluation of its argument causes an error, otherwise 0.
- onerror Has two arguments. First it evaluates the first argument. If no error occurs, returns its value. On the other hand, if an error occurs, it is forgotten and the second argument is evaluated, its result being the result of the whole expression. If this causes an error too, that error remains unhandled.
- strlen The length of its argument as string in characters.
- strpos The position of its second argument in the first argument (both are strings). If the second argument doesn't appear in the first, returns -1.
- strsub Has three arguments, third is optional. Returns the substring of the first (string) argument, starting from the character indexed by the second argument ending with the character indexed by the third argument (or up to the end of the string). Indexes are truncated and bounded to limits automatically.
- strcat Any number of arguments. Returns a string which is the concatenation of all of its arguments, in the specified order.
- msg Displays a message to the user with text taken from the first argument. (See Figure 4/a)
- read Promts the user for a string with the first argument as the query message. The entered string is returned. (See Figure 4/b)
- ask A yes/no question is asked from the user with the first argument as the question. The answer is returned as 1 or 0, depending on the answer of the user. (See Figure 4/c)
- eval Starts a new parsing and evaluation on its argument, which must be a string. Ideal for evaluating expressions read from the user.
Figure 4: Msg, Read and Ask dialogs
![]()
![]()
![]()
3.7 User Defined Functions
The syntax of user function definition is the following:fun <funname> (<arg1>, <arg2>, ...) = <bodyexp>Such a declaration is also an expression naturally, it always evaluates to 0. User defined functions are identified by their names alone, number of arguments doesn't count. Therefore if you define a function with two arguments, and then define another one with the same name, but three arguments, the second definition overrides the first one. User defined functions are called exactly like built-in functions. The function body of a user function is reevaluated whenever the evaluation of a corresponding user function call is requested. Therefore functions shouldn't be considered as macros that expand at the time of parsing but as pointers to an address which pointer is only resolved at execution time. This also means, that when defining multiple functions that rely on each other, they don't have to be defined in strict call order.At a user function call a new variable frame is created, expressions specified as arguments are evaluated exactly once, and local variables given in the function header with the corresponding expressions' results as initial values are created. At function exit, the frame is dropped. Since arguments are stored in ordinary variables, these variables may be freely modified in a function body. There is a special expression which is only meaningful in function bodies. The syntax is the following:
return <retval>With this expression, you can skip right out of the current function body with return value retval. The behaviour of this command outside function calls is undefined.3.8 Controlling Structures
Controlling structures are not entirely unlike C structures, but there are minor differences. Mind the syntax of the for cycle and the switch especially!
- if (<condexp>) <thenexp> [ else <elseexp> ]
- condexp is evaluated. If it's value is not 0, thenexp is evaluated, and the also result of the whole expression is the result of thenexp. If condexp yields 0, then either elseexp is evaluated or 0 is returned. The following use of a condition perhaps looks weird to a C programmer, but completely accepted in Calc:
Result = if Test then a^2 else sqrt(b)- while (<condexp>) <doexp>
- Creates a loop. In each cycle, condexp is evaluated. If it returns 0, the loop is broken, otherwise doexp is executed (its result is dropped) and the loop is restarted. This expression always returns 0.
- do <doexp> while (<condexp>)
- Creates a loop, similar to the previous one, the only difference that condexp is evaluated after the execution of doexp. Always returns 0. Has the same effect as
<doexp>; while (<condexp>) <doexp>- for (<iniexp>, <testexp>, <stepexp>) <exp>
- Although the behaviour is identical to that of a C for cycle, the syntax is somewhat different: there are commas (,) instead of semicolons (;) in the head. This is so, because in Calc, semicolons are used to separate expressions from each other. iniexp is evaluated exactly once at the beginning of the cycle. The cylcle is continued as long as testexp evaluates to a value different than 0. In each cycle first exp, then stepexp is evaluated. The return value of the whole expression is 0. Has the same effect as
<iniexp>; while (<testexp>) (<exp>; <stepexp>)Note that in this equivalent form, the parentheses are necessary, otherwhise stepexp would be evaluated only once, after the complete cycle has finished.- switch (<exp>) { case <testexp1> : <bodyexp1> case <testexp2> : <bodyexp2> ... [ default: <defaultbody> ] }
- This syntax resembles the C switch syntax very much, but as the syntax so the behaviour differs a little. Here test expressions can also be arbitary expressions - they are not limited to literal constants. exp is evaulated exactly once, and its value is compared to the freshly evaluated testexps. When there's a match, the corresponding bodyexp is evaluated and the result is returned as the result of the whole expression. The default case always matches any values, therefore there is no meaning in putting more cases after it. The type of the test expressions must match the type of the switching expression (i.e., number or string). Please note, that the braces used in switch do not create a new variable frame! The following use of a switch perhaps looks weird to a C programmer, but completely accepted in Calc:
monthname = switch (month) { case 1: "January" case 2: "Februray" case 3: "March" case 4: "April" case 5: "May" case 6: "June" case 7: "July" case 8: "August" case 9: "September" case 10: "October" case 11: "November" case 12: "December" default: error("unknown month") }3.9 Precedences
The precedences of the operators and linguistical terms is summarised in the following table. It is beginning with the lowest (weakest) precedence and ended with the highest (strongest).It is important to notice, that the semicolon (;) has the lowest precedence, therefor expression sequences must almost always be grouped with parentheses or braces, except where unambiguous.
Lowest ; return =, +=, -=, *=, /=, %=, ^= if, do, while, for, switch, var, fun || && ! ==, != <, >, <=, >= +, - (subtraction) *, /, % - (negation) ^ Highest ++, -- 3.10 A Simple Example
This function calculates the square root of a number with a given precision using Newton's method. Even in such a simple example you may notice many advanced features of Calc.fun n_sqrt(num, prec) = { var (root, prev); root = num/2; do { prev = root; root = (num/root + root) / 2 } while (abs(prev - root) > prec); root }
If there is an error which is recognised only at runtime, it is reported when the critical piece of code is evaluated. From that point, the error propagates straight up, meaning that none of the following expressions is evaluated, cycles are broken and functions are returned from. If the error is caught with an onerror or iserr call, it is dropped, otherwise it is brought to toplevel, and reported to the user. It is only important to understand the propagation of errors if you want to catch them, although this is often unavoidable.
When you press the Abort button during an evaluation, all calculations are stopped immediately, and "user break" is reported. Abort propagates like errors do, only user breaks can't be caught or tested for.
The possible error messages are summarised in the following table, but some of them should not occur at all (another error should occur somewhat earlier instead or it is caused by internal faults), these are marked with an asterisk.