Chapter 2: Variables and operators

A global variable is created on the first time it is referenced. Scalar variables are created with the value (and type) NIL.

Variables are normally referenced by their name. A variable name must start with underscore or letter and can consist underscores, letters and digits and may contain a $ suffix (but this does not enforce the variable type to be string) . A variable name is case sensitive.

2.1. Global vs. local

A variable is a piece of data memory, named by the variable name.

A global variable is a variable that is accessible from every function within a script and will always access the same memory region with the same name. A global variable exists from the time the script is loaded until it is unloaded.

A local variable is function-local: it exists only for a specific call of a function; different functions or different calls of the same function will see a different memory location using the same local variable name. More on local variables in chapter 4. This chapter will deal with global variables only.

2.2. Scalar vs. array

Each variable is either a scalar or an array. A scalar variable holds a single value, an array holds multiple values. This chapter describes scalars only - more on arrays in chapter 5.

2.3. Data types

Each variable stores a data and a data type. Data type is one of:

type name description example
NUM rational number 4, -6, 3.14, 0, 0x2a
STR text string "hello, world!"
FUNC function ref main
NIL special empty value ""
ARRAY arrays see chapter 5

Data type is determined automatically, runtime: when the value of the variable is changed, the data type is adjusted as required.

The NIL type is a special type used for indicating "no value". It is written as "" in fbas source code - the empty string is the same as NIL. A NIL value is equal to another NIL value and is not-equal only to non-NIL values. When a NIL value is compared in any other way or to any other value, the result of the comparison is false (e.g. both 1<NIL and 1>NIL are false).

2.4. Assignment

Variables are changed using operators. The simplest operator is the assignment operator (written as '='
example program ch2_ex1
foo = 5

rem the let keyword is optional; this will do the same:
let foo = 5
example program ch2_ex2
foo = 5
foo = foo + 3
example program ch2_ex3
foo = 5
foo = foo + 3
fawk_print_cell(foo)
fawk_print(foo)
example program ch2_ex4
foo = "5"
bar = 3
fawk_print(foo+bar)
Below is a table of the common operators on numbers, demonstrated with operands a and b - both are expressions (can be variables or constants or a whole expression of other operands and operators). When an operand must be a variable, v is used in the example.

Arithmetic operators
syntax description example
a + b sum of a and b foo+3
a - b subtract b from a foo-3
a * b multiply a with b 10*foo
a / b divide a with b foo/3
a mod b integer remiainder of a/b foo mod 3
-a negate a -5
-foo
(a) change precedence (4+2)*8

boolean operators
not a logical negate a v = !a
a and b true if a and b are true  
a or b true if a or b is true  

Note: boolean operators will look at the numeric value of the operand. Value zero is interpreted as false, any other value is interpreted as true.

Relational operators
syntax description example
a = b true if a equals to b if (a = 5) ...
a != b true if a is not equal to b if (a != 5) ...
a > b true if a is greater than b if (a > 5) ...
a < b true if a is less than b if (a < 5) ...
a >= b a is greater than or equal to b if (a >= 5) ...
a <= b a is less than or equal to b if (a <= 5) ...

Misc operators
v = a copy the value of a to v foo=5
foo=bar
a @ b concatenate string a and b "foo" @ "bar" is "foobar"
v[] explicit array (chapter 5) my_func(FOO[])
v[b] array indexing (chapter 5) FOO[3]
v.b array indexing (chapter 5) FOO.bar
&v used in C function call: pass by reference (chapter 5) delete(&FOO)

2.6. expressions

Using the operators listed above will build expressions. An expression is evaluated in place and will yield a result which is a type and a value. The result can be used as an operand in another expression, as a function call parameter, as a function return value or can be discarded:
example program ch2_ex5
rem the result of 2 * 3 is used as an operand for the +; result is 7:
a = 1 + 2 * 3

rem () changes precedence so (1 + 2) is calculated first; result is 6:
b = (1 + 2) * 3

rem as a function call parameter: expression is evaluated first, the result
rem (which is 7) is passed to the function:
fawk_print(1 + 2 * 3)

In fact fawk_print() is a function that we call. A function always has a return value, so a function call is an expression too. So far all our calls to fawk_print() were "void expressions" because we discarded the return value of fawk_print().

Note: "void expressions" is the way an expression is turned into a statement, which is required because a function body is a sequence of statements

2.7. Short circuit evaluation (lazy evaluation)

When there is a logical AND or OR in an expression, the left side is evaluated first. If the left side determines the result already, the right side is not evaluated at all. For example in if foo() or bar() then ... if foo() is true, the result will always be true so bar() is not evaluated. Since in this case the right side is a function call, this means bar() is not called.

Similar way, if the left side of an AND operator is false, the result is false and the right side is not evaluated.

This obviously doesn't make a difference if the right side is something like (a > 4), but does make a difference if the right side has side effect (any effect that change global states, e.g. global variables, or calls to C functions, even indirectly).