expr(W):-
W :->
level1 lchainedBy (symbolA("+") <: symbolA("-")).
level1(W):-
W :->
level0 lchainedBy (symbolA("*") <: symbolA("/")).
level0(W):-
W :->
fact lchainedBy (symbolA("mod") <: symbolA("//")).
Představme si však situaci, kdy máme mnohem více úrovní priority
nebo můžeme operátory přidávat jako v Prologu.
V takovém případě jsme nuceni vytvářet stejně velké množství
téměř identického kódu --
tomu se však lze velice snadno vyhnout pomocí generátoru,
který z daného seznamu operátorů stejné precedence vygeneruje
parser a ten aplikuje na vstup:
exprGen(Operators,P,W):-
mapList(sfx(tokenA),Operators,OpList),
selection(OpList,SepParser),
W :->
P lchainedBy SepParser.
Vytvoření parseru pro libovolný počet úrovní precedence
je pak opravdu jednoduché:
expr(W):-
foldR(sfx2(exprGen),fact(expr),
[["+","-"],["*","/"],["//","mod"]], ExprParser),
W :->
ExprParser.
Nejdříve se zkonstruuje pomocí foldR/4 parser, který bude
na jednotlivých úrovních precedence volat generátor.
Druhý parametr obsahuje parser entity s nejvyšší precedencí a třetí seznam, v jehož položkách jsou vždy operátory stejné precedence.
Tyto podseznamy jsou seřazeny s klesající precedencí. Na každé úrovni
se pak v průběhu rozkladu volá generátor:
?- expr(s("1+10mod3//2*100+2*5//2")+L)
L= [[]> 5]
Yes
Rozšíření o další úroveň priority nyní spočívá v pouhém přidání
podseznamu do třetího parametru predikátu foldR/4 .
Obdobným způsobem, jakým jsme v této kapitole vytvářely nové konstruktory,
by bylo možné pokračovat dál a to v oblasti arity operátorů a typů jejich
asociativity.
V knihovně kombinátorů parserů byl vytvořen obecný
parser výrazů obsahujících unární i binární operátory s libovolným
počtem priorit, u kterých je navíc možné specifikovat
typ jejich asociativity (a to xf, yf, fx,
fy, xfx, xfy, yfx nebo yfy).
Z uživatelského zápisu je nejdříve vygenerován parser ve formě
environmentu, jenž je následně použit pro rozklad vstupního textu.
Pro vyhodnocování v době rozkladu se navíc používá vyhodnocovač, který
je možné specifikovat v jednom z jeho parametrů (podobně jako tomu bylo
u chainL v části
).
Alespoň pro představu si na závěr této kapitoly ukažme, jak by
vypadalo volání tohoto konstruktoru, pokud by jsme jej chtěli použít
pro analýzu podmnožiny jazyka Prolog:
?- s("saveTerm(File,Term):-
| openFile(File,Stream,write),
| write(Term),
| closeFile(Stream,write)")+L
| :->
| expression([[fx(":-",':-'),fx("?-",'?-')],
| [xfx(":-",':-')],
| [xfy(";",';')],
| [xfy("->",'->')],
| [xfy(",",',')],
| [fy("not",'not')]
| ],
| factProlog(id)).
Pro zkonstruování syntaktického stromu je zde použita místo
vyhodnocovače identita id/2.
dvorka
2013-12-31