Yacc 10192021 Institutt for informatikk INF 5110 2005

  • Slides: 37
Download presentation
Yacc 10/19/2021 © Institutt for informatikk INF 5110 - 2005 Yet Another Compiler 1

Yacc 10/19/2021 © Institutt for informatikk INF 5110 - 2005 Yet Another Compiler 1

Yak Langhåret kveg med pukkel Finnes i Tibet og øvrige områder i Himalaya Villyaken

Yak Langhåret kveg med pukkel Finnes i Tibet og øvrige områder i Himalaya Villyaken er cirka 2 meter høy ved skulderen, tam yak ca 1 meter ”Yak” er oksen, hunn-yaken kalles ”dri” eller ”nak” Yak-melk har en rosa farge Grynter istedet for å raute INF 3110/4110 - 2004 § § § INF 5110 - 2005 10/19/2021 2

Yacc – et helt annet dyr § Yacc er en ”parsergenerator” – Yacc er

Yacc – et helt annet dyr § Yacc er en ”parsergenerator” – Yacc er ikke en parser i seg selv § Genererer en parser i C basert på en gitt grammatikk INF 3110/4110 - 2004 § Håndterer LALR(1) grammatikker – Merk: Bison støtter en såkalt ”Generalized LR” modus som er mer fleksibel § Bison – GPL alternativ til Yacc (installert på IFI – bruk i oblig) INF 5110 - 2005 10/19/2021 3

Bruk av Yacc § § § 10/19/2021 INF 5110 - 2005 /* Called by

Bruk av Yacc § § § 10/19/2021 INF 5110 - 2005 /* Called by yyparse on error. */ void yyerror (char const *s) { printf ("%sn", s); } INF 3110/4110 - 2004 Brukeren definerer en grammatikk i BNF-form Hver produksjon kan ha en assosiert ”action” En action er en blokk med C-kode Actions brukes vanligvis for å bygge opp et syntakstre I enklere tilfeller (gjerne brukt i eksempler), kan man foreta utregninger direkte (tenk f. eks en enkel kalkulator) § Brukeren kaller funksjonen yyparse() for å starte parseringen – I main()? § Yacc kaller yyerror() ved feil: 4

Yacc-filer § Vanlig med filendingen. y § Har følgende struktur: definisjoner %% produksjoner %%

Yacc-filer § Vanlig med filendingen. y § Har følgende struktur: definisjoner %% produksjoner %% epilog § C-kommentarer(/*. . */) tillatt overalt 10/19/2021 INF 5110 - 2005 § (Ikke tilfeldig at strukturen ligner på lex’) INF 3110/4110 - 2004 %{ prolog %} 5

Prolog INF 3110/4110 - 2004 § Starter med %{, ender med %} § Inneholder

Prolog INF 3110/4110 - 2004 § Starter med %{, ender med %} § Inneholder C-kode – #include – #define – typedef – funksjonsdeklarasjoner § yacc rører ikke denne koden – Blir kopiert a verbo til output § Funksjonene yylex() og yyerror() må defineres her – Enten inline eller via #include INF 5110 - 2005 10/19/2021 6

Epilog § § Vilkårlig C kode int main() Implementasjoner av yylex() og yyerror() Hjelpefunksjoner

Epilog § § Vilkårlig C kode int main() Implementasjoner av yylex() og yyerror() Hjelpefunksjoner INF 3110/4110 - 2004 INF 5110 - 2005 10/19/2021 7

Definisjoner § Kan være tom – Kun i de mest trivielle tilfellene § Alle

Definisjoner § Kan være tom – Kun i de mest trivielle tilfellene § Alle terminaler som ikke består av en enkelt karakter må deklareres som såkalte %token: %token INT_LITERAL FLOAT_LITERAL § Inneholder andre direktiver som påvirker parseren (vi kommer tilbake til disse) –%type –%left –%nonassoc – etc 10/19/2021 INF 5110 - 2005 –%right INF 3110/4110 - 2004 –’+’, ’-’ etc trenger ikke deklareres som %token 8

Produksjoner § Inneholder en grammatikk i BNF-form – Produksjonene skrives slik: exp: NUM ’+’

