Niedawno podjąłem się zadania napisania języka programowania opartego na stosie. Zanim jednak zacząłem projektować swój język, pomyślałem, że dobrym pomysłem byłoby czytanie i eksperymentowanie z istniejącymi językami stosowymi.
To prowadzi mnie do tematu tego postu. Czytałem artykuł w Wikipedii na temat Forth , języka opartego na stosie, który używa wyrażeń w stylu postfiksowym. W artykule widziałem następujące oświadczenie:
Elastyczność Fortha sprawia, że statyczna gramatyka BNF jest nieodpowiednia i nie ma monolitycznego kompilatora. Rozszerzenie kompilatora wymaga tylko napisania nowego słowa, zamiast modyfikacji gramatyki i zmiany podstawowej implementacji.
Z mojego zrozumienia, w języku żargonu Forth, termin „słowo” wydaje się zasadniczo równoznaczny z „podprogramem”. Biorąc to pod uwagę, powyższe stwierdzenie wydaje się dziwne. Dlaczego właśnie możliwość tworzenia nowych funkcji w Forth sprawia, że formalna gramatyka dla Forth jest nieodpowiednia? Dlaczego musiałbyś przepisywać gramatykę dla każdego nowego podprogramu, który zdefiniujesz? W jaki sposób pisanie nowego słowa w środowisku stanowi rozszerzenie kompilatora? Powyższe stwierdzenie wydaje się podobne do stwierdzenia, że gramatyka formalna jest nieodpowiednia dla Pythona, ponieważ można definiować nowe funkcje.
W rzeczywistości postanowiłem napisać gramatykę w stylu BNF dla prostego podzbioru Forth poniżej:
program ::= stmt+
stmt ::= func | expr
func ::= ':' expr+ ';'
expr ::= INTEGER | word
word ::= ('+' | '-' | '*' | '/' )
Powyższa gramatyka wydaje się obejmować prawidłowy podzbiór zdań Fortha i nie wydaje się, że trudno jest rozszerzyć ją na wszystkie prawidłowe instrukcje w języku Forth. Ponadto, jeśli parser kompilatora implementuje powyższą gramatykę, nie widzę, jak kiedykolwiek kompilator mógłby zostać rozszerzony. Kompilator po prostu doda nowe słowa do swojego środowiska . Zmienia się tylko środowisko. Wydaje się, że powyższy fragment Wikipedii łączy w sobie kod podkreślający, który tworzy kompilator (który się nie zmienia) ze środowiskiem kompilatora (który się zmienia).
Podsumowując, dlaczego nieumiejętność Fortha w zakresie definiowania nowych słów (podprogramów) jest nieodpowiednia dla gramatyki pisanej?
Odpowiedzi:
„Normalne” słowo jest właściwie tylko podprogramem.
... ale możesz napisać zdefiniowane przez użytkownika słowo , które zmienia sposób działania kompilatora. Na przykład definicja zwykle rozpoczyna się dwukropkiem („:”), a kończy średnikiem („;”). Ale jeśli chcesz, możesz (na przykład) zmienić to, co robi dwukropek, a tym samym zmienić sposób, w jaki definicja słowa jest „kompilowana”, zmieniając w ten sposób sposób działania kompilatora i zmieniając gramatykę rozpoznawanego języka.
Dlatego mówi, że gramatyka jest nieodpowiednia - gramatyka może dosłownie zmieniać się z jednej części programu na inną. Ładowanie słownika może zmienić nie tylko podprogramy, których nazwy są obecnie rozpoznawane, ale także gramatykę analizowaną podczas definiowania nowego słowa.
źródło
W Forth możesz uruchomić kod w czasie kompilacji.
W szczególności możesz uruchomić kod, który zużywa słowa z danych wejściowych. Na przykład, możesz napisać kompilator C w Forth, a następnie wywołać go w czasie kompilacji, a następnie napisać resztę swojego programu w C.
Częściej można definiować słowa, które odczytują argumenty z kodu źródłowego. Tradycyjnie czytałbyś słowa w taki sam sposób jak kompilator, ale nie jest to wymagane.
Na przykład
."
słowo (które wypisuje ciąg) nie odczytuje się do następnej spacji, odczytuje do następnej"
. Jeśli spróbujesz parsować kod: PRINTHELLO ." Hello ; : func2 world!" ;
bez specjalnego przypadku."
, okaże się, że nie jest on poprawnie parsowany.Można oczywiście dodać szczególny przypadek dla
."
do gramatyki, ale gramatyka nadal będzie nieprawidłowy, jeśli programista definiuje swoje własne słowo jak."
- na przykład tutaj jest jeden:: MY_PRINT POSTPONE ." ; IMMEDIATE
. To słowo jest równoważne z."
; Mogę pisać,MY_PRINT Hello ; world! "
a twoja gramatyka musi być w stanie to przeanalizować. Powodzenia z tym.źródło