Een configuratiebestand parsenLaten we een deel van het eerder genoemde configuratiebestand herhalen: zone "." { type hint; file "/etc/bind/db.root"; };We hebben al een Lexer voor dit bestand. Nu hoeven we alleen nog maar een YACC grammatica te schrijven, en de Lexer aanpassen zodat het waarden teruggeeft in een vorm die YACC kan snappen.In de lexer van Voorbeeld 6 zien we: %{ #include <stdio.h> #include "y.tab.h" %} %% zone return ZONETOK; file return FILETOK; [a-zA-Z][a-zA-Z0-9]* yylval=strdup(yytext); return WOORD; [a-zA-Z0-9\/.-]+ yylval=strdup(yytext); return BESTANDSNAAM; \" return QUOTE; \{ return OBRACE; \} return EBRACE; ; return PUNTKOMMA; \n /* negeer einde regel*/; [ \t]+ /* negeer whitespace */; %% Als je goed kijkt, zie je dat yylval veranderd is! We verwachten niet meer dat het een integer is, maar nemen aan dat het een char * is. Voor de eenvoud roepen we strdup aan en verspillen een hoop geheugen. Merk op dat dit geen probleem is in veel gevallen als je een bestand maar een keer hoeft te parsen, en dan exit.We willen strings opslaan omdat we nu voornamelijk met namen te maken hebben: bestandsnamen en zonenamen. In een later hoofdstuk zullen we uitleggen hoe je met verschillende soorten data omgaat.Om YACC over het nieuwe type van yylval te vertellen, voegen we dit toe aan de header van onze YACC grammatica: #define YYSTYPE char *De grammatica zelf is weer ingewikkelder. We hakken het in stukjes om het verteerbaarder te maken.commands: | commands command PUNTKOMMA ; command: zone_set ; zone_set: ZONETOK quotedname zonecontent { printf("Complete zone for '%s' gevonden\n",$2); } ; Dit is de intro, inclusief voornoemde recursieve `wortel' Merk op dat we specificeren dat commands worden getermineerd (en gescheiden) door ;'s. We definiëren één soort command, de `zone_set'. Deze bestaat uit het ZONE token (het woord `zone'), gevolgd door een quotedname en de `zonecontent'. De zonecontent begint eenvoudig: zonecontent: OBRACE zonestatements EBRACE Hij moet beginnen met een OBRACE, een {. Dan komen de zonestatements, gevolgd door een EBRACE, een }.quotedname: QUOTE BESTANDSNAAM QUOTE { $$=$2; } Deze sectie definieert een `quotedname': een BESTANDSNAAM tussen QUOTES. Dan iets bijzonders: de waarde van een quotedname token is de waarde van de BESTANDSNAAM. Dit betekent dat de quotedname als waarde de bestandsnaam zonder quotes heeft.Dat is wat het magische `$$=$2' doet. Het zegt: mijn waarde is de waarde van mijn tweede deel. Als nu naar de quotedname verwezen wordt in andere regels, en je benadert zijn waarde met de $-constructie, zie je de waarde die we hier ingesteld hebben met $$=$2.OPMERKING: deze grammatica verslikt zich in bestandsnamen zonder een `.' of een `/' erin.zonestatements: | zonestatements zonestatement PUNTKOMMA ; zonestatement: statements | FILETOK quotedname { printf("Een zonefile naam '%s' tegengekomen\n", $2); } ; Dit is een algemeen statement die alle soorten statements binnen het `zone' blok afvangt. We zien opnieuw de recursiviteit.block: OBRACE zonestatements EBRACE PUNTKOMMA ; statements: | statements statement ; statement: WOORD | block | quotednameDit definieert een blok, en `statements' die er in gevonden kunnen worden.Bij uitvoering ziet de uitvoer er zo uit:$ ./example6 zone "." { type hint; file "/etc/bind/db.root"; type hint; }; Een zonefile naam '/etc/bind/db.root' tegengekomen Complete zone for '.' gevonden