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