H-code compiler. 4tH 4tH Forth compiler
Advertisement
Advertisement
CHAPTER 2. OVERVIEW 27 compacted Code Segment, the String Segment and some additional information on compatibility and integrity. Numbers are stored in an architecture-independant way.
2.4.3
H-code compiler
The H-code compiler looks a lot like any conventional compiler or assembler. Basically it is a simple one-pass compiler. In order to understand the workings of 4tH you have to know that not all H-code instructions are equal:
• Immediate words (flow control, declarations, etc.)
• Predefined constants (addresses, aliases, etc.)
• Simple words (do not require an argument)
• Symboltable entries (user-definitions)
To determine the initial size of both the Code Segment and the symbol table the source is parsed first and the actual number of words counted. This determines the initial size of the Code Segment with a high degree of accuracy, so extending the Code Segment is never necessairy. After compilation the Code Segment will be shrunk to its actual size.
The parser can distinguish between directives and string constants. The size of the symboltable is determined by simply counting all definitions. Every definition needs one symboltable entry. That makes determining the size of the symbol-table very easy.
During compilation all simple words are compiled into tokens without a valid argument.
When a definition is encountered, like a colon-definition or a variable-declaration, a symbol is added to the symbol-table.
There are four compiler directives which determine how a number is interpreted. ’[BI-
NARY]’ interprets numbers as binary numbers, ’[HEX]’ interprets them as hexadecimal numbers. ’[DECIMAL]’ and ’[OCTAL]’ are available too. The "simple words" ’HEX’,
’DECIMAL’ and ’OCTAL’ only act during execution and do not determine how a number is interpreted during compilation.
During compilation the compiler also resolves all flow words. It simply matches the correct instruction and enters the jump-address into the argument of the ’BRANCH’, ’?DO’,
’LOOP’, ’+LOOP’, ’CALL’ or ’0BRANCH’ word. The way 4tH handles flow control is almost completely identical to Forth.
It may sound strange, but colon-definitions are also treated like flow-words. The colon simply compiles into a ’BRANCH’ instruction that skips the colon definition.
When the user calls a colon definition, it simply compiles into a ’CALL’ instruction that puts the current address on the return-stack and jumps inside the colon definition, after the
’BRANCH’. The semi-colon works like a RETURN instruction that pops the return address from the return-stack. Yes, like a subroutine in BASIC or assembler!
2.4.4
Error handling
When 4tH finds an error during compilation or execution it stops and sets the H-code member ErrNo. It works like errno in C. You can optionally link in an array of error-messages.
ErrNo is an index to this array, which makes issuing the correct error message very simple.
The instruction pointer is frozen at the point where the error occured, so it is very easy to find out where the error occured.
CHAPTER 2. OVERVIEW 28
2.4.5
Interfacing with C
A minimal compiler would take only a few lines of C-code. The C-programmer can send
C-variables to the interpreter, just like strcalc().
E.g. a compile takes a string-pointer as argument and returns a pointer to H-code: object = comp_4th (source);
Executing H-code is easy too:
ReturnVal = exec_4th (object, argc, argv, 3, Var1, Var2, Var3);
Which would preload variables Var1, Var2 and Var3. You must specify how many variables are preloaded. Also argc and **argv are available from the 4tH program.
The value returned by exec_4th() and stored into ReturnVal is the value of the 4tH variable ’OUT’, which initially contains CELL_MIN. If an error occurs exec_4th() will always return CELL_MIN, regardless the value stored in ’OUT’.
Download
Advertisement