Vars module contains functions for managing variables, commands, functions, and operators.
Structure
Variables are special kind of structures which require two or three atoms to hold their description. The macros DESCR1 and DESCR2 are used to access these additional atoms:
- DESCR1 - first descriptor of a variable (exists in each variable)
- DESCR2 - second descriptor of a variable (exists only in functions)
Use IS_VARATOM() macro to check whether the atom is a var atom.
Structure of var atoms
There are three groups of variables depending on their values. The group code is accessed with the VARTYPE macro:
- VAR_TYPE_NORMAL - the variable stores its value in the stack at specific offset. Use IS_NORMAL macro to check for such variables
- VAR_TYPE_RUNTIME - the variable stores its value in the var atom. Such variables are primitive variables, global variables and local variables created at run-time. Use IS_RUNTIME macro to check for such variables
- VAR_TYPE_TAG - the variable corresponds to a tag. The value, which is stored in the var atom is the address of the tag. Use IS_TAG macro to check for tag variables
Primitive variables
Primitive variables are those which are automatically created by Lhogho. For example, such variables are PRINTDEPTHLIMIT
, CASEIGNOREDP
, LOGOVERSION
and others. The macros which access data of primitive variables are:
- PARENT - points to the parent of all primitive vars (this is the globals variable)
- NAME - an atom containing the name of the primitive
- VALUE - value of a primitive variable (stored as field
DATA
in DESCR1)
Use IS_VARIABLE and IS_PRIMITIVE macros to check for primitive variables.
User-defined variables
User-defined variables are those which are defined by user's program code. There are several types of such variables, depending on how they are created.
Compile-time variables
These variables are processed during the compilation of the program. Usually these are variables created with LOCAL
and MAKE
. The values of such variables are stored in the stack. The macros which access data of compile-time variables are:
- PARENT - points to the parent variable
- NAME - an atom containing the name of the variable
- OFFSET - an offset of the variable's value in the local stack (relative to
EBP
register). If the offset is positive, then the variable corresponds to an input of the current function. If the offset is negative, then it is a local variable.
- LEVEL - level of the variable. The root variable is level 0.
Use IS_VARIABLE and IS_NORMAL macros to check for compile-time variables.
Run-time variables
These variables are processed during the execution of the program. Usually these are variables created with LOCAL
when the input is an expression. The values of such variables are stored in the DATA
field of DESCR1. The macros which access data of run-time variables are:
- PARENT - points to the parent variable (it must be a master variable)
- NAME - an atom containing the name of the variable
- VALUE - the value of the variable
Use IS_VARIABLE and IS_RUNTIME macros to check for variables that store their values in VALUE.
Global variables
These variables are similar to the run-time variable as long as their values are stored in the DATA
field of DESCR1. The macros which access data of global variables are:
- PARENT - points to the parent variable (it must be globals variable)
- NAME - an atom containing the name of the variable
- VALUE - the value of the variable
Use IS_VARIABLE and IS_GLOBAL macros to check for global variables. Note that globals variable also contains the primitive variables.
Primitive functions
Primitive functions (this includes primitive commands and operators) are defined automatically by Lhogho. There is no any Logo source code corresponding to these functions. The macros which access data of primitive functions are:
- PARENT - points to the globals variable
- NAME - an atom containing the name of the primitive
- ADDRESS - address of the machine code of the function (stored in
DATA
in DESCR1)
- PRIORITY - priority of the primitive
- LARGS - number of left-arguments of the primitive
- RARGS - number of right arguments of the primitive
All these data are placed in the first descriptor. The second one is NULL
. Primitive functions can be checked with IS_PRIMITIVE, IS_FUNCTION, IS_COMMAND macro.
User-defined functions
User-defined functions, commands and operators are defined by Logo source code. They contain these data:
- PARENT - parent variable
- NAME - name
- ADDRESS - address of the machine code of the compiled code (stored in
DATA
in DESCR1)
- LEVEL - level of the function
- PRIORITY - priority (constant)
- LARGS - number of left-arguments
- RARGS - number of right arguments
- DEFINITIONS - definition of the function at various stages of processing. It is a list of four elements accessed by these macros:
- FULLSOURCE - source of the function as a word
- SOURCE - source of the function as a word
- BODY - source as a flat list of tokens
- TREE - abstract syntax tree of a variable (LISP-like notation)
- LOCALS - list of local variables
- BINARY - memory containing the compiled (binary) code of a function
Tags
Tags are recorded as local variables. The tag name becomes the name of the variable, and the tag address becomes value of the variable. Tag variables have their VARTYPE value equal to VAR_TYPE_TAG. The macros which access data of primitive variables are:
- VALUE - adress of the tag
- NAME - name of the tag
Use IS_VARIABLE and IS_TAG macros to check for tags.
Flags
Var atoms have bitmask flags with the following meaning:
- FLAG_PRIMITIVE. This flag is set for all variables that are defined as primitive by Lhogho. Primitives are defined in array
vars
[]. Primitive variables differ from all others that they do not have any corresponding Logo source code. They cannot be traced and debugged. Their definition cannot be extracted in the form of Logo commands.
- FLAG_VARIABLE. This flag is set when a variable is created with
MAKE
or LOCAL
commands. Lhogho assumes that such a variable is not a function or a command, although when forced Lhogho will discard this assumption. If FLAG_VARIABLE flag is set, it is assumed that FLAG_PRIMITIVE, FLAG_FUNCTION, and FLAG_COMMAND flags are cleared.
- FLAG_COMMAND. This flag is set when a variable contains executable commands (i.e. it is a routine) which do not return a value. Both primitive and user-defined routines can be commands. For primitives this flag means that the routine does not return a value. For user-defined routines this flag means that there is no
OUTPUT
value
command in the definition. If FLAG_COMMAND is set, it is assumed that FLAG_VARIABLE is cleared. Examples for primitive commands are MAKE
and PRINT
.
- FLAG_FUNCTION. This flag is set when a variable contains executable commands (i.e. it is a routine) which generate and return a value. Both primitive and user-defined routines can be functions. Operators are also functions. For primitives this flag means that the routine really returns a value. For user-defined routines this flag means that there is
OUTPUT
value
command in the definition - there is no guarantee that the OUTPUT
is actually used. If FLAG_FUNCTION is set, it is assumed that FLAG_VARIABLE is cleared. Examples for primitive functions are SIN
and ROUND
.
- FLAG_CAN_BE_UNARY. This flag is set only for operators which left argument could be missing, thus making the operator unary. Only two of the primitive operators can be unary:
+
and -
.
- FLAG_INFINITE_ARGS. This flag is set for functions and commands which may accept any number of arguments without issuing an error message. Examples of primitive functions with infinite number of arguments:
ALL
, SUM
, and WORD
; and primitve commands: PRINT
and LOCAL
.
- FLAG_MAY_SKIP_LAST_ARG. This flag is set for commands which can be run without their last argument. The only command which has this property is
IF
.
- FLAG_PROCESS_ARGS. This flag is set for commands and functions which arguments are list of commands. If the parser knows in advance that a list-constant is such an argument, then it can parse the list too. Not using this flag is nit vital, but it usage can result in a shorter and faster code. Example:
IF
, REPEAT
, WHILE
, UNTIL
, RUN
, FOREVER
and FOR
. If the actual argument is not a list constant, then this flag is ignored.
- FLAG_PUSH_PARENT. This flag is set for commands and functions which need additional information for the parent context. Most often this is used in cases when the routine compiles commands at run-time. Routines which do not need parental information do not care whether this flag is set, however, passing this information for such routines is a waste of memory and time. Examples of routinges needing parental information:
RUN
, THING
, NAME
?, DEFINED
? and DEFINE
.
- FLAG_SET_ONE_VAR. This flag is set for a command which first parameter is a name of a variable. This flag could be entirely omitted, but it existence leads to faster execution of generated programs. Examples of such commands:
MAKE
and FOR
.
- FLAG_SET_ALL_VARS. This flag is set for a command which parameters are names of variables. This flag is essential for proper compilation, although it is not compulsory. Currently there is only one such command -
LOCAL
.
- FLAG_MAY_HAVE_EXTRA_ARG. This flag is set for commands which can accept one more right argument additionally to the default number of right arguments. Such commands are
ARCTAN
, RADARCTAN
RANDOM
and RERANDOM
.
- FLAG_PUSH_FRAME. This flag is set for commands and functions which need the frame pointer of the caller. The frame pointer could be later used to access static or dynamic pointer, local variables, input parameters, repeat chain, etc. Examples of routinges needing frame information:
REPCOUNT
.
- FLAG_PRINT_VARS. This flag is set for commands which require the values of print-related variables, like PRINTDEPTHLIMIT, PRINTWIDTHLIMIT, and FULLPRINTP.
- FLAG_EQUAL_VARS. This flag is set for functions which require the values of compare-related variable, like CASEIGNOREDP.
There are extended flags (FLAGS_EX_) which are used only in the vars[] definition of the variables. These flags do not exist in the FLAGS field of the var atoms.
-FLAG_EX_PRINTDEPTHLIMIT. This flag is used during the creation of the top-level variable printdepthlimit.
-FLAG_EX_PRINTWIDTHLIMIT. This flag is used during the creation of the top-level variable printwidthlimit.
-FLAG_EX_FULLPRINTP. This flag is used during the creation of the top-level variable fullprintp.
-FLAG_EX_CASEIGNOREDP. This flag is used during the creation of the top-level variable caseignoredp.
Special variables
Lhogho defines several special variables:
- root - used as the root variable of all user-defined functions, procedures, operators and variables.
- globals - used as the root variable of all primitive functions, procedures, operators and variables.
- fullprintp - used to quickly access the word FULLPRINTP.
- caseignoredp - used to quickly access the word CASEIGNOREDP.