27.22Using the symbol table. 4tH 4tH Forth compiler
Reklamë
Reklamë
CHAPTER 27. MODIFYING 4TH 544
If you want to check a device in exec_4th(), there are several macros you can use. They all take the value returned by OpenStream() as parameter.
27.22
Using the symbol table
The symboltable is a way to dynamically add words to the vocabulary of 4tH. All other words are hard-coded into the compiler. If you want to add any, you have change the entire compiler and make a new executable. We’ve seen that before.
Without the symboltable there wouldn’t be any strings, tables, variables or even colondefinitions. May be you think that such a powerful feature must be hard to work with. No, it isn’t!
The only thing you have to tell the symboltable is "hey, if that word comes along, compile this token and this argument into the object". That’s all. There are three functions that control the symbol-table:
F
UNCTION
D
ESCRIPTION
AddSymbol()
MakeSymbol()
Adds a symbol to the symboltable
Makes a symbol of the current word
GetSymbol() Searches the symboltable
SearchDictionary() Searches the entire dictionary
Table 27.13: Symboltable API
You can forget about the GetSymbol(). You will hardly ever need it. Let’s see how it works. We’ll continue with ’:’: if (DecodeWord (M4NODECL))
{
AddSymbol (CALL, Object->ErrLine, CurrentWord);
CompileMark (BRANCH, R_COLON);
}
First it uses DecodeWord() to set "CurrentWord" to the next word in the source, which is the name of the definition. Then it adds a symbol to the symboltable. Hey, shouldn’t we compile a word first?
No. The member "ErrLine" of an Hcode header always points to the next available word in the Code Segment. That is the place where we will compile our ’BRANCH’ instruction.
When the instruction pointer is set to that location, it will be automatically incremented and get inside the definition. So that is okay.
The token we’ll use to branch inside that definition is not ’BRANCH’ or ’0BRANCH’, but
’CALL’. ’CALL’ throws the address of its own location on the Return Stack. When the definition is done, ’EXIT’ takes that address off the Return Stack and jumps backs.
AddSymbol() adds an entry to the symboltable. No, you don’t need to check the symboltable when you add a symbol. AddSymbol() does that for you and sets the member
"ErrNo" when needed.
Finally, a ’BRANCH’ token is compiled with a dummy argument. It will be solved later with a backlink, marked by MarkLink(). Now, how does it actually work? We’ll give you an example. Take this small program:
CHAPTER 27. MODIFYING 4TH 545
: hello’s 0 do ." Hello " loop cr ;
20 hello’s 10 hello’s
When the ’:’ is reached by the compiler, it hasn’t compiled a thing, so "ErrLine" still points to the first word in the Code Segment (0). DecodeWord() is called, so "CurrentWord" points to "HELLO’S". Then a symbol is added to the symboltable by calling
AddSymbol() . The entry looks like this:
HELLO’S -> CALL (0)
That means that every time the name "HELLO’S" is found in the source, the word "CALL
(0)" will be compiled. See for yourself:
[0]
[1]
[2]
[3]
[4]
[5]
[6]
[7] branch literal do
." loop cr exit literal
[8]
[9] call literal
[10] call
(6)
(0)
(0)
(0)
(2)
(0)
(0)
(20)
(0)
(10)
(0)
Basically, that is all you need to know about the symboltable. Yes, you can search it yourself, but why should you? It is done automatically for you. But if you really want to know: you do it by calling GetSymbol().
All you need is the name of the symbol you’re looking for and what you want the compiler to do when i finds it. E.g. if you were looking for "HELLO’S" and didn’t want to compile it, you’d have to write: int x = GetSymbol ("HELLO\’S", W_SEARCH);
GetSymbol() returns the index of "HELLO’S" in the symboltable. You can use this index to access the symboltable, called "SymTable": printf ("%d, %ld, %s\n", (int) SymTable [x].Token,
(long) SymTable [x].Value, SymTable [x].Name);
Which prints the token, the argument and the name of the symbol. If the name isn’t listed
GetSymbol() returns "MISSING": if ((x = GetSymbol ("HELLO\’S", W_SEARCH)) == MISSING) printf ("Not found\n");
If you search the symboltable in order to compile a word, you only have to tell: int x = GetSymbol ("HELLO\’S", W_EXEC);
Shkarko
Reklamë