Produksjoner § Inneholder en grammatikk i BNF-form – Produksjonene skrives slik: exp: NUM ’+’ exp; § Ikketerminaler skrives typisk med små bokstaver – Som en identifier: RETURN § Vanlig med store bokstaver for terminaler – Som en enkel karakter: ’+’ – Som en C-streng: ”return” § Kun støttet i Bison, ikke i originale Yacc § Produksjoner må avsluttes med semikolon 10/19/2021 INF 5110 - 2005 § Anbefalt dersom man skal representere tokens som bare består av en karakter (matematiske operatorer etc) INF 3110/4110 - 2004 § Terminaler kan representeres på tre måter: 9

Produksjoner (forts) § | kan brukes for alternering: stmt: if_stmt | while_stmt | for_stmt

Produksjoner (forts) § | kan brukes for alternering: stmt: if_stmt | while_stmt | for_stmt ; stmt: if_stmt ; while_stmt ; for_stmt ; 10/19/2021 INF 5110 - 2005 § Det første er mest vanlig § Startsymbolet er den ikketerminalen som er på venstresiden av den første produksjonen – Eller man kan definere startsymbolet med direktivet %start INF 3110/4110 - 2004 § Eller man kan skrive slik: 10

yylex() § Yacc kaller funksjonen yylex() hver gang den trenger et nytt token (shift)

yylex() § Yacc kaller funksjonen yylex() hver gang den trenger et nytt token (shift) – Denne funksjonen må returnere en int § Returnere et token, f. eks NAME § Returnere ascii-verdien av en karakter: ’+’ 10/19/2021 INF 5110 - 2005 if ( has matched floating point number ) { yylval. real = atof( yytext ); return NUMBER; } INF 3110/4110 - 2004 § Yacc definerer en global variabel yylval som inneholder den semantiske verdien av et symbol (hvis type er definert enten via YYSTYPE eller %union) – yylex() må oppdatere denne ved behov: 11

Semantiske verdier expression(4) 10/19/2021 * INTEGER(2) INF 5110 - 2005 INTEGER(2) INF 3110/4110 -

Semantiske verdier expression(4) 10/19/2021 * INTEGER(2) INF 5110 - 2005 INTEGER(2) INF 3110/4110 - 2004 § Hvert token i en Yacc-grammatikk har både en ”token type” og en semantisk verdi § Ett token som representerer et heltall vil typisk ha typen INTEGER og f. eks den semantiske verdien ’ 42’ § Ikketerminaler har også en semantisk verdi – Eks: i en triviell kalkulator vil ikketerminalen expression ha resultatet av utregningen som semantisk verdi 12

Semantiske verdier(forts) § Typen (i C) av den semantiske verdien er int dersom ikke

Semantiske verdier(forts) § Typen (i C) av den semantiske verdien er int dersom ikke annet er oppgitt § Dersom man bare trenger en type for alle tokens, kan denne endres ved å sette inn #define YYSTYPE ønskettype i prologen: #define YYSTYPE float 10/19/2021 INF 5110 - 2005 %union { Expression* expression; char* text; double real; } INF 3110/4110 - 2004 § Man trenger vanligvis mer enn én type § Bruk direktivet %union i definisjonsseksjonen: 13

Semantiske verdier (forts) § Man må da angi hvilken type skal assosieres med hvert

Semantiske verdier (forts) § Man må da angi hvilken type skal assosieres med hvert symbol § Bruk direktivet %type for ikketerminaler: %type <expression> exp § Bruk %token for terminaler: § Ikke nødvendig med typer for tokens uten en naturlig semantisk verdi – %token<real> ’+’ <- Bare tull § Eksempel: 10/19/2021 exp ’+’ exp | NAME INF 5110 - 2005 exp: INF 3110/4110 - 2004 %token <text> NAME 14

Actions § Inneholder C kode som skal eksekveres når en produksjon matches § Skrives

