CHAPTER 27. MODIFYING 4TH 524 app 0 th
Is the very first application variable and: app 1 th
Is the second application variable. You can do the same. Let’s say you have three application variables, which contain the document-number, the page-number and the line-number.
You’d like to call them "&DOC", "&PAGE" and "&LINE". The ampersands are not really necessary, but we add them in order to identify the application specific words. To make it work you have to call exec_4th() by:
Result = exec_4th (Program, 0, NULL, 3, (cell) Doc, (cell) Page,
(cell) Line);
Now these are the mappings.
C
VARIABLE
4
T
H
EXPRESSION
Doc
Page
Line app 0 th app 1 th app 2 th
Table 27.5: Mapping between 4tH and C variables
Now all we have to do is add constants that are equivalent to these addresses. As we’ve seen before, we can do that by modifying comp_4th(). That is GetConstant() to be exact:
{ 4, "&DOC", LITERAL, VAR4TH+0 },
{ 5, "&PAGE", LITERAL, VAR4TH+1 },
{ 5, "&LINE", LITERAL, VAR4TH+2 },
That’s all! You can now refer to these variables with their proper names.
C
VARIABLE
4
T
H
EXPRESSION
4
T
H
VARIABLE
Doc
Page
Line app 0 th app 1 th app 2 th
&doc
&page
&line
Table 27.6: Mapping between 4tH and C variable names
Note that if you use this technique you are bound to calling exec_4th() with these arguments in this order! Failure to do so may cause unpredictable results (but no crashes of course).
27.11
Adding new variables
In standard 4tH there are five environment variables, HI, FIRST, LAST, CIN and COUT.
There are also five predefined variables, ’>IN’, ’BASE’, ’OUT and the variable pair ’SOURCE’.
These variables are initialized by exec_4th(), so their initial value should be known by then.
Adding new variables is not difficult. We’re going to make a variable that contains 4tHs release number, called "VERSION". First take a look at cmds_4th.h. It contains a
#define called "VAR4TH":
CHAPTER 27. MODIFYING 4TH 525
/* variables and environs */
#define SYS4TH 3
#define VAR4TH 10
#define ENV4TH 5
Now remember that number behind "VAR4TH". You will need it later. Then increment it:
/* variables and environs */
#define SYS4TH 3
#define VAR4TH 11
#define ENV4TH 5
If you would have preferred to make ’VERSION’ an environment, you should also have incremented "ENV4TH". But we assume you’ll allow the variable to be overwritten. Now add a symbolic value for the variable. Just append it to the list and increment the number:
#define VBASE
#define VIN
#define VOUT
#define VTIB
#define VTIBS
#define VVERS
5
6
7
8
9
10
Or if you prefer it to make an environment variable, add it to the environment variable list:
#define VHI
#define VFIRST
#define VLAST
#define VCIN
#define VCOUT
#define VVERS
#define VBASE
#define VIN
#define VOUT
#define VTIB
#define VTIBS
6
7
8
9
10
0
1
2
3
4
5
That’s all. Now save cmds_4th.h and load comp_4th() in your editor. This stage is very much like adding a name to an application variable. We simply define a constant that contains the address of our new internal variable. You will remember how we add a constant. Right, we add an entry to the GetConstant() table:
{ 7, "VERSION", LITERAL, VVERS },
Making it an environment variable is very easy too: just replace the ’LITERAL’ token by an ’ENVIRON’ token:
{ 7, "VERSION", ENVIRON, VVERS },
All we need to do now is to initialize the variable in exec_4th(). Since it is a variable, it resides in the Variable Area of the Integer Segment. The Integer Segment is just a large array of unsigned longs.
The pointer "Stack" points to the beginning of the Integer Segment, which is also the beginning of the Stack Area. The pointer "Vars" points to the area that is assigned to 4tHs variables. Our constant "VERSION" is an index to that array, so the expression "Vars
[VVERS]" is a valid reference to our "VERSION" variable.
However, this indexed way of referencing is slower than a pointer. Therefore, we have created pointers that reference these frequently used variables:
CHAPTER 27. MODIFYING 4TH 526 cell cell
Base
In
*In;
*Result;
/* equivalent of forth >IN */
/* return value for apps */
= &(Vars [VBASE]); /* assign pointer to BASE */
= &(Vars [VIN]); /* assign pointer to >IN */
You might have noticed the absence of "Base". Well, since it is referenced elsewhere as well, this is a global variable. But don’t worry, there is no need to reference "VERSION" globally. So, we need to define a pointer to a cell, assign it to "Vars [3]" and initialize it:
Vars [VVERS] = Version4th; /* initialize it */
That is all! Any questions? Where does "Version4th" come from? It is defined in cmds_4th.h.
Anybody else? Next subject, please.
27.12
Resizing the 4tH environment
You might come up with a situation that the stack isn’t big enough. Or that you want to give your programmers deeper nesting. Or that 512 characters isn’t just good enough for temporary storage.
Relax! All these things can be changed with very little effort. And after that, you just need to recompile 4tH like we’ve done before.
There is a single file you need to edit, cmds_4th.h. You will find several easy to change
#defines there.
/* compiler */
#define LINKSIZ
#define SYMLEN
64
16
/* interpreter */
#define STACKSIZ
#define TIBSIZ
#define PADSIZ
512
256
512
#define DOTSIZ
#define MAXDEVS
64
8
#define PIPEWAIT 102400L
You already know "VAR4TH", since we discussed that one earlier in this document. Right, it determines the number of internal variables! "LINKSIZ" determines the nesting depth.
Nesting depth has to do with the number of nested branches, e.g.
IF
IF
THEN
THEN
IF
THEN
Each ’IF’ puts its address and a reference (I’m an IF) on the flow control stack. Each
’THEN’ takes an entry off the flow control stack and takes the appropriate action. So, in the current version of 4tH you can nest upto 64 consecutive conditionals, before you get an error. You may increase or decrease that number.
"SYMLEN" is the maximum length of any name you define, e.g. a colon-definition, a constant, a variable. The default is 16, which is enough to define a name like "multiplications".