67
1/25/16, 2:49 PM Compiladores: Yacc - (c)2014 LSUB Page 1 of 67 http://127.0.0.1:3999/s07.yacc.slide#1 Compiladores: Yacc Francisco J Ballesteros LSUB, URJC

Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 1 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Compiladores: YaccFrancisco J BallesterosLSUB, URJC

Page 2: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 2 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Yacc

Es un compilador de compiladores

yet another compiler compiler

Genera parsers LALR para gramáticas adecuadas

Disponible en casi todos los sistemas

En C, en Limbo, en Go, etc.

Ver Yacc: A parser generator Stephen C. Johnson y Ravi Sethi

Ver tambien

Yacc: Yet Another Compiler-Compiler (http://dinosaur.compilertools.net/yacc/)

Page 3: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 3 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Yacc en Go

Basta ejecutar:

term% go tool yaccusage: yacc [-o output] [-v parsetable] inputterm%

O, haciendo un script...

term% gaccusage: yacc [-o output] [-v parsetable] inputterm%

Page 4: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 4 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Yacc

El fuente para yacc es un fichero xxx.y con formato

/* declaraciones para yacc */%{ ... declaraciones en Go ...%}... mas declaraciones para yacc ...%%expr : expr '+' expr | expr '-' expr

term : id | '(' expr ')'

... mas reglas en BNF ...

%%

... codigo en Go ...

Page 5: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 5 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Yacc

...declaraciones...%%...reglas BNF de la gramática...%%...código para el compilador...

Las declaraciones definen tokens, etc.

Las que van entre %{ y %} son declaraciones en Go

La gramática son reglas en BNF (formateadas a gusto del autor)

El código se escribe en Go.

En el yacc para C se genera C y se usa C, no Go.

Page 6: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 6 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Yacc

A partir del fich.y yacc genera un fichero fuente en Go

Como Go permite definir items después de usarlos, el orden da un poco igual.

Pero no ocurre así en C.

Page 7: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 7 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Declaraciones

Normalmente incluyen declaraciones iniciales para el fuente...

/* Evaluador de expresiones simples */

%{

// +build ignore

package main

import ( "io" "os" "strconv" "fmt" "unicode" "bufio")

%}

Page 8: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 8 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Declaraciones

y definiciones de tokens, lexemas y atributos

/* tipo de datos para atributos de simbolos de la gramatica */%union { num float64 name string}

/* tokens */%token '('%token ')'%token '\n'%token <num> NUM PI /* su valor es float64 */%token <name> FN /* su valor es string */

/* tokens para operadores, de menor a mayor precedencia * y con asociatividad indicada (left, right, unary) */%left '+' '-'%left '*' '/'

%%

Page 9: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 9 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Tokens

Un token es un int

Si definimos

%token '('

El (identificador del) token vale '('

Si definimos

%token NUM

Yacc crea una constante NUM para el id del token.

Si definimos

%token <num> NUM

Decimos que el lexema vale yySymVal.num, esto es, float64

Page 10: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 10 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Tokens

%union { num float64 name string}

%token '('%token ')'%token '\n'%token <num> NUM PI%token <name> FN

¿Más claro ahora?

Page 11: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 11 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Tokens

Cuando los tokens son operadores y queremos definir su precedencia podemos utilizar

%left '+'

para un operador binario asociado a la izquierda

%right ARROW

para un operador binario asociado a la derecha

%unary UMINUS

para un operador unario

Su precedencia es menor si se declaran antes

%left '+' '-'%left '*' '/'

Page 12: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 12 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Atributos y símbolos

Cada símbolo tiene un valor definido en la unión

%union { num float64 name string}

Según la declaración de token o la declaración de tipo para el no-terminal que hagamos:

%type <num> expr call

indica que los no-terminales expr y call son yySymVal.num

Page 13: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 13 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Símbolo inicial

La definición

%start prog

indica que prog es el símbolo inicial de la gramática

Si no la indicamos, es el primero en la gramática

Page 14: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 14 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Gramática

La gramática se define en BNF.

Para

A ::= B | C | <empty>

podemos escribir

A : B | C | /* empty */ ;

Page 15: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 15 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Ejemplo de gramática

lines : line | lines line ;

line : expr '\n' | '\n' ;

expr : expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | '(' expr ')' | NUM | PI | FN '(' expr ')' ;

Page 16: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 16 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Ejemplo de gramática

Mejor que no sea recursiva por la derecha!

lines : line | lines line ;

line : expr '\n' | '\n' ;

La entrada tiene en este caso líneas con una expresión por línea (o líneas vacías).

Nuestro lex tendrá que darnos el token '\n' en este ejemplo

Page 17: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 17 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Ejemplo de gramática

expr : expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | '(' expr ')' | NUM | PI | FN '(' expr ')' ;

La gramática para expresiones es ambigua, pero las declaraciones de precedencia lo resuelven.

%left '+' '-'%left '*' '/'

Page 18: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 18 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Acciones

Para, por ejemplo, pasar de notación infija a postfija:

%%lines : line | lines line ;

line : expr '\n' { fmt.Printf("\n") } | '\n' ;

expr : expr '+' expr { fmt.Printf(" +") } | expr '-' expr { fmt.Printf(" -") } | expr '*' expr { fmt.Printf(" *") } | expr '/' expr { fmt.Printf(" /") } | '(' expr ')' { } | NUM { fmt.Printf(" %v", $1) } | PI { fmt.Printf(" pi") } | FN '(' expr ')' { fmt.Printf(" %s\n", $1) } ;%%

Page 19: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 19 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Acciones

Y con esta gramática:

term% gacc -p Expr expr.yterm% go run y.go3 + 4 * pi 3 4 pi * +2 2

La opción -p Expr hace que se use ExprSymVal en lugar de yySymVal

Page 20: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 20 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Código

Tras el último %% escribimos normalmente el programa principal y a menudo el código del scanner.

Por ejemplo, este es el que hemos utilizado en el traductor a postfija:

func main() { debuglex = false txt := &bufsrc{in: bufio.NewReader(os.Stdin)} l := NewLex(txt, "stdin")

ExprParse(l) os.Exit(nerrors);}

Page 21: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 21 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Código

La llamada

yyParse(l)

ejecuta el parser

El argumento ha de implementar

type yyLex interface { Lex(lval *yySymType) int Error(e string)}

y es el scanner.

Con el flag -p Expr usamos ExprParse, ExprLex y ExprSymType

Page 22: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 22 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

func main() { debuglex = false txt := &bufsrc{in: bufio.NewReader(os.Stdin)} l := NewLex(txt, "stdin")

ExprParse(l) os.Exit(nerrors);}

Page 23: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 23 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

type Text interface { Get() (rune, error) Unget() error}

type bufsrc struct { in io.RuneScanner}

func (s *bufsrc) Get() (rune, error) { r, _, err := s.in.ReadRune() return r, err}

func (s *bufsrc) Unget() error { return s.in.UnreadRune()}

Page 24: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 24 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

type builtin struct { tok int num float64}var builtins = map[string]builtin{ "pi": builtin{tok: PI, num: 3.1415926}, "abs": builtin{tok: FN},}

var file stringvar line intvar debuglex boolvar nerrors int

Page 25: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 25 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

type ExprLex interface { Lex(lval *ExprSymType) int Error(e string)}

type lex struct { in Text val []rune}

func NewLex(t Text, fname string) *lex { file = fname line = 1 return &lex{in: t}}

Page 26: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 26 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

func (l *lex) got(r rune) { l.val = append(l.val, r)}

func (l *lex) getval() string { return string(l.val)}

Page 27: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 27 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

func (l *lex) skipBlanks() error { for { c, err := l.in.Get() if err != nil { return err } if c == '#' { for c != '\n' { if c, err = l.in.Get(); err != nil { return err } } if c == '\n' { line++ } } if c == '\n' { line++ } if c != ' ' && c != '\t' { l.in.Unget() return nil } }}

Page 28: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 28 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

func Errorf(s string, v ...interface{}) { fmt.Printf("%s:%d: ", file, line) fmt.Printf(s, v...) fmt.Printf("\n")

nerrors++ if nerrors > 5 { fmt.Printf("too many errors\n") os.Exit(1) }}

func (l *lex) Error(s string) { Errorf("%s near '%s'", s, l.getval())}

Page 29: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 29 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

func (l *lex) Lex(lval *ExprSymType) (tid int) { if debuglex { defer func() { fmt.Printf("tok %s\n", tname(tid, lval)) }() } l.val = nil if err := l.skipBlanks(); err != nil { if err != io.EOF { Errorf("%s", err) } return 0 } c, err := l.in.Get() if err != nil { Errorf("%s", err) return 0 } l.got(c) switch {

...

Page 30: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 30 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

func (l *lex) Lex(lval *ExprSymType) (tid int) {

...

switch { case c == '\n' || c == '+' || c == '*' || c == '/' || c == '(' || c == ')': lval.name = l.getval() return int(c) case c == '-': n, _ := l.in.Get() l.in.Unget() if n < '0' || n > '9' { return '-' } fallthrough

...

Page 31: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 31 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

case c >= '0' && c <= '9': for { c, err := l.in.Get() if err != nil { Errorf("%s", err) return 0 } if c != '-' && c != 'e' && c != '+' && c != '.' && !unicode.IsNumber(c) { l.in.Unget() break } l.got(c) } // id,kw lval.name = l.getval() n, err := strconv.ParseFloat(lval.name, 64) if err != nil { Errorf("%s", err) return 0 } lval.num = n return NUM

Page 32: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 32 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

case unicode.IsLetter(c): for { c, err := l.in.Get() if err != nil { Errorf("%s", err) return 0 } if !unicode.IsLetter(c) && !unicode.IsNumber(c) { l.in.Unget() break } l.got(c) } // id,kw lval.name = l.getval() b, ok := builtins[lval.name] if !ok { Errorf("unknown name '%s'", lval.name) return 0 } lval.num = b.num return b.tok } Errorf("wrong input at char %c", c) return 0}

Page 33: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 33 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Lex para yacc

func main() { debuglex = false txt := &bufsrc{in: bufio.NewReader(os.Stdin)} l := NewLex(txt, "stdin")

ExprParse(l) os.Exit(nerrors);}

Page 34: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 34 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Normalmente se usa una global nerrors

Y la usaremos para abortar tras varios errores

El parser llama al método Error del scanner en errores sintácticos:

func (l *lex) Error(s string) { Errorf("%s near '%s'", s, l.getval())}

Y luego hace lo que puede por recuperarse...

En C llama a yyerror y yacc mantiene yynerrs.

Page 35: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 35 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Salida de Yacc

La salida es

El fuente en Go para el parser

Un fichero y.output con información del parser

Page 36: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 36 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Salida de Yacc

Para

%token num%left '+'%left '*'

%%

expr : expr '+' expr | expr '*' expr | num

%%

Page 37: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 37 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Salida de Yacc

Tenemos un y.output como sigue

state 0 $accept: .expr $end

num shift 2 . error

expr goto 1

state 1 $accept: expr.$end expr: expr.+ expr expr: expr.* expr

$end accept + shift 3 * shift 4 . error

Page 38: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 38 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Salida de Yacc

state 2 expr: num. (3)

. reduce 3 (src line 8)

state 3 expr: expr +.expr

num shift 2 . error

expr goto 5

Page 39: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 39 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Salida de Yacc

state 4 expr: expr *.expr

num shift 2 . error

expr goto 6

state 5 expr: expr.+ expr expr: expr + expr. (1) expr: expr.* expr

* shift 4 . reduce 1 (src line 8)

Page 40: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 40 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Salida de Yacc

state 6 expr: expr.+ expr expr: expr.* expr expr: expr * expr. (2)

. reduce 2 (src line 8)

6 terminals, 2 nonterminals4 grammar rules, 7/2000 states0 shift/reduce, 0 reduce/reduce conflicts reported51 working sets usedmemory: parser 2/300000 extra closures6 shift entries, 1 exceptions3 goto entries0 entries saved by goto defaultOptimizer space used: output 9/300009 table entries, 2 zeromaximum spread: 6, maximum offset: 6

Page 41: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 41 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Conflictos

Shift/reduce

A veces los buscamos (se hará un shift)

Reduce/reduce

La hemos liado (normalmente)

Pero se usa la primera encontrada en el estado

Hay que ver y.output

Page 42: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 42 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Atributos

Cada símbolo tiene un valor

definido por la declaración dada a Yacc

En una regla de la forma

A: B C { ....} X Y

Podemos utilizar en la acción

$$: Valor de A

$1: Valor de B

$2: Valor de C

$4: Valor de X

$5: Valor de Y

Page 43: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 43 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Calcular expresiones

Si incluimos las definiciones

%union { num float64 name string}

%token '('%token ')'%token '\n'%token <num> NUM PI%token <name> FN

%left '+' '-'%left '*' '/'

%type <num> expr

Page 44: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 44 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Calcular expresiones

lines : line | lines line ;

line : expr '\n' { fmt.Printf("%v\n", $1) } | '\n' ;

expr : expr '+' expr { $$ = $1 + $3 } | expr '-' expr { $$ = $1 - $3 } | expr '*' expr { $$ = $1 * $3 } | expr '/' expr { $$ = $1 / $3 } | '(' expr ')' { $$ = $2 } | NUM | PI /* by default: {$$ = $1} */ ;

Page 45: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 45 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Calcular expresiones

term% gacc -p Expr expr2.yterm% go run y.go1 + 2 * pi7.2831852

Page 46: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 46 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Atributos

Como definimos los valores a partir de los hijos

los denominamos atributos sintetizados

Page 47: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 47 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Acciones y gramática

La introducción de acciones equivale a introducir nuevos símbolos

Y modifica la gramática

A: B {...} C

No es lo mismo que

A: B C {...}

Page 48: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 48 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Acciones y gramática

A: B {...} C

Equivale a

A: B TEMP CTEMP: /* empty */ { ... }

Page 49: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 49 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Acciones y gramática

A: B { $$ = 1 } C { $$ = $2 + 2 }

Hace que el valor de A sea 3.

A: B TEMP C { $$ = $2 + 2 }TEMP: /* empty */ { $$ = 1 }

Page 50: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 50 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Debug

Podemos darle un valor a la global yyDebug

O ExprDebug si usamos el flag de yacc -p Expr

term% go run y.go3 + 253 +reduce 10 in: state-6stdin:2: syntax error near ''state-10saw

error recovery pops state 10error recovery pops state 3error recovery pops state 0exit status 1

Esto es para su valor 2

Page 51: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 51 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Debug

ExprDebug = 3

nos da

term% go run y.go3 + 3lex U+E002 NUMreduce 10 in: state-6lex U+002B +lex U+E002 NUMreduce 10 in: state-6lex U+000A

reduce 5 in: state-15reduce 3 in: state-96reduce 1 in: state-2lex U+0000 tok-1

Page 52: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 52 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Tomemos de nuevo

lines : line | lines line ;

line : expr '\n' { fmt.Printf("%v\n", $1) } | '\n' ;

expr : expr '+' expr { $$ = $1 + $3 } | expr '-' expr { $$ = $1 - $3 } | expr '*' expr { $$ = $1 * $3 } | expr '/' expr { $$ = $1 / $3 } | '(' expr ')' { $$ = $2 } | NUM | PI /* by default: {$$ = $1} */ ;

Page 53: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 53 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Y con esta entrada...

term% gacc -p Expr expr3.yterm% go run y.go3 + 2 *stdin:1: syntax error near '\n'exit status 1term%

en la primera línea con error dejamos de compilar!

Page 54: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 54 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Pero podemos modificar la gramática usando:

lines : line | lines line ;

line : expr '\n' { fmt.Printf("%v\n", $1) } | error \n | '\n' ;

Y ahora tenemos:

term% go run y.go3 + 2 *stdin:1: syntax error near '\n'2 + 24

Page 55: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 55 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

El símbolo error

está predefinido en la gramática

equivale a un error sintáctico

yacc puede reducir el error a error si tiene problemas

Con la producción hemos

dado la línea por zanjada

y la gramática sigue evaluando las líneas siguientes

Page 56: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 56 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Veámoslo con yyDebug=2 (o ExprDebug)

term% go run y.go3 +reduce 11 in: state-7stdin:1: syntax error near '\n'state-11saw

error recovery pops state 11error recovery pops state 3reduce 4 in: state-15reduce 1 in: state-2

Page 57: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 57 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

stdin:1: syntax error near '\n'state-11saw

error recovery pops state 11

Y de y.output:

state 11 expr: expr +.expr

( shift 6 NUM shift 7 PI shift 8 . error

expr goto 17

No había expresión tras el +

Page 58: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 58 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Y sigue con...

error recovery pops state 3

Y de y.output:

state 3 line: expr.\n expr: expr.+ expr expr: expr.- expr expr: expr.* expr expr: expr./ expr

\n shift 10 + shift 11 - shift 12 * shift 13 / shift 14 . error

Page 59: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 59 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Y sigue con...

reduce 4 in: state-15

Y de y.output:

state 15 line: error \n. (4)

. reduce 4 (src line 48)

El error ha podido reducirse por la nueva producción, y el análisis sigue...

Page 60: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 60 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Veamos con esta otra...

lines : line | lines line ;

line : expr '\n' { if nerrors == 0 { fmt.Printf("%v\n", $1) } } | error '\n' { Errorf("wrong expression") } | '\n' ;

expr : expr '+' expr { $$ = $1 + $3 } | expr '+' error { Errorf("operand expected after '+'") } | expr '-' expr { $$ = $1 - $3 } | expr '*' expr { $$ = $1 * $3 } | expr '/' expr { $$ = $1 / $3 } | '(' expr ')' { $$ = $2 } | NUM | PI /* by default: {$$ = $1} */ ;

Page 61: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 61 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Ahora tenemos...

term% go run y.go3 +stdin:1: syntax error near '\n'stdin:1: operand expected after '+'

Con yacc es muy difícil dar buenos errores.

aumentamos la gramática con errores sintácticos

Y nos sincronizamos en algún signo de puntuación

Pero habrá errores en cascada

Al final hay que evitar producir salida si hay errores

Page 62: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 62 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Cuándo acaba un error y empieza otro?

Otro error:

term% go run y.go3 + +stdin:1: syntax error near '+'stdin:1: operand expected after '+'stdin:2: operand expected after '+'

Page 63: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 63 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Cuándo acaba un error y empieza otro?

Ahora con...

lines : line | lines line ;

line : expr '\n' { if nerrors == 0 { fmt.Printf("%v\n", $1) } } | error '\n' { Errorf("wrong expression"); Errflag = 0 } | '\n' ;

expr : expr '+' expr { $$ = $1 + $3 } | expr '+' error { Errorf("operand expected after '+'"); Errflag = 0 } | expr '-' expr { $$ = $1 - $3 } | expr '*' expr { $$ = $1 * $3 } | expr '/' expr { $$ = $1 / $3 } | '(' expr ')' { $$ = $2 } | NUM | PI /* by default: {$$ = $1} */ ;

Page 64: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 64 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Cuándo acaba un error y empieza otro?

Errflag = 0

le dice a Yacc que considere el error por zanjado.

En lugar de recuperarse llamará de nuevo a yyError

En este caso es peor usarlo, otras veces no

term% go run y.go3 + +stdin:1: syntax error near '+'stdin:1: operand expected after '+'stdin:2: syntax error near '\n'stdin:2: operand expected after '+'too many errors

Page 65: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 65 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

A veces no son sintácticos...

expr : expr '+' expr { $$ = $1 + $3 } | expr '-' expr { $$ = $1 - $3 } | expr '*' expr { $$ = $1 * $3 } | expr '/' expr { if $3 == 0.0 { Errorf("divide by 0") $$ = 0 } else { $$ = $1 / $3 } } | '(' expr ')' { $$ = $2 } | NUM | PI /* by default: {$$ = $1} */ ;

Page 66: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 66 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Errores

Con lo que tenemos...

term% go run y.go3 / 0stdin:0: divide by 0

Page 67: Compiladores: Yacc - (c)2014 LSUBlsub.org/comp/slides/s07.yacc.pdf · Compiladores: Yacc - (c)2014 LSUB 1/25/16, 2:49 PM Page 18 of 67 Acciones Para, por ejemplo, pasar de notación

1/25/16, 2:49 PMCompiladores: Yacc - (c)2014 LSUB

Page 67 of 67http://127.0.0.1:3999/s07.yacc.slide#1

Questions?

Francisco J BallesterosLSUB, URJChttp://lsub.org (http://lsub.org)