Actions § Inneholder C kode som skal eksekveres når en produksjon matches § Skrives etter produksjonen – Helst (alltid) i krøllparenteser § Brukes gjerne til å bygge et abstrakt syntakstre (AST) – Men ikke nødvendigvis INF 3110/4110 - 2004 § Enkle kalkulatorer, kommandolinjeparsere INF 5110 - 2005 10/19/2021 15

Pseudovariable § Pseudovariablene $1, $2, $3. . . $n brukes i actions for å

Pseudovariable § Pseudovariablene $1, $2, $3. . . $n brukes i actions for å referere til den semantiske verdien av et token § $$ tilegnes det semantiske resultatet av en action: exp: exp '+' exp { $$ = $1 + $3; } ; exp: NUM { $$ = $1; } ; § Er det samme som exp: NUM; exp: 10/19/2021 NUM {} ; INF 5110 - 2005 § Merk at det ikke er det samme som dette (dette er en bug, idet $$ forblir uinitialisert): INF 3110/4110 - 2004 § Hvis ingen action oppgitt: 16

Pseudovariable (forts) § $$ blir brukt av ”neste” produksjon i grammatikken exp: '+' '-'

Pseudovariable (forts) § $$ blir brukt av ”neste” produksjon i grammatikken exp: '+' '-' '*' '/' exp exp { { { $$ $$ $$ = = = $1; $1 + $1 $1 * $1 / 10/19/2021 [1] [2] [3] [4] [5] INF 5110 - 2005 § For uttrykket 7 * 3 + 21 blir følgende actions utført : – [1], med $1 = 7, $$ <= 7 – [1], med $1 = 3, $$ <= 3 – [4], med $1 = 7, $3 = 3, $$ <= 21 – [1], med $1 = 21, $$ <= 27 – [2], med $1 = 21, $$ <= 42 $3; $3; } } } INF 3110/4110 - 2004 | | NUM exp exp 17

Presedens og assosiativitet § Følgende grammatikk er tvetydig: exp: | | NUM exp exp

Presedens og assosiativitet § Følgende grammatikk er tvetydig: exp: | | NUM exp exp '+' '-' '*' '/' { { { exp exp $$ $$ $$ = = = $3; $3; 4 * 2 3 4 § Litt jobb (del av obligen) – Gi Yacc noen hint om hvordan denne grammatikken skal tolkes 10/19/2021 INF 5110 - 2005 § Yacc genererer 16 shift/reduce konflikter for denne grammatikken § Løsning? – Skriv om grammatikken slik at den er entydig INF 3110/4110 - 2004 2+3*4 + 3 } } } + * 2 $1; $1 + $1 $1 * $1 / 18

Presedens og assosiativitet (forts) § Assosiativitet kan uttrykkes med direktivene %left, %right og %nonassoc:

Presedens og assosiativitet (forts) § Assosiativitet kan uttrykkes med direktivene %left, %right og %nonassoc: – Dette angis i definisjons-seksjonen i stedet for %token § Presedens angis ved rekkefølgen på disse direktivene – Her har altså ’+’ og ’-’ lavest presedens, mens ’^’ har høyest: § %nonassoc betyr at man ikke kan benytte operatoren mer enn én gang: – %nonassoc AND – 4 and 5 and 6 => ulovlig INF 5110 - 2005 § 1 + 2 * 3 ^ 4 => 1 + (2 * (3^4)) INF 3110/4110 - 2004 %token NUM %left '-' '+' %left '*' '/' %right '^' /* exponentiation */ 10/19/2021 19

Parseringstabellen § Dersom man bruker opsjonen –verbose til yacc/bison, får man ut en fil

Parseringstabellen § Dersom man bruker opsjonen –verbose til yacc/bison, får man ut en fil som inneholder parseringstabellen som brukes § Gitt følgende grammatikk: exp: NUM | NUM ’+’ exp ; state 3 NUM shift, and go to state 1 exp go to state 4 $default reduce using rule 2 (exp) state 1 exp -> NUM '+' exp. state 4 -> -> $ go to state 5 shift, and go to state 2 state 5 $default reduce using rule 1 (exp) $ go to state 6 state 2 state 6 exp -> NUM '+'. exp (rule 2) $default accept 10/19/2021 NUM shift, and go to state 1 exp go to state 3 INF 5110 - 2005 '+' NUM. (rule 1) NUM. '+' exp (rule 2) INF 3110/4110 - 2004 state 0 20

Tracing av parseren 10/19/2021 -> INF 5110 - 2005 Reading a token: Next token

Tracing av parseren 10/19/2021 -> INF 5110 - 2005 Reading a token: Next token is 259 (NUM) Shifting token 259 (NUM), Entering state 1 Reading a token: Next token is 43 ('+') Shifting token 43 ('+'), Entering state 2 Reading a token: Next token is 259 (NUM) Shifting token 259 (NUM), Entering state 1 Reading a token: Now at end of input. Reducing via rule 1 (line 10), NUM -> exp state stack now 0 1 2 Entering state 3 Reducing via rule 2 (line 11), NUM '+' exp state stack now 0 Entering state 4 Now at end of input. Shifting token 0 ($), Entering state 5 Now at end of input. INF 3110/4110 - 2004 § Gir deg mulighet til å se hvilke steg Yacc bruker for å parsere § Flere muligheter for å skru det på: – Definer #yydebug i prologen – Bruk opsjonene –t eller –debug – Bruk direktivet %debug i definisjonsseksjonen § Må også sette den globale variabelen yydebug til 1 – F. eks i main() Starting parse § For 1 + 1: Entering state 0 21

Tracing av parseren (forts) INF 5110 - 2005 10/19/2021 -> exp INF 3110/4110 -

Tracing av parseren (forts) INF 5110 - 2005 10/19/2021 -> exp INF 3110/4110 - 2004 Starting parse Entering state 0 Reading a token: Next token is 259 (NUM) Shifting token 259 (NUM), Entering state 1 Reading a token: Next token is 43 ('+') Shifting token 43 ('+'), Entering state 2 Reading a token: Next token is 259 (NUM) Shifting token 259 (NUM), Entering state 1 Reading a token: Now at end of input. Reducing via rule 1 (line 10), NUM -> exp state stack now 0 1 2 Entering state 3 Reducing via rule 2 (line 11), NUM '+' exp state stack now 0 Entering state 4 Now at end of input. Shifting token 0 ($), Entering state 5 Now at end of input. 22

Shift/reduce konflikter § Ta følgende grammatikk: exp: NUM | exp ’+’ exp ; §

Shift/reduce konflikter § Ta følgende grammatikk: exp: NUM | exp ’+’ exp ; § Forteller Yacc at man skal foretrekke en reduce – Gir (2 + 3) + 4 – Gir 2 + (3 + 4) § %nonassoc vil gi error for uttrykket § Yacc foretrekker alltid en shift foran en reduce dersom det er en konflikt 10/19/2021 INF 5110 - 2005 § %right gir en shift INF 3110/4110 - 2004 § Yacc vil her rapportere 1 shift/reduce konflikt – 2 + 3. + 4 <= redusere 2 + 3 til exp eller shifte ’+’? – Kan løses ved å bruke %left ’+’ 23

Output fra bison --verbose State 4 contains 1 shift/reduce conflict. Grammar rule 1 rule

Output fra bison --verbose State 4 contains 1 shift/reduce conflict. Grammar rule 1 rule 2 state 2 exp -> NUM exp -> exp '+' exp -> $ '+' exp (rule 2) go to state 5 shift, and go to state 3 Terminals, with rules where they appear state 3 $ (-1) '+' (43) 2 error (256) a (258) NUM (259) 1 exp -> exp '+'. exp (rule 2) shift, and go to state 1 exp go to state 4 Nonterminals, with rules where they appear exp (6) on left: 1 2, on right: 2 state 4 exp state 0 -> -> exp. '+' exp. (rule 2) NUM shift, and go to state 1 '+' shift, and go to state 3 exp go to state 2 '+' [reduce using rule 2 (exp)] $default reduce using rule 2 (exp) state 5 exp -> NUM. (rule 1) $ $default go to state 6 reduce using rule 1 (exp) INF 5110 - 2005 state 1 INF 3110/4110 - 2004 NUM state 6 $default 10/19/2021 accept 24

Shift/reduce konflikter (forts) § %expect 1 – Yacc vil nå ikke advare om denne

Shift/reduce konflikter (forts) § %expect 1 – Yacc vil nå ikke advare om denne konflikten – Viktig å forsikre seg om at det faktisk er en shift man vil ha 10/19/2021 INF 5110 - 2005 § Men vil advare dersom det er 0 eller flere enn 1 konflikter INF 3110/4110 - 2004 § I noen tilfeller er det enklere å bare godta at grammatikken har shift/reduce konflikter – Dangling else § Yacc foretrekker alltid shift i en S/R-konflikt § Man kan da fortelle Yacc at man vet at grammatikken har så og så mange S/R-konflikter § Direktivet %expect forteller Yacc hvor mange S/R konflikter grammatikken har – Vi vet at grammatikken inneholder én S/R konflikt: 25

Reduce/reduce konflikter § Ta følgende grammatikk: s: x | y ; x: A y:

Reduce/reduce konflikter § Ta følgende grammatikk: s: x | y ; x: A y: A INF 3110/4110 - 2004 § Yacc rapporterer én reduce/reduce konflikt § Bruk flagget –verbose til Yacc INF 5110 - 2005 10/19/2021 26

Output fra bison --verbose state 0 state 4 a shift, and go to state

Output fra bison --verbose state 0 state 4 a shift, and go to state 1 S X Y go to state 4 go to state 2 go to state 3 $ go to state 5 $ go to state 6 state 1 -> -> a. a. (rule 3) (rule 4) $ reduce using rule 3 (X) $ [reduce using rule 4 (Y)] $default reduce using rule 3 (X) state 2 S -> X. -> Y. $default 10/19/2021 accept (rule 1) reduce using rule 1 (S) state 3 S $default (rule 2) reduce using rule 2 (S) INF 5110 - 2005 $default state 6 INF 3110/4110 - 2004 X Y 27

Locations first_line; first_column; last_line; § Kan omdefineres – Sjelden nødvendig INF 5110 - 2005

Locations first_line; first_column; last_line; § Kan omdefineres – Sjelden nødvendig INF 5110 - 2005 struct { int int } yylloc; INF 3110/4110 - 2004 § Ofte et behov for å holde styr på hvor i input-fila man befinner seg – Feilmeldinger etc. . . § Yacc definerer en global variabel yylloc som holdes ajour av lexeren – Lex gjør dette automatisk. – Dersom du har en håndskrevet lexer, må du oppdatere denne manuelt § Forhåndsdefinert som en struct som ser slik ut: 10/19/2021 28

Locations(forts) § Den gjeldende lokasjon for ett token er tilgjengelig fra en action med

Locations(forts) § Den gjeldende lokasjon for ett token er tilgjengelig fra en action med pseudovariablene @1, @2, etc. § @S angir lokasjonen for en gruppering av tokens – Tilsvarer $$ § Standard regel for lokasjoner: 10/19/2021 INF 5110 - 2005 § Kan omdefineres – Sjelden nødvendig i praksis – standard regel gjør det du trenger INF 3110/4110 - 2004 term: tok 1 tok 2 tok 3. . . tokn { @S. first_line = @1. first_line; @s. first_column = @1. first_column; @s. last_line = @n. last_line; @s. last_column = @n. last_line; } ; 29

Bruk av yacc med lex § Lex (flex) ble skrevet for å være kompatibel

