FORTH: the self-defined words
suppose you have some project on the forth language, which uses a sufficiently large number of similar variables.
/ > For example: x, y, z, x', y', z', x", y", z", s, m and so on...
To determine those, you need to write a word VARIABLE, and it is cumbersome, dull and ugly. Is it possible to make a little brighter?
To indicate that further will define variables and write their names.
Something like:
Remember that the forth interpreter implemented in SP-Forth, if you can not find the word in the context looking for vocabulary in the same context the word NOTFOUND, which takes. NOTFOUND input parameters are the address and count of the substring from the input stream. So, you need to override NOTFOUND to do what we need.
What do you need?
To take it is not found word and compile it to the top of the current dictionary as a variable. We recall the definition
But the word itself chooses the CREATE from the input stream following the word, and we need to create a dictionary entry from a string address and count on the stack. The benefit of this case is the word CREATED, just the host address and the meter lines from the stack and creates a dictionary entry. Unfortunately, it, like NOTFOUND, not part of the standard ANSI-94 set of words.
Thus
But if we place this definition in the underlying list FORTH, you will lose the ability to enter numbers. So it is necessary to hide this new NOTFOUND in any other context. Get dictionary of variables.
and make it current.
put the definition NOTFOUND
return the current context
Therefore, the word VARIABLES: switches the context to variables and we need the NOTFOUND
Closing words ;VARIABLES will return the context. Is it must, of course, in the context of variables.
That is, a total of
So, literally, in four rows, we extended the interpreter SP-Forth and simplified descriptions of the variables.
But the same approach can be used for VALUE-variables, and constants, and in General any words with the General semantics of performance. Those words that are defined using the defining word. In principle, it is useful to have pairs define words. For one single definition, and pair for group definitions. In fact, a defining word is created for the opportunity to create groups of words with common semantics. And whether if these definitions are not spread out through the text and collected in the same block.
Let's try to implement this for VALUE variables.
And here we stumble upon some trouble. The defining word VALUE is not defined via CREATE. It is defined as:
Happiness the word of the HEADER, taking the string from the input stream there are a couple in word SHEADER, is synonymous with the word CREATED.
Just replace one for the other and get the necessary version of the word.
So:
But there is one drawback. All VALUE are initialized with zero. It would be nice to fix it.
Implementation choices may be few.
You can write just
It is difficult to read.
Try to write so:
looks nice.
It is obvious that the word "equal" in the context of values. One should choose the next word and interpret it as a number. That is, to be almost synonymous with LITERAL. Even equals should assign it the value last determined VALUE of the variable.
Write
This option
For its implementation does not need to override NOTFOUND. Will only change the meaning of the word TO. Between words-limiters VALUES: ;VALUES TO must act as a normal VALUE.
You can make the same recording method, and constants.
The implementation of this method, I think, is obvious.
In General, this campaign creates a new type of defining word — group qualifying words. A simple defining word allows you to create words that share semantics. Group having the same property, require to concentrate the definitions of similar words in one part of the original text. What positively affects its readability and maintenance.
A much more pleasant addition to SP - SP-Forth can be group implementation word WINAPI:. In particular, the library Winctl define WINAPI: scattered throughout the text that looks like clutter.
As an option:
To do that, Snoop on the way how word WINAPI:
Apparently implemented lazy loading DLL. In the dictionary entry with the name of the imported function is compiled into a code reference to call the WinAPI, then some parameters and then the name of the library file and the procedure within it. Next comes the validation of the existence of that file and this procedure.
In order to alter this code to our wishes, determine what will make each word.
;WINAPIS — just restores the context.
LIB: — enters from the input stream the next word and stores it in a temporary buffer. Can be combined with a validation.
The remaining words are taken as names of procedures.
So:
Article based on information from habrahabr.ru
/ > For example: x, y, z, x', y', z', x", y", z", s, m and so on...
To determine those, you need to write a word VARIABLE, and it is cumbersome, dull and ugly. Is it possible to make a little brighter?
To indicate that further will define variables and write their names.
Something like:
VARIABLES: x y z x' y' z' x" y" z" s m ;VARIABLES
Remember that the forth interpreter implemented in SP-Forth, if you can not find the word in the context looking for vocabulary in the same context the word NOTFOUND, which takes. NOTFOUND input parameters are the address and count of the substring from the input stream. So, you need to override NOTFOUND to do what we need.
What do you need?
To take it is not found word and compile it to the top of the current dictionary as a variable. We recall the definition
: VARIABLE CREATE 0 , ;
But the word itself chooses the CREATE from the input stream following the word, and we need to create a dictionary entry from a string address and count on the stack. The benefit of this case is the word CREATED, just the host address and the meter lines from the stack and creates a dictionary entry. Unfortunately, it, like NOTFOUND, not part of the standard ANSI-94 set of words.
Thus
: NOTFOUND (addr u -- ) 0 CREATED , ;
But if we place this definition in the underlying list FORTH, you will lose the ability to enter numbers. So it is necessary to hide this new NOTFOUND in any other context. Get dictionary of variables.
VOCABULARY variables
and make it current.
ALSO variables DEFINITIONS
put the definition NOTFOUND
return the current context
PREVIOUS DEFINITIONS
Therefore, the word VARIABLES: switches the context to variables and we need the NOTFOUND
: VARIABLES: variables ALSO ;
Closing words ;VARIABLES will return the context. Is it must, of course, in the context of variables.
That is, a total of
VOCABULARY variables ALSO variables DEFINITIONS : NOTFOUND (addr u -- ) 0 CREATED , ; : ;VARIABLES PREVIOUS ; PREVIOUS DEFINITIONS : VARIABLES: variables ALSO ;
So, literally, in four rows, we extended the interpreter SP-Forth and simplified descriptions of the variables.
But the same approach can be used for VALUE-variables, and constants, and in General any words with the General semantics of performance. Those words that are defined using the defining word. In principle, it is useful to have pairs define words. For one single definition, and pair for group definitions. In fact, a defining word is created for the opportunity to create groups of words with common semantics. And whether if these definitions are not spread out through the text and collected in the same block.
Let's try to implement this for VALUE variables.
VOCABULARY values ALSO values DEFINITIONS : NOTFOUND ...
And here we stumble upon some trouble. The defining word VALUE is not defined via CREATE. It is defined as:
: VALUE HEADER ['] _CONSTANT-CODE COMPILE , ['] _TOVALUE-CODE COMPILE, ;
Happiness the word of the HEADER, taking the string from the input stream there are a couple in word SHEADER, is synonymous with the word CREATED.
Just replace one for the other and get the necessary version of the word.
: VALUED ( n addr u --- ) SHEADER ['] _CONSTANT-CODE COMPILE , ['] _TOVALUE-CODE COMPILE, ;
So:
VOCABULARY values ALSO values DEFINITIONS : ;DROP TO PREVIOUS VALUES ; : NOTFOUND VALUED 0 ; PREVIOUS DEFINITIONS : VALUES: values ALSO 0 ;
But there is one drawback. All VALUE are initialized with zero. It would be nice to fix it.
Implementation choices may be few.
You can write just
VALUES: 11 aa 22 bb 33 cc ;VALUES
It is difficult to read.
Try to write so:
VALUES: aa = 11 bb = 22 cc = 33 ;VALUES
looks nice.
It is obvious that the word "equal" in the context of values. One should choose the next word and interpret it as a number. That is, to be almost synonymous with LITERAL. Even equals should assign it the value last determined VALUE of the variable.
Write
VOCABULARY values ALSO values DEFINITIONS : ;DROP TO PREVIOUS VALUES ; : = BL WORD ?LITERAL LATEST NAME> 9 + EXECUTE ; : NOTFOUND VALUED 0 ; PREVIOUS DEFINITIONS : VALUES: values ALSO 0 ;
This option
Valuable because it does not fall out of the paradigm of language, also allows to initialize the VALUE variable of the calculated values.VALUES: 11 TO aa 22 TO bb 33 TO cc ;VALUES
VALUES: 11 TO aa 22 1980 * TO bb aa bb + TO cc ;VALUES
For its implementation does not need to override NOTFOUND. Will only change the meaning of the word TO. Between words-limiters VALUES: ;VALUES TO must act as a normal VALUE.
VOCABULARY values ALSO values DEFINITIONS : ;PREVIOUS VALUES ; TO VALUE ; PREVIOUS DEFINITIONS : VALUES: values ALSO ;
You can make the same recording method, and constants.
CONSTANTS: 11 IS aa 22 1980 * IS bb aa bb + cc IS ;CONSTANTS
The implementation of this method, I think, is obvious.
In General, this campaign creates a new type of defining word — group qualifying words. A simple defining word allows you to create words that share semantics. Group having the same property, require to concentrate the definitions of similar words in one part of the original text. What positively affects its readability and maintenance.
A much more pleasant addition to SP - SP-Forth can be group implementation word WINAPI:. In particular, the library Winctl define WINAPI: scattered throughout the text that looks like clutter.
As an option:
WINAPIS: LIB: USER32.DLL PostQuitMessage PostMessageA SetActiveWindow LIB: GDI32.DLL CreateFontA GetDeviceCaps DeleteDC LIB: COMCTL32.DLL InitCommonControlsEx ;WINAPIS
To do that, Snoop on the way how word WINAPI:
spf_win_defwords.f
:__: WIN ( params, "Imprecatory" "Inability" -- ) HERE >R 0 , \ address of the winproc 0 , \ address of library name 0 , \ address of function name , \ # of parameters IS-TEMP-WL 0= IF HERE WINAPLINK @ , WINAPLINK ! ( link ) THEN HERE DUP R@ CELL+ CELL+ ! PARSE-NAME CHARS, HERE SWAP DUP ALLOT MOVE 0 C, \ name functions HERE DUP R > CELL+ ! PARSE-NAME CHARS, HERE SWAP DUP ALLOT MOVE 0 C, \ name library LoadLibraryA DUP 0= IF THROW THEN -2009 \ ABORT" Library not found" GetProcAddress 0= IF -2010 THROW THEN \ ABORT" Procedure not found" ; : WINAPI: ( "Imprecatory" "Inability" -- ) ( Used to import the WIN32 routines. The resulting definition will have the name "Imprecatory". Field address of the winproc will be filled at the time of first the execution of the received entries. To call the resulting "import" procedure parameters placed on the data stack in reverse order as described in C you call this procedure. The result of function execution will be put on the stack. ) NEW-WINAPI? IF HEADER ELSE -1 >IN @ HEADER > IN ! THEN ['] _WINAPI-CODE COMPILE, __WIN: ;
Apparently implemented lazy loading DLL. In the dictionary entry with the name of the imported function is compiled into a code reference to call the WinAPI, then some parameters and then the name of the library file and the procedure within it. Next comes the validation of the existence of that file and this procedure.
In order to alter this code to our wishes, determine what will make each word.
;WINAPIS — just restores the context.
LIB: — enters from the input stream the next word and stores it in a temporary buffer. Can be combined with a validation.
The remaining words are taken as names of procedures.
So:
string to stack.f
SP@ VALUE spstore : sp-save SP@ TO spstore ; : sp-restore spstore SP! ; : s-allot ( n bytes -- addr ) sp-save spstore SWAP - ALIGNED DUP >R CELL - CELL SP! R> ; : s-s ( -- addr u ) NextWord 2>R R@ s-allot DUP DUP R@ + 0! 2R> >R SWAP R@ CMOVE R>; : s-free spstore CELL+ SP! ; : 3DUP 2 PICK 2 PICK 2 PICK ;
winapis.f
VOCABULARY winlibs : ;WINAPIS s-free PREVIOUS ; : LIB: (id -- addr u ) s is a free s-s CR OVER LoadLibraryA DUP 0= IF THROW THEN -2009 ; : NOTFOUND ( id addr u addr u -- addr u id ) 2>R 3DUP 2R> 2DUP SHEADER ['] _WINAPI-CODE COMPILE, HERE >R 0 , \ address of the winproc 0 , \ address of library name 0 , \ address of function name -1 , \ # of parameters IS-TEMP-WL 0= IF HERE WINAPLINK @ , WINAPLINK ! ( link ) THEN HERE DUP R@ CELL+ CELL+ ! >R CHARS, HERE SWAP DUP ALLOT MOVE 0 C, R> \ the name of the function HERE R > CELL+ ! 2>R CHARS, HERE SWAP DUP ALLOT MOVE 0 C, 2R> \ the name of the library GetProcAddress SWAP 0= IF -2010 THROW THEN \ ABORT" Procedure not found" ; PREVIOUS DEFINITIONS : WINAPIS: sp-save 1 2 3 ALSO winlibs ;
Комментарии
Отправить комментарий