Piszę parser dla utworzonego przeze mnie języka znaczników (piszę w Pythonie, ale to nie jest tak naprawdę istotne w przypadku tego pytania - w rzeczywistości, jeśli wydaje się to złym pomysłem, chętnie zaproponuję lepszą ścieżkę) .
Czytam o parserach tutaj: http://www.ferg.org/parsing/index.html i pracuję nad napisaniem leksera, który, jeśli dobrze rozumiem, powinien podzielić zawartość na tokeny. Nie rozumiem, jakich typów tokenów powinienem używać i jak je tworzyć. Na przykład typy tokenów w przykładzie, z którym się połączyłem, to:
- STRUNOWY
- IDENTYFIKATOR
- NUMER
- BIAŁA PRZESTRZEŃ
- KOMENTARZ
- EOF
- Wiele symboli, takich jak {i (liczy się jako własny typ tokena)
Problemem jest to, że bardziej ogólne typy tokenów wydają mi się nieco arbitralne. Na przykład, dlaczego STRING ma swój własny osobny typ tokena kontra IDENTYFIKATOR. Ciąg może być reprezentowany jako STRING_START + (IDENTIFIER | WHITESPACE) + STRING_START.
Może to mieć również związek z trudnościami mojego języka. Na przykład deklaracje zmiennych są zapisywane {var-name var value}
i wdrażane za pomocą {var-name}
. Wygląda na to, że powinny '{'
i '}'
powinny być ich własnymi tokenami, ale czy VAR_NAME i VAR_VALUE są odpowiednimi typami tokenów, czy też oba byłyby objęte IDENTYFIKATOREM? Co więcej, VAR_VALUE może faktycznie zawierać białe znaki. Biały var-name
znak po służy do oznaczenia początku wartości w deklaracji. Wszelkie inne białe znaki są częścią wartości. Czy ta biała przestrzeń staje się własnym tokenem? Białe znaki mają tylko to znaczenie w tym kontekście. Co więcej, {
może nie być początkiem deklaracji zmiennej. Zależy to od kontekstu (znowu to słowo!). {:
rozpoczyna deklarację nazwy i{
może być nawet używany jako część pewnej wartości.
Mój język jest podobny do Pythona, ponieważ bloki są tworzone z wcięciem. Czytałem o tym, w jaki sposób Python używa leksykonu do tworzenia tokenów INDENT i DEDENT (które służą mniej więcej tak, jak {
i }
robią w wielu innych językach). Python twierdzi, że jest pozbawiony kontekstu, co oznacza dla mnie, że przynajmniej leksykon nie powinien dbać o to, gdzie jest w strumieniu podczas tworzenia tokenów. Skąd leksem Python wie, że buduje token INDENT o określonej długości, nie wiedząc o poprzednich znakach (np. Że poprzednia linia była nową linią, więc zacznij tworzyć spacje dla INDENT)? Pytam, bo ja też muszę to wiedzieć.
Moje ostatnie pytanie jest najgłupsze: dlaczego leksykon jest nawet potrzebny? Wydaje mi się, że analizator składni mógłby przejść znak po znaku i dowiedzieć się, gdzie jest i czego się spodziewa. Czy leksykon dodaje korzyści wynikające z prostoty?