FORTH: Selbstdefinierende Wörter

    Es gebe ein Projekt in der Sprache Fort, in dem eine ausreichend große Anzahl von Variablen desselben Typs verwendet werde.
    Zum Beispiel: x, y, z, x ', y', z ', x' ', y' ', z' ', s, m und so weiter ...
    Um sie zu bestimmen, müssen Sie jedes Mal das Wort VARIABLE ausschreiben. traurig und hässlich. Gibt es eine Möglichkeit, es lustiger zu machen?
    Geben Sie an, dass weitere Variablen definiert werden, und schreiben Sie deren Namen.
    So etwas wie:
    VARIABLEN:
      xyz  
      x 'y' z '
      x '' y '' z ''
      sm
    VARIABLEN
    



    Denken Sie daran, dass der in SP-Forth implementierte Fort-Interpreter, wenn er kein Wort im Kontextwörterbuch findet, nach dem Wort NOTFOUND im selben Kontextwörterbuch sucht, das er ausführt. Die NOTFOUND-Eingabeparameter sind die Adresse und der Zähler der Teilzeichenfolge aus dem Eingabestream. Sie müssen also NOTFOUND neu definieren, damit es das tut, was wir brauchen.

    Was brauchst du
    Nehmen Sie dieses nicht gefundene Wort und kompilieren Sie es als Variable oben im aktuellen Wörterbuch. Ich erinnere mich an die Definition
     : VARIABLE CREATE 0 ,;
    

    Das Wort CREATE selbst wählt jedoch das nächste Wort aus dem Eingabestream aus, und wir müssen einen Wörterbucheintrag aus einer Zeile mit einer Adresse und einem Zähler auf dem Stapel erstellen. Glücklicherweise gibt es in diesem Fall das Wort CREATED, das nur die Adresse und den Zeilenzähler vom Stapel nimmt und einen Wörterbucheintrag erstellt. Leider ist es wie NOTFOUND nicht Teil des ANSI-94-Standardwortsatzes.
    Auf diese Weise
    : NOTFOUND (addr u -) CREATED 0 ,; 
    

    Wenn wir jedoch eine solche Definition in die FORTH-Basisliste aufnehmen, verlieren wir die Möglichkeit, Zahlen einzugeben. Sie müssen diesen neuen NOTFOUND also in einem anderen Kontext verstecken. Holen wir uns das Variablen-Wörterbuch.
    VOCABULARY-Variablen 
    

    und mach es aktuell.
    AUCH Variablen DEFINITIONEN
    

    Geben Sie dort die Definition von NOTFOUND ein und geben Sie

    den aktuellen Kontext zurück
    VORHERIGE BEGRIFFSBESTIMMUNGEN
    


    Das Wort VARIABLES: schaltet also den Kontext auf Variablen um und stellt den benötigten NOTFOUND zur Verfügung
    : VARIABLEN: AUCH Variablen;
    

    Schlusswort: VARIABLES gibt einen Kontext zurück. Es sollte natürlich im Zusammenhang mit Variablen sein.

    Das heißt, insgesamt:
    VOCABULARY-Variablen 
    AUCH Variablen DEFINITIONEN
    : NOTFOUND (addr u -) CREATED 0 ,; 
    :; VARIABLES VORHERIGES; 
    VORHERIGE BEGRIFFSBESTIMMUNGEN
    : VARIABLEN: AUCH Variablen;
    

    In nur vier Zeilen haben wir den SP-Forth-Interpreter erweitert und die Beschreibung der Variablen vereinfacht.
    Ein ähnlicher Ansatz kann jedoch für VALUE-Variablen, Konstanten und im Allgemeinen für beliebige Wörter mit gängiger Ausführungssemantik verwendet werden. Die Wörter, die mit dem definierenden Wort definiert werden. Grundsätzlich ist es sinnvoll, Paare definierender Wörter zu haben. Eine für eine einzelne Definition und gepaart für eine Gruppendefinition. Tatsächlich wird das definierende Wort erstellt, um Wortgruppen mit gemeinsamer Semantik erstellen zu können. Und es ist praktisch, wenn diese Definitionen nicht über den Text verteilt, sondern in einem Block zusammengefasst werden.

    Versuchen wir dies für VALUE-Variablen zu implementieren.
    VOCABULARY-Werte
    Werte AUCH DEFINITIONEN
    : NOTFOUND ...
    

    Und hier stoßen wir auf einige Schwierigkeiten. Das Qualifikationswort VALUE wird nicht über CREATE definiert. Es ist wie folgt definiert:
    : WERT  
           HEADER
           ['] _CONSTANT-CODE COMPILE ,,
           ['] _TOVALUE-CODE COMPILE,
    ;
    

    Glücklicherweise hat das Wort HEADER, das einen String aus dem Eingabestream entnimmt, ein Paar in Form des Wortes SHEADER, synonym mit dem Wort CREATED.
    Ersetzen Sie einfach einen durch den anderen und erhalten Sie die erforderliche Version des Wortes.
    : VALUED (n addr u ---)
          SHEADER
          ['] _CONSTANT-CODE COMPILE ,,
          ['] _TOVALUE-CODE COMPILE,
    ;
    


    Also:
    VOCABULARY-Werte
    Werte AUCH DEFINITIONEN
    :; WERTE VORHERIGER TROPFEN;
    : NOTFOUND VALUED 0;
    VORHERIGE BEGRIFFSBESTIMMUNGEN 
    : WERTE: AUCH Werte 0;
    

    Aber es gibt einen Nachteil. Alle VALUEs werden auf Null initialisiert. Es wäre schön, dies zu beseitigen.
    Es gibt möglicherweise mehrere Optionen für die Implementierung.
    Du kannst einfach aufnehmen
    WERTE:
      11 aa   
      22 bb 
      33 cm³
    WERTE
    

    Das ist nicht lesbar.

    Versuchen wir mal so zu schreiben:
    WERTE:
       aa = 11
       bb = 22
       cc = 33 
    WERTE
    

    Es sieht wunderschön aus.

    Offensichtlich muss das Wort "gleich" im Kontext von Werten vorhanden sein. Man muss das nächste Wort auswählen und als Zahl interpretieren. Das heißt, fast synonym mit LITERAL zu sein. Ein anderes "Gleich" sollte diesen Wert der zuletzt definierten VALUE-Variablen zuweisen.

    Wir schreiben
    VOCABULARY-Werte
    Werte AUCH DEFINITIONEN
    :; WERTE VORHERIGER TROPFEN;
    : = BL WORD? LITERAL LATEST NAME> 9 + EXECUTE;
    : NOTFOUND VALUED 0;
    VORHERIGE BEGRIFFSBESTIMMUNGEN 
    : WERTE: AUCH Werte 0;
    


    Eine solche Option
    WERTE:
      11 bis aa   
      22 bis bb 
      33 bis cc
    WERTE
    
    Dies ist insofern von Vorteil, als es nicht aus dem Paradigma der Sprache herausfällt. Außerdem können Sie VALUE-Variablen mit berechneten Werten initialisieren.
    WERTE:
           11 bis aa   
      22 1980 * TO bb 
      aa bb + TO cc
    WERTE
    

    Um es zu implementieren, müssen Sie NOTFOUND nicht neu definieren. Nur die Bedeutung des Wortes TO wird geändert. Zwischen den WERTEN: Abschlusswörter :; WERTEN ZU sollte sich wie ein normaler WERT verhalten.
    VOCABULARY-Werte
    Werte AUCH DEFINITIONEN
    :; WERTE VORHERIGER;
    : TO VALUE;
    VORHERIGE BEGRIFFSBESTIMMUNGEN 
    : WERTE: AUCH Werte;
    


    Sie können eine ähnliche Schreibweise für Konstanten erstellen.
    KONSTANTE:
           11 IS aa   
      22 1980 * IS bb 
      aa bb + IS cc
    CONSTANTS
    

    Die Implementierung dieser Methode liegt meiner Meinung nach auf der Hand.

    Im Allgemeinen bildet diese Kampagne eine neue Art der Definition von Wörtern - gruppendefinierende Wörter. Mit einem einfachen Definitionswort können Sie Wörter erstellen, die durch eine gemeinsame Semantik verbunden sind. Bei Gruppen mit derselben Eigenschaft müssen die Definitionen der gleichen Wortart auf einen Teil des Quelltextes konzentriert werden. Das wirkt sich positiv auf die Lesbarkeit und Begleitung aus.
    Eine viel unterhaltsamere Ergänzung zu SP-SP-Forth ist die Gruppenimplementierung des Wortes WINAPI:. Insbesondere in der Winctl-Bibliothek sind WINAPI-Definitionen im gesamten Text verteilt, was düster aussieht.
    Als Option:
    WINAPIS:
        LIB: USER32.DLL
                 PostQuitMessage
                 PostMessageA
                 SetActiveWindow
        LIB: GDI32.DLL
                 CreateFontA
                 GetDeviceCaps
                 DeleteDC
        LIB: COMCTL32.DLL
                 InitCommonControlsEx
    WINAPIS
    

    Schauen Sie sich dazu an, wie das Wort WINAPI implementiert ist:
    spf_win_defwords.f

    : __WIN: (params "ProcedureName" "LibraryName" -)
      HIER> R
      0, \ Adresse von winproc
      0, \ Adresse des Bibliotheksnamens
      0, \ Adresse des Funktionsnamens
      Anzahl der Parameter
      IS-TEMP-WL 0 =
      IF
        HIER WINAPLINK @, WINAPLINK! (Mitteilung)
      DANN
      HIER DUP R @ CELL + CELL +!
      PARSE-NAME HIER CHARS SWAP DUP ALLOT MOVE 0 C \ Funktionsname
      HIER DUP R> CELL +!
      PARSE-NAME CHARS HERE DUP DUP ALLOT MOVE 0 C, \ Bibliotheksname
      LoadLibraryA DUP 0 = IF -2009 THROW THEN \ ABORT "Bibliothek nicht gefunden"
      GetProcAddress 0 = IF -2010 THROW THEN \ ABORT "Prozedur nicht gefunden"
    ;
    : WINAPI: ("ProcedureName" "LibraryName" -)
      (Wird zum Importieren von WIN32-Prozeduren verwendet.
        Die resultierende Definition heißt ProcedureName.
        Die Adresse des winproc-Feldes wird zum Zeitpunkt der ersten Eingabe ausgefüllt
        Ausführung des resultierenden Wörterbucheintrags.
        Aufruf der empfangenen "Import" -Prozedurparameter
        in umgekehrter Reihenfolge auf den Datenstapel geschoben
        im C-Aufruf dieser Prozedur. Funktion Ergebnis
        wird auf den Stapel geschoben.
      )
      NEU-WINAPI?
      WENN HEADER
      ELSE
        -1
        > IN @ HEADER> IN!
      DANN
      ['] _WINAPI-CODE COMPILE,
      __WIN:
    ;
    


    Anscheinend ist das verzögerte Laden der DLL implementiert. Eine Verknüpfung zum WinAPI-Aufrufcode wird in einen Wörterbucheintrag mit dem Namen der importierten Funktion, einigen Parametern und dem Namen der Bibliotheksdatei und der darin enthaltenen Prozedur kompiliert. Dann findet das Vorhandensein einer solchen Datei und einer solchen Prozedur statt.
    Um diesen Code unseren Wünschen anzupassen, bestimmen wir, was jedes Wort tun wird.
    ; WINAPIS - stellt nur den Kontext wieder her.
    LIB: - gibt das nächste Wort aus dem Eingabestream ein und speichert es in einem temporären Puffer. Es kann mit der Validierung kombiniert werden.
    Die restlichen Wörter werden als Namen der Prozeduren wahrgenommen.

    Also:
    string to stack.f

    SP @ VALUE spstore 
    : sp-save SP @ TO spstore;
    : sp-restore spstore SP! ;
    : s-allot (n bytes - addr) sp-save spstore Tausch - Ausgerichtetes DUP> R CELL-CELL-SP! R>;
    : ss (- addr u) NächstesWort 2> RR @ 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

    Wortschatz winlibs
    AUCH winlibs DEFINITIONEN
    :; WINAPIS s-free ZURÜCK;
    : LIB: (- addr u id) s-frei ss CR OVER LoadLibraryA DUP 0 = WENN -2009 THROW THEN;
    : NOTFOUND (addr u id addr u - addr u id) 
              2> R 3DUP 2R>    
              2DUP SHEADER
              ['] _WINAPI-CODE COMPILE, 
              HIER> R  
              0, \ Adresse von winproc
              0, \ Adresse des Bibliotheksnamens 
              0, \ Adresse des Funktionsnamens
              -1, \ # der Parameter
              IS-TEMP-WL 0 =
                         IF
                            HIER WINAPLINK @, WINAPLINK! (Mitteilung)
                         DANN 
                  HIER DUP R @ CELL + CELL +! > R
                   HIER CHARS SWAP DUP ALLOT MOVE 0 C, R> \ Funktionsname
                  HIER R> CELL +! 2> R  
                    HIER CHARS SWAP DUP ALLOT MOVE 0 C, 2R> \ Bibliotheksname 
                  SWAP GetProcAddress 0 = IF -2010 THROW THEN \ ABORT "Prozedur nicht gefunden"
    ;
     VORHERIGE BEGRIFFSBESTIMMUNGEN
    : WINAPIS: sp-save 1 2 3 AUCH winlibs; 
    





    Jetzt auch beliebt: