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 . 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 fpas 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 ':=' ), which assigns a new value to a named variable:
example program ch2_ex1
function main(ARGV);
begin
	foo := 5;
end;

This will copy 5 into global variable called foo and sets the type of the variable to NUM. The variable is global because there is no sign that suggests it is not.

Reading the variable is done by simply using its name. For example:
example program ch2_ex2
function main(ARGV);
begin
	foo := 5;
	foo := foo + 3;
end;

at the end of main the value of foo is 8. The second statement reads the original value (5) and adds (3) to it then assigns the result (8) to the variable, overwriting any previous value (and type, but in this example the type did not change).

A vairable is a cell so it can be printed using fawk_print_cell() or fawk_print(), depending on the details required:
example program ch2_ex3
function main(ARGV);
begin
	foo := 5;
	foo := foo + 3;
	fawk_print_cell(foo);
	fawk_print(foo);
end;

Note: for the + operator, each operand is converted to number before the operation. For example:
example program ch2_ex4
function main(ARGV);
begin
	foo := '5';
	bar := 3;
	fawk_print(foo+bar);
end;

will print 8, not "53": the + operator means "convert both sides to number and sum them".

2.5. Operators

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 % b integer remiainder of a/b foo%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
function main(ARGV);
begin
	{ the result of 2 * 3 is used as an operand for the +; result is 7: }
	a := 1 + 2 * 3;

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

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

	{ "void expression": an expression that is evaluated but the result is
	  is discarded; the result is 3 and is not used for anything }
	1+2;
end;

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).