Name | Volker Oth |
Born | 1971 |
Country | Germany |
Occupation | Embedded C software development (automobile) |
Contact | You might contact me by mail if you have questions/bug reports/suggestions regarding Calcutta: VolkerOth (at) GMX.de |
Official Homepage
Bitbucket Project Homepage
Details of the latest changes can be found here.
As of version 0.86, Calcutta became an Open Source project. All source
files are released under the Apache
License 2.0. In a nutshell that means you can use them and modify them
even for closed source or commercial projects, as long as you leave some copyright
info in and give appropriate credit. See the linked Apache License for details.
Each file of the source code should contain a header with the license information.
The whole source code, the icons and the HTML help are now stored in a Git repository hosted by Bitbucket.
I recommend to use SourceTree to handle the repository but there are several other tools and also Eclipse plugins.
Repository URL: https://bitbucket.org/fade0ff/calcutta
Expression |
Comment |
prime(2**31-1) out = true |
This number is indeed prime and we can find out in the tenth of a second |
a=1;b=a++
out = 1 b out = 1 a out = 2 |
Note that the postincrement ++ works as
it should: a is increased after b is assigned the value of a (still 1) and after the whole expression is evaluated (also out=1). |
fraction(1.34p456) out = 22387/16650 |
Rational number with endless periods can be expressed as rational fraction. Indeed there is no loss of
precision as long as no irrational function as sin,sqrt etc. is used. |
hex(65536) out = 0x010000 |
Get hexadecimal output |
bin(0x7e) out = 0b01111110 |
get binary output |
(1+2*3-4/(2*3)) out = 6.3333333333333333 fraction(out) out = 19/3 out*6 out = 38 |
Note that the variable out is always
overwritten with the last result. Also note that even if a decimal is printed out, the internal
representation is always a rational fraction. That's why multiplication with 6 ends with an integer
number though the operand had an endless period |
fac(2000) out = 0.3316275092450633e+5736 |
factorial of 2000. This is way beyond the scope of normal calculators or even double precision.
Try to print out the whole number with full(out) |
hex(0x80) out = 0x0080 hex(-128) out = 0x80 ~0x80; out = -129 hex(out) out = 0xff7f |
Note that while 0x80 seems to fit into
a byte, it is automatically evaluated as 0x0080 to express that it's
unsigned, while hex(-128) is evaluated as 0x80: here the most
significant bit is set, so it's a negative number. As 0x80 is internally represented as 0x0080, the binary complement evaluated to 0xff7f, which can only be evaluated as negative number, as the most significant bit is set. |
bin(0b111
^ 0b101) out = 0b00000010 |
This goes to show that "^" is not a "to
the power of" operator, but the binary XOR. Also note that binary
numbers are always extended to the next byte, word, dword etc. boundary |
true
^ true out = false |
And yes, as in Java, the XOR is also
defined on boolean values |
full(2**150) out = 1427247692705959881058285969449495136382746624 |
Already quite a large number. But not nearly as large as it can get ;) |
5<<3
== 5*8 out = true |
Was to be expected |
false
&& ((z=1)==1) out = false z z ^ Empty or invalid expression |
Note that "&&" and "||" are
boolean short-circuit operators. If the left side is sufficient to evaluate
the expression (false && exp is always false), the right side
is not evaluated. In this case, 'z' is not set to 1. Therefore it's
still undefined! |
false &
((w=1)==1) out = false w out = 1 |
Same
example with non-short-circuit operator &. This time the right side is evaluated
and 'w' is defined. |
sqrt(2**2000) out = 10.7150860718626732e+300 |
Note that functions like sqrt are not
simply passed to the double sqrt. Most simple calculators will fail here. |
2 out = 2 2; out = <UNDEF VALUE> |
A separator consumes an existing value |
a
= {1,
"lurch", {2,true}} out = {1,"lurch",{2,true}} a[1] out = "lurch" a[2] out = {2,true} a[2][1] out = true a[2][0] = "new" out = {1,"lurch",{"new",true}} |
Define a list by putting value separated by commas into curved braces Access list elements by using index in brackets (reading or writing is allowed) Lists are allowed as list elements -> multidimensional lists |
Integer numbers: |
1, 2e3, 1971e+3 |
Decimal numbers (p marks beginning of periodic part) |
1.345, 2e-3, 1.2p3 |
Hex numbers: |
0xdeadbeef, 0xe |
Binary Numbers: |
0b010101 |
Octal Numbers: |
070, 066 |
a=1;b=2 | No need to define them, just assign a value |
a=1; a="oink"; a=true | 1st a is a number, then a string, then a boolean |
a=c | Now c is not defined yet -> this will result in an error |
my_1st_string = "Hello World" | Now we have a string |
my_1st_boolean = true | And now a boolean |
Operator |
Use |
Precedence |
Valid on |
Description |
+ |
+op1 |
1 |
Number |
Marks numeric value as positive |
++ |
++op1 op1++ |
1 |
Number |
Preincrement, postincrement |
- |
-op1 |
1 |
Number | Negative value of operand |
-- |
--op1 op1-- |
1 |
Number |
Predecrement, postdecrement, |
~ |
~op1 |
1 |
Integer Number |
Binary complement |
! |
!op1 |
1 |
Integer Number, Boolean |
Logical complement (true - false, 0 - >0) |
** |
op1**op2 |
1 |
Number |
op1 to the power of op2 |
* |
op1*op2 |
2 |
Number |
Multiplication |
/ |
op1/op2 |
2 |
Number |
Division |
% |
op1%op2 |
2 |
Integer Number |
Integer Division Remainder |
+ |
op1+op2 |
3 |
Number, String, List |
Addition, String-Concatenation, List-Concatenation |
- |
op1-op2 |
3 |
Number |
Subtraction |
<< |
op1<<op2 |
4 |
Integer Number |
Shift left |
>> |
op1>>op2 |
4 |
Integer Number |
Shift right |
< |
op1<op2 |
5 |
Number,String |
Smaller than (result: boolean) |
<= |
op1<=op2 |
5 |
Number,String | Smaller than or equal (result: boolean) |
> |
op1>op2 |
5 |
Number,String | Larger than (result: boolean) |
>= |
op1>=op2 |
5 |
Number,String | Larger than or equal (result: boolean) |
== |
op1==op2 |
6 |
Number, Boolean, String, List |
Equals (result: boolean) |
!= |
op1!=op2 |
6 |
Number, Boolean, String, List |
Not equal (result: boolean) |
& |
op1&op2 |
7 |
Integer Number, Boolean |
Integer Number: binary AND, boolean: logical AND (no short-circuit!) |
^ |
op1^op2 |
8 |
Integer Number, Boolean |
Integer Number: binary XOR, boolean: logical XOR (no short-circuit!) |
| |
op1|op2 |
9 |
Integer Number, Boolean |
Integer Number: binary OR, boolean: logical OR (no short-circuit!) |
&& |
op1&&op2 |
10 |
Integer Number, Boolean |
logical AND (short-circuit!) |
|| |
op1||op2 |
11 |
Integer Number, Boolean |
Logical OR (short-circuit!) |
= |
var=exp |
13 |
Left Side: variable, Right side: any expression |
Defines
variable var if it doesn't exist yet and
assigns it to the value of the expression on the right side |
*= | var*=op | 14 | Left: variable Right: numeric expression |
same as var = var * (op) (multiplication) |
/= | var/=op | 14 | Left: variable Right: numeric expression |
same as var = var / op (division) |
+= | var+=op | 14 | Left: variable Right: Number, String, List |
same as var = var + op (addition/ Concatenation) |
-= | var-=op | 14 | Left: variable Right: Number |
same as var = var - op (subtraction) |
<<= | var<<=op | 14 | Left: variable Right: Number |
same as var = var << op (shift left) |
>>= | var>>=op | 14 | Left: variable Right: Number |
same as var = var >> op (shift right) |
|= | var|=op | 14 | Left: variable Right: Number.Boolean |
same as var = var | op (or) |
&= | var&=op | 14 | Left: variable Right: Number, Boolean |
same as var = var & op (and) |
^= | var^=op | 14 | Left: variable Right: Number, Boolean |
same as var = var ^ op (xor) |
Cast Operator |
Valid on |
Description |
(u8),(u08),(byte) |
Number |
Casts expression to unsigned 8bit value (0..255) |
(s8), (s08) |
Number |
Casts expression to signed 8bit value (-128..128) |
(u16),(word),(char) |
Number |
Casts expression to unsigned 16bit value (0..65535) |
(s16), (short) |
Number |
Casts expression to signed 16bit value (-32768..32767) |
(u32),(dword) |
Number |
Casts expression to unsigned 32bit value (0..4294967295) |
(s32),(int) |
Number |
Casts expression to signed 32bit value (-2147483647..2147483646) |
(u64),(qword) |
Number |
Casts expression to unsigned 64bit value (0..18446744073709551616) |
(s64), (long) |
Number |
Casts expression to signed 64bit value (-9223372036854775807..9223372036854775806) |
(double) |
Number |
Castto double |
(integer) |
Number |
Cast to integer number (same as trunc(operand)) |
(string) | any value | Converts a value to a string. The resulting string will look exactly as the default output on the console. |
Function |
Description |
abs(x) |
Absolute value of number x |
trunc(x) |
Integer part of number x (cutting of decimal part) |
floor(x) |
Integer i closest to number x with i <= x |
ceil(x) |
Integer i closest to number x with i >= x (same as -floor(-x) ) |
round(x) |
Integer closest to number x + 0.5 (same as floor(x+0.5) ) |
pow(x,N) |
Calculates number x to the power of number N (same as x**N) |
root(x,N) |
Calculates the Nth root of number x (same as x**(1/N) ) |
sqrt(x) |
Calculates the square root of number x (same as root(x,2) ) |
fac(x) |
Calculates factorial of number x (normally written as x!, but "!" is logical complement) |
prime(x) |
Returns boolean if integer number x is (probably) a prime number |
exp(x) |
Returns Euler's number e raised to the power of number x
|
log(x) |
Returns the natural logarithm (base e) of number x |
log10(x) |
Returns the logarithm (base 10) of number x |
ld(x) |
Returns the logarithm digitalis (base 2) of number x |
bits(x) |
Returns the number of bits needed to represent the integer number x |
sin(x) |
Returns the trigonometric sine of a radian angle x (number) |
sinh(x) |
Returns the trigonometric hyperbolic sine of a radian angle x (number) |
asin(x) |
Returns the trigonometric arc sine of a radian angle x (number) |
cos(x) |
Returns the trigonometric cosine of a radian angle x (number) |
cosh(x) |
Returns the trigonometric hyperbolic cosine of a radian angle x (number) |
acos(x) |
Returns the trigonometric arc cosine of a radian angle x (number) |
tan(x) |
Returns the trigonometric tangent of a radian angle (number) |
tanh(x) |
Returns the trigonometric hyperbolic tangent of a radian angle (number) |
atan(x) |
Returns the trigonometric arc tangent of a radian angle (number) |
Function |
Description |
print(x) println(x) |
Print value x on the console (x can be a number, boolean or string) println works as print, but adds a linefeed |
hex(x) |
Show integer number x in hexadecimal representation* |
bin(x) |
Show integer number x in binary representation* |
oct(x) | Show integer number x in octal representation* |
full(x) |
Show number x as accurate as possible BEWARE! For rational numbers with more digits after the decimal point than the internal scale provides, the result will be less precise. E.g. full(1/3)==(1/3) results in false, since 1/3 is precise, but full(1/3) is not!!! |
fraction(x) |
Show number x as a rational fraction |
defined(x) |
Returns true, if the variable x is defined, else false. Will not work on values! |
load(x) |
Load file with name x (must be a
string!). Files can contain all the operators, literals and functions described here. E.g. load("test.clc") |
die(x) |
Immediately exits the current expression evaluation and
creates a user defined parse exception x, where x must be a string.
E.g. a==1 || die("a is not 1"); |
rnd() | Returns random number N where 0 <= N <= 1 |
time() | Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT |
clear() | Undefines all user variables and user functions |
listv() | Returns a sorted list with all defined variables (as strings) |
listf() | Returns a sorted list with all defined user functions (as strings) |
eval(x) | Evaluates the expression inside string
<x>. E.g. eval("1+3*2") will evaluate as 7. Every operator, function and literal is allowed within the expression, only quotes (") are forbidden. |
Function |
Description |
lfill(value,size) |
Returns a list filled with value until size is reached 'a= fill(true,3)' results in {true,true,true} |
sfill(string,size) | Returns a string filles with
string until size is reached 'a= sfill("ab",5)' results in "ababa" |
sub(string,pos,len) | Returns a substring of string
starting at position pos and
containing len characters 'sub("12345",2,3)' results in "345" |
sub(list,pos,len) | Returns a sublist of list
starting at position pos
and containing len
list elements 'sub({1,2,3,4,5},2,3)' results in {3,4,5} |
insert(string,insert,pos) | Returns a string with the string insert inserted into string string at position pos 'insert("12345","AB",2)' results in "12AB345" |
insert(list,insert,pos) | Returns a list with the list insert inserted into list list at position pos 'insert({1,2,3,4,5},{"A","B"},3)' results in {1,2,3,"A","B",4,5} |
replace(string,replace,pos) | Returns a string with the string replace replaced in string string beginning with position pos 'replace("12345","AB",2)' results in "12AB5" |
replace(list,replace,pos) | Returns a list with the list replace replaced in list string beginning with position pos 'replace({1,2,3,4,5},{"A","B"},2)' results in {1,2,"A","B",5} |
index(string1,string2) | Returns (0 based) index of string2 inside string1, if found, else -1 (searching from beginning) |
index(list,value) | Returns (0 based) index of value inside string1, if found, else -1 (searching from beginning) |
lastindex(string1,string2) | Returns (0 based) index of string2 inside string1, if found, else -1 (searching from end) |
lastindex(list,value) | Returns (0 based) index of value inside string1, if found, else -1 (searching from end) |
size(variable) | returns
the size of a variable. For a list, this is the number of elements: 'a={1,2,3,{1,2,3}}; size(a)' results in 4 For a String, this is the number of characters 'a="0123456789"; size(a)' results in 10 For any other value (number, boolean), this is 1 |
{} | empty list |
{1,2,3} out = {1,2,3} |
simple list |
{true, 2,
"sheep" } out = {true, 2, "sheep" } |
mixed list |
{1, {1,2,3}, 3} out = { 1, {1,2,3}, 3} |
list inside list |
a=1;
b=2; { a, b, 3} out = {1,2,3} |
Note that the variables are evaluated when creating the list |
{
sin(0), cos(0), tan(0) } out = {0,1,0} |
Same with functions |
a
=
{1,2,3};
a[0] out = 1 |
Just like in C or Java |
a
=
{1,2,3};
a[0] = a[2] = 0; a out = {0,2,0} |
Indexed variables behave just like ordinary variables. You can write to them and also right association is working. |
b={
{1,2}, {3,4}, {4,5} };
b[0][0] = b[2][0] = 0;b out = {{0,2},{3,4},{0,5}} |
Same with two dimensions |
a = { 1, 2, 3 }; a[3] Index 3 out of bounds. |
Neither reading nor writing to an undefined index is allowed. |
{1,"a",true,
{1,2}} == {1,"a",true, {1,2}} out = true |
equality operator works on lists as well |
a = {}; a = a + {1}; a = a + {2}; a out = {1,2} |
plus operator allows list concatenation |
function
square(a) { a*a } square(4) out = 16 square(true) Number expected on the left side of operator |
The
return value is just the value of
the expression "a*a" Works with numbers Doesn't work with boolean |
function square(a) { a*a; } square(4); out = <UNDEF VALUE> |
Beware! The semicolon after the last statement of the function consumes the value |
function
test(a,b) { c=a*b; println(c); d=a+b; println(d); } |
Two
parameters here. Use as many as you want. |
lurch = 2; function lurchtest() { println(lurch); lurch = 3; println(lurch) } lurchtest() 2 3 out = 3 lurch out = 2 |
Note
that first the global variable is
read (which contains
2). Then a local variable is written to. With the next read access, the local variable is read, which now hides the global variable!!! |
function
ctest(a,b) { c } |
This
is allowed, since the syntax is
correct. However when you call this function, it will fail if no global variable c exists. It will work however if the variable exists! |
a
= 1; if ( a == 1) { b = 0 } else { b = 1 } out = 0 |
b is assigned 0, note that the result of the statement equals the if branch |
a = 1; |
This does the same as the example above by directing assigning the statement to b. Note that this is perfectly allowed in contrary to C etc. where you would need to use the "?:" operator |
a = 1; |
Note that the semicolon consumes the value. Thus the return value is undefined!!! |
a
= 1; sin ( if (a==1) {PI} else {1}) out = 0 |
Note how the result of the statement can be passed as parameter |
if
(false) {1} out = <UNDEF VALUE> |
There is no else branch and no statement after this that would define a result. Thus the value of this statement is undefined! |
Furthermore the ternary operator "?" is defined as in C and Java.
(<condition>) ? <true_statement> : <false_statement>
Remarks:
a = 1; |
b is assigned 0, note that the result of the statement equals the true branch |
a
= 1; |
This does the same as the example above by directing assigning the statement to b. Note that this is perfectly allowed in contrary to C etc. where you would need to use the "?:" operator |
a = 1; |
Note that the semicolon consumes the value. Thus the return value is undefined!!! |
a = 1; |
Note that the semicolon after the false statement consumes the return value of the whole expression. Still a is defined correctly. Using parentheses around "1" would create an evaluator stack underflow as well. |
a = 1; sin ( (a==1) ? PI : 1) out = 0 |
Note how the result of the statement can be passed as parameter |
for (i=0; i<10;i++) { print(i) } 0123456789 |
Nothing spectacular. Just note that since "i++" evaluates 9, while "i" is already 10! |
for (i=0; i<10;i=i+1) { print(i) } 0123456789 out = 10 |
"i=i+1" works exactly the same as "++i" would |
for (i=sin(0); i<3**2+1;i=i+1) { print(i) } 0123456789 |
You can use expressions and functions inside the statements of course |
for (;;) { print("#") } Invalid condition |
The loop condition shall not be omitted! |
a={1,2,3}; foreach(i;a) { print(i) } 123 |
Simple example |
foreach(i;{1,2,3}) { print(i) } 123 |
Same with a list literal |
foreach(i;{1,2,3})
{ print(i); foreach(j;{"a","b","c"}){print(j)} } 1abc2abc3abc |
Nested foreach loops |
a={1,2,3}; foreach(i;a){ a={"a","b"}; print(i) } 123 a out = {"a","b"} |
Note that changing the variable 'a' works, but doesn't influence the loop behavior. |
i=0;do
{ print(i) }while(++i<10) 0123456789 |
No init statement, so you have to put it in a separate statement. |
i=0;while (i<10)
{ print(i++) } 0123456789 |
No init statement, so you have to put it in a separate statement. |
function
factorial(n) { if (n<=1) { 1 } else { n*factorial_recursive(n-1) } } |
load("factorial.clc") factorial(200) out = 0.7886578673647905e+375 fac(200) out = 0.7886578673647905e+375 |
function galton(rows, trials)
{
// init slot = lfill(0,rows+1); // run trials for (trial = 0; trial < trials; trial++) { position = 0; for (pos = 0; pos < rows; pos++) { if (rnd() >= 0.5) { position++; } } slot[position]++; } // output for (pos = 0; pos <= rows; pos++) { println("Slot " + (string)(pos+1) + " contains " + (string)slot[pos] + " balls."); } } |
load("galton.clc") galton(4,1000) Slot 1 contains 49 balls. Slot 2 contains 240 balls. Slot 3 contains 374 balls. Slot 4 contains 273 balls. Slot 5 contains 64 balls. |
//
Calcutta version of 99 Bottles of beer b1 = " bottle of beer"; bn = " bottles of beer"; otw = " on the wall"; for (i=100; i>0; i--) { b = if (i>1) {bn} else {b1}; println ((string)i+b+otw+", "+(string)i+b+"."); println("Take one down and pass it around,"); b = if (i-1>1) {bn} else {b1}; println((string)(i-1)+b+otw+"."); println(""); } |
load("99bottles.clc") 100 bottles of beer on the wall, 100 bottles of beer. Take one down and pass it around, 99 bottles of beer on the wall. ... ... ... 1 bottle of beer on the wall, 1 bottle of beer. Take one down and pass it around, 0 bottle of beer on the wall. |