12.1 Adding your own library. 4tH 4tH Forth compiler
Reklaam
Reklaam
Chapter 12
Standard libraries
12.1
Adding your own library
This is a lot easier than you might think! As a matter of fact, almost any program can be turned into a specialized library. A well-written program contains a lot of definitions and only one executable word. Take that word away and you’ve got a library!
A library may contain word defintions, variables, constants, almost anything you like. And a program that includes that library will have all these definitions at its disposal. As a matter of fact, the resulting program will behave like you entered the contents of the entire library file at the position of the ’[NEEDS’ directive, e.g. this is an except of constant.4th:
-1 constant NULL
When it is included in this file:
\ This is a sample table using NULL
[needs lib/constant.4th] create sample
," First entry"
," Second entry"
," Third entry"
NULL ,
It will compile to the same code as this:
\ This is a sample table using NULL
-1 constant NULL create sample
," First entry"
," Second entry"
," Third entry"
NULL ,
So it is not a good idea to make your library files too big, since there will be a lot of superfluous code included in the compilant which 4tH will not dispose of automatically.
164
CHAPTER 12. STANDARD LIBRARIES 165
You can nest ’[NEEDS’ directives, so one library file may include other library files. This helps to prevent duplicate code, which can be a serious maintenance problem. You can nest them as deep as you want, available memory being the only restriction.
However, when nesting inclusions you always have the problem of multiple inclusions.
Don’t think that all 4tH users know by heart which library files calls which. Multiple inclusions will lead to errors, unless you take precautions. We have ’[DEFINED]’ and
’[UNDEFINED]’ to prevent that:
[UNDEFINED] 2drop [IF]
: 2drop drop drop ;
: 2dup over over ;
: 2swap rot >r rot r> ;
[THEN]
If you have included this file before, ’2DROP’ is already defined, so in fact all definitions are skipped when the file is included for the second time. Of course, it will take up some extra memory, but at least it won’t generate any errors.
You should not automatically resolve library dependencies when the file included:
• Is fairly large
1
;
• Is required by many other include files
2
;
• Has lots of (nested) dependencies itself.
In that case you should add a check whether a certain file has been loaded and if not, abort compilation, e.g.:
[UNDEFINED] F+ [IF] [ABORT] [THEN]
If you want to port your library file, it might be a good idea to hide specific 4tH constructions, e.g.:
[DEFINED] 4TH# [IF] ( a n --)
: string! chars + 0 swap c! ;
[ELSE]
: string! swap 1- c! ;
\ make an ASCIIZ string
( a n --)
[THEN] \ make a counted string
Since ’4TH#’ is a 4tH specific constant, it will not be defined in other Forth compilers. This way the compiler will automatically select the correct definition. Finally, you may want to hide all words which you don’t want exposed to the outside program:
[DEFINED] 4TH# [IF] hide buffer hide /buffer
[THEN]
The reason for that is twofold. First, you don’t want the user of your library to meddle with the internal code or variables of your library. Second, if you leave all these words in, you’re cluttering the symboltable, which may lead to compilation errors if the user happens to choose a name you already used inside your library.
1
See sections 12.22 and 13.18.
2
See sections 12.21 and 12.22.
Laadi alla
Reklaam