Více úrovní precedence

Jednou z cest, jak analyzovat výrazy v nichž se vyskytují operátory s více úrovněmi precedence, je pro každou další precedenci zavést nový predikát. Ukážeme si to na rozšíření příkladu z předchozí části:
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