podstawową strukturą danych Forth jest „słownik”, który mapuje „słowa” na kod wykonywalny lub nazwane struktury danych. Słownik jest zapisywany w pamięci jako drzewo połączonych list z linkami przechodzącymi od najnowszego (ostatnio) zdefiniowanego słowa do najstarszego, aż do znalezienia wartości sentinel, Zwykle wskaźnika NULL. Przełącznik kontekstowy powoduje, że wyszukiwanie listy zaczyna się od innego liścia. Połączone wyszukiwanie listy jest kontynuowane, gdy gałąź scala się z głównym pniem, prowadząc ostatecznie z powrotem do Sentinela, korzenia.Może być kilka słowników. W rzadkich przypadkach, takich jak Meta-kompilacja, słownik może być izolowany i samodzielny.Efekt ten przypomina zagnieżdżanie przestrzeni nazw i może przeciążać słowa kluczowe w zależności od kontekstu.
zdefiniowane słowo zazwyczaj składa się z head i body z głową składającą się z pola nazwy (NF) i pola łącza (LF), a ciało składające się z pola kodu (CF) i pola parametru (PF).
głowa i ciało wpisu słownikowego są traktowane oddzielnie, ponieważ mogą nie być przyległe. Na przykład, gdy program Forth jest rekompilowany dla nowej platformy, głowa może pozostać na komputerze kompilującym, podczas gdy ciało przechodzi do nowej platformy. W niektórych środowiskach (takich jak systemy wbudowane) głowice zajmują niepotrzebnie pamięć. Jednak niektóre Kompilatory krzyżowe mogą umieścić głowy w celu, jeśli sam cel ma obsługiwać interaktywne Forth.
wpis Słownikowyedit
dokładny format wpisu słownikowego nie jest zalecany, a implementacje są różne. Jednak niektóre komponenty są prawie zawsze obecne, chociaż dokładny rozmiar i kolejność mogą się różnić. Opisywany jako struktura, wpis słownika może wyglądać w ten sposób:
structure byte: flag \ 3bit flags + length of word's name char-array: name \ name's runtime length isn't known at compile time address: previous \ link field, backward ptr to previous word address: codeword \ ptr to the code to execute this word any-array: parameterfield \ unknown length of data, words, or opcodes end-structure forthword
pole nazwa zaczyna się od prefiksu określającego długość nazwy słowa (zazwyczaj do 32 bajtów) i kilku bitów dla FLAG. Reprezentacja znaków nazwy słowa następuje po prefiksie. W zależności od konkretnej implementacji Forth, może być jeden lub więcej bajtów NUL (’\0′) do wyrównania.
pole link zawiera wskaźnik do wcześniej zdefiniowanego słowa. Wskaźnik może być względnym przesunięciem lub absolutnym adresem wskazującym na następne najstarsze rodzeństwo.
wskaźnik pola kodu będzie albo adresem słowa, które wykona kod lub dane w polu parametru, albo początkiem kodu maszynowego, który procesor wykona bezpośrednio. W przypadku słów zdefiniowanych dwukropkiem wskaźnik pola kodu wskazuje na słowo, które zapisze bieżący wskaźnik instrukcji Forth (IP) na stosie zwrotnym i załaduje adres IP z nowym adresem, z którego będzie kontynuowane wykonywanie słów. Jest to takie samo, jak to, co robią instrukcje wywołania/powrotu procesora.
struktura kompilatora
sam kompilator nie jest programem monolitycznym. Składa się z wyrazów widocznych dla systemu i użytecznych dla programisty. Pozwala to programiście na zmianę słów kompilatora do specjalnych celów.
flaga „compile time” w polu name jest ustawiana dla słów z zachowaniem „compile time”. Większość prostych słów wykonuje ten sam kod, niezależnie od tego, czy są one wpisane w wierszu poleceń, czy osadzone w kodzie. Kompilując je, kompilator po prostu umieszcza kod lub gwintowany wskaźnik na słowo.
klasycznymi przykładami słów w czasie kompilacji są struktury sterujące, takie jakIF
IWHILE
. Prawie wszystkie struktury sterujące Forth i prawie cały jego kompilator są zaimplementowane jako słowa kompilujące. Oprócz niektórych rzadko używanych słów control flow spotykanych tylko w kilku implementacjach, takich jak warunkowy zwrot, wszystkie słowa control flow Forth są wykonywane podczas kompilacji w celu kompilacji różnych kombinacji prymitywnych słów wraz z ich adresami gałęzi. Na przykład, IF
I WHILE
I słowa, które pasują do nich, skonfiguruj BRANCH
(bezwarunkowa gałąź) i ?BRANCH
(usuwa wartość ze stosu i rozgałęzia, jeśli jest fałszywa). Liczone słowa sterowania przepływem pętli działają podobnie, ale tworzą kombinacje prymitywnych słów, które działają z licznikiem i tak dalej. Podczas kompilacji, stos danych jest używany do obsługi równoważenia struktury kontrolnej, zagnieżdżania i back-patchingu adresów gałęzi. Fragment:
... DUP 6 < IF DROP 5 ELSE 1 - THEN ...
zostanie skompilowany do następującej sekwencji wewnątrz definicji:
... DUP LIT 6 < ?BRANCH 5 DROP LIT 5 BRANCH 3 LIT 1 - ...
liczby poBRANCH
reprezentują względne adresy skoków. LIT
jest prymitywnym słowem do pchania „dosłownej” liczby na stos danych.
Stan kompilacji i stan interpretacjiedit
słowo:
(dwukropek) parsuje nazwę jako parametr, tworzy wpis słownikowy (definicję dwukropka) i wprowadza stan kompilacji. Interpreter nadal odczytuje słowa rozdzielone spacjami z urządzenia wejściowego użytkownika. Jeśli zostanie znalezione słowo, interpreter wykonuje semantykę kompilacji związaną z tym słowem, zamiast semantyki interpretacji. Domyślną semantyką kompilacji słowa jest dołączenie jego semantyki interpretacji do bieżącej definicji.
słowo ;
(średnik) kończy bieżącą definicję i powraca do stanu interpretacji. Jest to przykład słowa, którego semantyka kompilacji różni się od domyślnej. Semantyka interpretacji ;
(średnik), większość słów przepływu sterowania i kilka innych słów są niezdefiniowane w ANS Forth, co oznacza, że muszą być używane tylko wewnątrz definicji, a nie w interaktywnym wierszu poleceń.
stan interpretera można zmienić ręcznie za pomocą słów (prawy nawias), które odpowiednio wprowadzają stan interpretacji lub stan kompilacji. Te słowa mogą być użyte ze słowem
LITERAL
, aby obliczyć wartość podczas kompilacji i wstawić obliczoną wartość do bieżącej definicji dwukropka. LITERAL
posiada semantykę kompilacji do pobierania obiektu ze stosu danych i dołączania semantyki do bieżącej definicji dwukropka w celu umieszczenia tego obiektu na stosie danych.
w ANS Forth aktualny stan interpretera można odczytać ze znacznikaSTATE
, który zawiera wartość true w stanie kompilacji i false w przeciwnym razie. Pozwala to na implementację tzw. State-smart words z zachowaniem, które zmienia się w zależności od aktualnego stanu interpretera.
słowa Natychmiastoweedit
słowoIMMEDIATE
oznacza najnowszą definicję dwukropka jako słowo natychmiastowe, skutecznie zastępując semantykę kompilacji semantyką interpretacji. Bezpośrednie słowa są zwykle wykonywane podczas kompilacji, a nie kompilowane, ale może to być nadpisane przez programistę w każdym stanie. ;
jest przykładem słowa bezpośredniego. W ANS Forth, słowo POSTPONE
przyjmuje nazwę jako parametr i dołącza semantykę kompilacji nazwanego słowa do bieżącej definicji, nawet jeśli słowo zostało oznaczone natychmiastowo. Forth-83 zdefiniowane oddzielne słowa COMPILE
I , aby wymusić kompilację słów nie-natychmiastowych i natychmiastowych.
nienazwane słowa i tokeny wykonaniaedit
w ANS Forth, nienazwane słowa mogą być zdefiniowane słowem:NONAME
, które kompiluje następujące słowa do następnego;
(średnik) i pozostawia token wykonania na stosie danych. Token wykonania zapewnia nieprzezroczysty uchwyt dla skompilowanej semantyki, podobny do wskaźników funkcji języka programowania C.
tokeny wykonania mogą być przechowywane w zmiennych. Słowo EXECUTE
pobiera token wykonania ze stosu danych i wykonuje powiązaną semantykę. Słowo COMPILE,
(compile-comma) pobiera token wykonania ze stosu danych i dołącza powiązaną semantykę do bieżącej definicji.
słowo'
(tick) przyjmuje nazwę słowa jako parametr i zwraca token wykonania powiązany z tym słowem na stosie danych. W stanie interpretacji ' RANDOM-WORD EXECUTE
jest odpowiednikiem RANDOM-WORD
.
Edytuj
słowa:
(dwukropek),POSTPONE
'
(tick) są przykładami parsowania słów, które pobierają swoje argumenty z urządzenia wejściowego użytkownika zamiast stosu danych. Innym przykładem jest słowo (
(paren), które odczytuje i ignoruje następujące słowa do następnego prawego nawiasu włącznie i jest używane do umieszczania komentarzy w definicji dwukropka. Podobnie, słowo \
(odwrotny ukośnik) jest używane dla komentarzy, które kontynuują do końca bieżącego wiersza. Aby poprawnie parsować, (
(paren) i \
(ukośnik wsteczny) muszą być oddzielone spacjami od następującego tekstu komentarza.
struktura codeEdit
w większości systemów Forth ciało definicji kodu składa się z języka maszynowego lub jakiejś formy kodu gwintowanego. Oryginał Forth, który podąża za nieformalnym standardem FIG (Forth Interest Group), jest TIL (gwintowany język interpretacyjny). Jest to również nazywane kodem pośrednim, ale forty gwintowane bezpośrednie i podprogram stały się również popularne w czasach nowożytnych. Najszybsze nowoczesne Forty, takie jak SwiftForth, VFX Forth i iForth, kompilują się do natywnego kodu maszynowego.
Obiekty Daneedit
gdy słowo jest zmienną lub innym obiektem danych, CF wskazuje na kod uruchomieniowy powiązany ze słowem definiującym, które je utworzyło. Słowo definiujące ma charakterystyczne „definiujące zachowanie” (tworzenie wpisu słownikowego plus ewentualnie przydzielanie i inicjalizacja przestrzeni danych), a także określa zachowanie instancji klasy słów skonstruowanych przez to słowo definiujące. Przykłady obejmują:
VARIABLE
nazywa niezainicjalizowaną, jednokomórkową lokalizację pamięci. Zachowanie instancjiVARIABLE
zwraca jej adres na stosie.CONSTANT
nazywa wartość (określoną jako argument doCONSTANT
). Zachowanie instancji Zwraca wartość.CREATE
określa lokalizację; przestrzeń może być przydzielona w tej lokalizacji lub może być ustawiona na łańcuch znaków lub inną zainicjowaną wartość. Zachowanie instancji zwraca adres początku tej przestrzeni.
Forth zapewnia również funkcję, za pomocą której programista może definiować nowe słowa definiujące specyficzne dla aplikacji, określając zarówno niestandardowe zachowanie definiujące, jak i zachowanie instancji. Niektóre przykłady obejmują okrągłe bufory, nazwane bity na porcie We / Wy i automatycznie indeksowane tablice.
obiekty danych zdefiniowane tymi i podobnymi słowami mają zasięg globalny. Funkcja dostarczana przez zmienne lokalne w innych językach jest dostarczana przez stos danych w Forth (chociaż Forth ma również rzeczywiste zmienne lokalne). Styl programowania Forth wykorzystuje bardzo niewiele nazwanych obiektów danych w porównaniu z innymi językami; zazwyczaj takie obiekty danych są używane do przechowywania danych, które są używane przez wiele słów lub zadań (w implementacji wielozadaniowej).
Forth nie wymusza spójności użycia typu danych; obowiązkiem programisty jest użycie odpowiednich operatorów do pobierania i przechowywania wartości lub wykonywania innych operacji na danych.