H-code. 4tH 4tH Forth compiler
Iklan
Iklan
CHAPTER 2. OVERVIEW 25
Finally there is a chunk of memory the user can manipulate at will. It contains the TIB, the
PAD and all string variables (if any). The memory layout of the Character Segment looks like figure 2.2.
The 4tH programmer can store and fetch anything here.
Since 4tH uses some C-functions ASCIIZ strings are used.
The words that act on counted strings take the same parameters and deliver functionally the same results.
User strings
File I/O is supported too in a more Forth-like way than
Forth itself.
You can have six concurrently open files and/or pipes. 4tH has threads too. A thread can be saved to disk and reloaded. The only restriction is that all files are closed when the execution of a thread is suspended.
PAD
TIB
2.4.1
The 4tH language
Figure 2.2: Character segment layout
Most Forths use four different datatypes: signed 16 bit numbers, unsigned 16 bit numbers, signed 32 bit numbers and unsigned 32 bit numbers. The latter two are usually called "double numbers". Unlike C they all have their own operators. On top of that there are mixed operators too. Highly confusing!
We never liked that in the first place. Application programmers want to make an application. They don’t want to worry whether any intermediate result could possibly be larger than 32767. So 4tH gets rid of most data- types and operators. It uses signed 32 bit numbers. That’s it. No mixed, double or unsigned operators.
Second, a Forth programmer has to know how much address-units a cell takes. Since every data-type in 4tH has its own segment, the address-unit of a segment is always one, regardless the data-type. Consequently, ANS- Forth words like ’CELLS’ and ’CHARS’ are ’NOOP’s. Which fits 4tH nicely.
Although 4tH has different words for storing and fetching different data- types, most of its vocabulary is still compatible with Forth. E.g. the word "C!" takes an address in the Character Segment and "!" takes an address in the Integer Segment. Since the Code Segment and String Segment do not allow any writing, there is no need for such operators.
Each segment has its own allocation operators too. ’VARIABLE’, ’ARRAY’ and ’VALUE’ allocate space in the Integer Area. ’STRING’ allocates space in the Character Area. Other words like ”’ and ’CREATE’ have restricted functionality and compatibility with Forth.
4tH was originally loosely based on the Forth-79 standard, but now it supports most of the
CORE wordset of ANS-Forth. Note that compatibility never had the highest priority. 4tH was designed to write applets, not to be the next "fully ANS-Forth compatible compiler with a little difference". If that is what you want, 4tH is not for you.
2.4.2
H-code
Long before the dawn of the original IBM-XT there was a language called UCSD Pascal.
Like Forth, it was a compiler and an interpreter. In fact, it didn’t compile source into objectcode for some silicon-based processor. Instead it made P-code. So if you wanted to execute it, you needed a P-code interpreter for your system.
Such an interpreter can run faster than an ordinary interpreter since it doesn’t interpret source-statements with all of its symbolic labels intact, but optimized P-code. It seems
CHAPTER 2. OVERVIEW 26 to have been discovered again, since Java and previous versions of Visual Basic work the same way. Visual Basic hides the interpreter in a DLL, but basically it doesn’t work any different.
The 4tH uses the same basic architecture. First the source is compiled into H-code. Then the H-code interpreter is run. A token is a very simple structure. It’s got a single byte instruction and an argument. Here’s a sample of disassembled H-code:
[62] CR (0)
[63] VARIABLE (2)
[64] @ (0)
[65] 1- (0)
[66] DUP (0)
[67] TO (2)
[68] 0BRANCH (62)
BTW, building a decompiler for tokenized code is quite simple. There is one for Visual Basic and it seems like one emerged for Java too. The H- code was the result after compiling this little piece of source code: cr begin times @ 1- dup times ! until
You can clearly see that everything is actually compiled. Flow-statements are compiled into BRANCH and 0BRANCH instructions pointing to addresses in the Code Segment.
Compiled H-code can be used on its own. It can be kept in memory, loaded, saved, decompiled and executed. H-code is a combination of the String Segment, the Code Segment and a header (figure 2.3). The header contains all the information to set up the runtime environment and some information on the String- and the Code Segments. The Integer Segment and the Character Segment are created at runtime.
Although speed was an issue when 4tH was designed, it is beaten by some other
Forths. There are several possible explanations.
*Hcode
Hcode header
• 4tH uses 32 bit numbers, while most other Forths use only 16 bit numbers
• 4tH checks all parameters, while other Forths depend on signals or don’t do any checking at all
• 4tH is written in C, while some other
Forths are written in assembler
When 4tH is compiled with a 32-bit compiler it outruns Python, Perl and most other
C-based Forths (upto 4 times) or has a comparable performance (with the possible exception of GCC optimized Forth compilers). In real life applications the difference is barely noticeable.
To make compiled H-code portable, a separate scheme was developed: the HcodeeXecutable. Or HX-file for short. It contains all the information in the header, a
S e g m e n t i r
S t n g e n t
S e g m d e
C o
S n t e g m e g e r t e
I n
Figure 2.3: Hcode structure
S e g m e t t e a c r a r
C h
Unduh
Iklan