ANTLR: ANother Tool for Language Recognition¶
Feladat (f02)
Adott az
1 2 3 |
|
nyelvtan. Készíts hozzá egy ANTLR 4 elemzőt, ami hagyományos infix formában kiírja a kifejezést és kiszámolja a kifejezés értékét! Az elemző a paraméterben kapott nevű fájl tartalmát dolgozza fel.
Először is próbáljuk meg átültetni a nyelvtant az ANTLR .g4-es formátumára.
Induljunk ki egy minimális g4 nyelvtanfájlból.
Egy S -> A | B | t
szabály (illetve ez 3 azonos jobboldalú szabály) például s : a | b | T;
lesz, amit szebben
1 2 3 4 5 |
|
t = [0-9]+
tokendefiníció pedig T : [0-9]+;
alakban írható.
A szabályokban használhatunk "inline" tokendefiníciókat is, pl. a fenti kombináció
1 2 3 4 5 6 |
|
1 2 3 4 |
|
Töltsük le az ANTLR jar fájlt, ami az elemző generálásához és a Java-s generált elemző futtatásához szükséges osztályokat is tartalmazza.
Jelölés
A továbbiakban a letöltött antlr-4.11.1-complete.jar
-ra röviden, mint antlr-4-complete.jar
fogunk hivatkozni.
A fájl átnevezése, egy szimbolikus link vagy a parancssorban a megfelelő fájlnév cseréje áthidalja az ebből adódó esetleges problémákat
Az elemző forrásait a java -jar antlr-4-complete.jar Simple.g4
parancs segítségével tudjuk legenerálni.
Nézzük meg, hogy milyen Java nyelvű forrásfájlokat generált a fenti parancs!
A generált forrásokat a javac -cp .:antlr-4-complete.jar *.java
parancs segítségével tudjuk lefordítani.
Az elemző nyelve
Megjegyzendő, hogy az elemző generálását mindenképpen egy Java nyelvű program végzi, de ez nem csak Java, hanem például C++ vagy Python nyelvű forráskódot is generálhat.
Az így generált elemző fordításához/futtatásához további elemek szükségesek (például Java esetén az alapvető .class
fájlok, C++ esetén header fájlok és az alapvető osztályokat/függvényeket megvalósító library is).
1. lépés: csak nyelvtan
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
- Elemző generálás:
java -jar antlr-4-complete.jar Simple.g4
- Elemző fordítás:
javac -cp .:antlr-4-complete.jar *.java
- Ez így még nem futtatható.
Hogyan tehetjük futtathatóvá az elemzőt? A nyelvtanban lehetőségünk van kódrészleteknek a megadására, amiket az elemző generálásakor az ANTLR a megfelelő helyekre be fog szúrni:
- global scope:
@header { ... }
: a...
a fájl elejére lesz beszúrva@members { ... }
: a...
az elemző osztályba lesz beszúrva
- szabály scope (a szabály
:
jele elé beszúrva):@init { ... }
: a szabály metódusának elejére lesz beszúrva a...
@after { ... }
: a szabály metódusának végére lesz beszúrva a...
A beszúrható kódrészletek
Az ANTLR a beszúrandó kódrészleteken csak jól meghatározott, nagyon minimális változtatásokat képes elvégezni. Mivel ezek a kódrészletek a genrált elemző forráskódjába fognak bekerülni, a generálás nyelvén kell őket megírni. A gyakorlaton ez a Java nyelv lesz.
2. lépés: elemzés
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
- Elemző generálás:
java -jar antlr-4-complete.jar Simple.g4
- Elemző fordítás:
javac -cp .:antlr-4-complete.jar *.java
- Elemző futtatás:
java -cp .:antlr-4-complete.jar SimpleParser input.txt
Hogyan fogunk számolni? Ehhez több dolog szükséges:
- Az egyes nyelvtani szabályokhoz szemantikus akciókat rendelhetünk.
Ezek a nyelvtani szabályokba beszúrt
{ ... }
alakú kódrészletek, melyek az elemzés során ott és akkor lesznek végrehajtva, amikor az elemzés az adott ponthoz ér.- Ezekben az akciókban hivatkozhatunk a szabályban (korábban) szereplő elemekre (tokenekre és nemterminálisokra).
A szabályban szereplő
TOKEN
tokenre vagyrule
nemterminálisra az akcióban (a{ ... }
részben) a$TOKEN
vagy$rule
azonosítókkal hivatkozhatunk, illetve lehetőségünk van ezeket megcímkézni, elnevezni alabel=TOKEN
vagy 'label=rule' formában, ami után$label
-ként hivatkozhatunk rájuk (ez kifejezetten jól jön, ha a szabályban egy adott nemterminális vagy token többször is szerepel). A tokeneknek többek között.text
,.int
vagy.line
attribútumaik is vannak, amiket az akciókban a megfelelő módon felhasználhatunk.
- Ezekben az akciókban hivatkozhatunk a szabályban (korábban) szereplő elemekre (tokenekre és nemterminálisokra).
A szabályban szereplő
- Az egyes szabályoknak lehetnek attribútumaik, vagy másképpen fogalmazva paramétereik és visszatérési értékeik.
- A szabályok általános alakja:
rule [ ptype1 par1, ... ] returns [ rtype1 ret1, ... ] locals [ ltype1 loc1, ...] : ...
- Paraméterekkel rendelkező szabályt alkalmazni ("meghívni") csak megfelelő paraméterezéssel lehet:
rule [arg1, ...]
- Visszatérési érték(ek)kel rendelkező szabály által visszaadott értékek kezelése:
sub=rule [arg1, ...] { ... $sub.ret1 ... }
- A szabályok általános alakja:
3. lépés: számolás
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
- Elemző generálás:
java -jar antlr-4-complete.jar Simple.g4
- Elemző fordítás:
javac -cp .:antlr-4-complete.jar *.java
- Elemző futtatás:
java -cp .:antlr-4-complete.jar SimpleParser input.txt