Bruk av yacc med lex § Lex (flex) ble skrevet for å være kompatibel med yacc § Lex definerer yylex() § Man vil helst unngå å definere de samme konstantene for tokens både i lex -fila og i yacc-fila – Løsning: Bruk opsjonen –d til Yacc %token OR AND NOT LT LTEQ GT GTEQ NOTEQ EQ § I lexer. l: ”&&" ”!=" 10/19/2021 { return AND; } { return NOTEQ; } INF 5110 - 2005 %{ #include ”y. tab. h” %} INF 3110/4110 - 2004 § Genererer en headerfil med #defines for alle tokens i yacc-fila § I parser. y: 30

Praktisk bruk av Yacc INF 5110 - 2005 10/19/2021 INF 3110/4110 - 2004 §

Praktisk bruk av Yacc INF 5110 - 2005 10/19/2021 INF 3110/4110 - 2004 § Definer en node som en struct i C § Bruk actions for å bygge et abstrakt syntakstre, bestående av disse nodene § Skriv funksjoner som traverserer dette treet etter at Yacc er ferdig og utfører de forskjellige operasjonene – Semantisk sjekk – Kodegenerering – Etc. § I objektorienterte språk, definer nodetypene som et hierarki av klasser – If. Statement. Node – Binary. Expression. Node – Etc § Visitor pattern (Go. F)? 31

Praktisk bruk av Yacc (forts) § Unix: – Sett opp regler i makefila: lexer.

Praktisk bruk av Yacc (forts) § Unix: – Sett opp regler i makefila: lexer. c: lexer. l parser. c flex –o $@ $< § bison -d -o$(Input. Name). cpp --verbose $(Input. File. Name) § flex -o$(Input. Name). cpp $(Input. File. Name) 10/19/2021 INF 5110 - 2005 § Windows (VC++) – Sett opp”Custom Build Step” for lexer. l og yacc. y – Output settes til lexer. c(pp) og parser. c(pp) – Kommandolinjer: INF 3110/4110 - 2004 parser. c: parser. y bison –d -o $@ $< 32

Output INF 3110/4110 - 2004 § Yacc genererer en C fil § C-koden implementerer

Output INF 3110/4110 - 2004 § Yacc genererer en C fil § C-koden implementerer en tabell-drevet LALR(1) parser – GLR § Stygg kode – Trenger heldigvis ikke modifisere denne selv § Må kompileres og linkes sammen med resten av kompilatoren INF 5110 - 2005 10/19/2021 33

Feilhåndtering § Funksjonen yyerror() blir kalt dersom Yacc finner en parseringsfeil: § Må defineres

Feilhåndtering § Funksjonen yyerror() blir kalt dersom Yacc finner en parseringsfeil: § Må defineres av brukeren: § Gir ut festlige feilmeldinger som ”Parse error” § Hvis du ikke gjør noe annet, vil yacc stoppe med en gang den finner en feil INF 3110/4110 - 2004 void yyerror (char const *s) { printf ("%sn", s); } INF 5110 - 2005 10/19/2021 34

Feilhåndtering (forts) § Kan bruke den spesielle terminalen error for å hente seg inn

Feilhåndtering (forts) § Kan bruke den spesielle terminalen error for å hente seg inn igjen etter en feil exp: NUM | NUM ’+’ exp ; exp: NUM | NUM ’+’ exp | error exp; 10/19/2021 INF 5110 - 2005 § Yacc vil fortsatt rapportere feil, men vil hente seg inn og fortsette parseringen INF 3110/4110 - 2004 § Med input ”+1+1” vil Yacc gi opp etter den første ’+’ § Vi utvider grammatikken litt: 35

GLR(bison) INF 3110/4110 - 2004 § Bison støtter en modus kalt Generalized LR –

GLR(bison) INF 3110/4110 - 2004 § Bison støtter en modus kalt Generalized LR – Skrus på med direktivet %glr-parser § Håndterer tvetydige grammatikker § Dersom shift/reduce konflikt: – Splitter parseren i to, forsøker begge løsninger – Fortsetter til en må forkastes INF 5110 - 2005 10/19/2021 36

Alternativer til Yacc (og Lex) INF 5110 - 2005 10/19/2021 INF 3110/4110 - 2004

Alternativer til Yacc (og Lex) INF 5110 - 2005 10/19/2021 INF 3110/4110 - 2004 § ANTLR(ANother Tool for Languate Recognition) – Parsere for C#, C++, Python og Java – Genererer en recursive descent parser § Jay – Port av yacc til Java (og C#) – Anbefales dersom man vil skrive oblig i ett av disse språkene, siden denne er mest lik Yacc § Coco/R – Støtter C#, Java, Oberon og en hel masse andre språk – Recursive descent – Aksepterer LL(k) grammatikker for en vilkårlig k (!) 37