Compiladores: Símbolos y ámbitos - LSUBlsub.org/comp/slides/s09.symbol.pdf · 2016-01-25 ·...
Transcript of Compiladores: Símbolos y ámbitos - LSUBlsub.org/comp/slides/s09.symbol.pdf · 2016-01-25 ·...
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 1 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Compiladores: Símbolos y ámbitosFrancisco J BallesterosLSUB, URJC
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 2 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Símbolos y ámbitos
En el lenguaje podemos tener
vars: a: int;procedure foo(a: int, b:int ) a: int;{}
Y tenemos que
saber qué es cada nombre
gestionar el ámbito en el que vive
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 3 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Símbolos y ámbitos
Tenemos un ámbito global
con nombres globales definidos
incluyendo nombres de procedimientos, funciones y tipos
Y dentro otro para cada procedimiento
Y dentro otro para las variables
Y puede que otros, mas anidados si el lenguaje lo permite
Se comportan como una pila
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 4 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Ámbitos
Hacen falta al compilar para saber qué es cada nombre
Y hará falta gestionarlos en tiempo de ejecución
normalmente con la pila utilizada para ejecutar el programa
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 5 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Tabla de Símbolos
Tendremos una pila de tablas (una por ámbito)
Cada una es una hash del nombre a los atributos del símbolo
type Skind int
const ( Snone Skind = iota Skey // keyword Stype // type name Sconst // constant name Svar // variable or parameter name Sproc // procedure name Sfunc // function name)
type Sym struct { name string // symbol name kind Skind // keyword, constant, var name, ... id int // token id
file string // where declared line int // where declared}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 6 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Tabla de Símbolos
Un buen punto de partida es
definir los keywords en una tabla
definir los tipos predefinidos en una tabla
igual para constantes, variables, procedimientos y funciones
Recorrerlos y definir símbolos para todos ellos
bltin := make(map[string]*Sym, 101)env = []map[string]*Sym{bltin}
for i := range keywords { bltin[keywords[i].name] = &keywords[i] keywords[i].kind = Skey keywords[i].file = "builtin"}...pushEnv() // top-level
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 7 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Tabla de Símbolos
El primer entorno (ámbito) en la pila tiene elementos predefinidos
No vamos a dejar redefinirlos en ningún programa
Nos ayuda a simplificar la gramática
Ahora el scanner tiene que mirar la tabla de símbolos
Devolver ID para nombres (predefinidos o no)
Devolver TYPEID para nombres de tipos (predefinidos o no)
Igual para literales con nombre (incluyendo por ej. True)
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 8 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Tabla de Símbolos
Utilizaremos estas funciones para abrir y cerrar ámbitos
func pushEnv() { env := map[string]*Sym{} envs = append(envs, env)}
func popEnv() { if len(envs) == 1 { panic("bug: attempt to pop builtin env") } envs = envs[:len(envs)-1]}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 9 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Tabla de Símbolos
Utilizaremos estas funciones para buscar y definir símbolos
func getbuiltin(n string) *Sym { if s, ok := envs[0][n]; ok { return s } return nil}
func getsym(n string) *Sym { for i := len(envs)-1; i >= 0; i-- { if s, ok := envs[0][n]; ok { return s } } return nil}
func defsym(s *Sym) { envs[len(envs)-1][s.name] = s}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 10 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Literales
Hay literales con nombre y valor de tipos distintos Vamos a dividir LIT entre BOOL, INT, ...
%token <ival> INT%token <bval> BOOL%token <rval> FLOAT%token <cval> CHAR%token <sval> STR%token <sym> ID TYPEID
Y a definir
%union { sym *Sym ival int rval float64 bval bool cval rune sval string}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 11 of 40http://127.0.0.1:3999/s09.symbol.slide#1
El punto de partida
tabla de símbolos inicial (src/lang/dat.go)
scanner (src/lang/lex.go)
parser (src/lang/lang2.y)
entrada de prueba (src/lang/f.p)
salida (src/lang/f.out)
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 12 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Antes de probar el parser
Necesitamos que los nombres de tipos definidos sean tokens TYPEID y no ID
Vamos a poner acciones para definir al menos los tipos y podremos probar el parser
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 13 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Definiciones
typedef : ID '=' type ';' { $1.kind = Stype $1.id = TYPEID defsym($1) } | TYPEID '=' type ';' ;
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 14 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Pruebas
func main() { os.Args[0] = "pick" flag.Usage = usage flag.Parse() initenv() args := flag.Args() if len(args) != 1 { usage() }
l, err := newFileLex(args[0]) if err != nil { Fatal("%s: %s", args[0], err) } debugLex = true yyParse(l) os.Exit(nerrors)}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 15 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Pruebas
tabla de símbolos (src/lang/dat.go)
scanner (src/lang/lex.go)
parser (src/lang/lang3.y)
entrada de prueba (src/lang/f.p)
salida (src/lang/f.out2)
Normalmente habríamos hecho
1. el scanner 2. la tabla de símbolos 3. la gramática, poco a poco y probándola con entradas
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 16 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Producciones de error
Para tolerar algunos errores vamos a poner producciones de error en algunos puntos
Luego habrá que mejorarlas
parser con errores iniciales (src/lang/lang4.y)
tabla de símbolos con debug flag (src/lang/dat2.go)
scanner (src/lang/lex.go)
entrada de prueba con errores (src/lang/ferr.p)
salida con errores (src/lang/f.out3)
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 17 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Definiciones y ámbitos
Para procesar definiciones:
llamar a pushEnv al abrir cada ámbito
llamar a popEnv al cerrarlo
incluso si hay errores sintáticos!
llamar a defXXX() para definir los nuevos símbolos
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 18 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Definiciones y ámbitos
Al entrar...
prochdr : PROCEDURE ID '(' optparms ')' { defproc($2) pushEnv($2.name) } | PROCEDURE error { pushEnv("proc") Errorf("bad procedure header") } ;
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 19 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Definiciones y ámbitos
Al salir...
procdef : prochdr ';' { popEnv() } | prochdr optvars body { popEnv() } | prochdr error body { popEnv() }
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 20 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Definiciones y ámbitos
Constantes
constdef : ID '=' expr ';' { defconst($1) } | error ';' { Errorf("bad constant declaration") Errflag = 0 } ;
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 21 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Definiciones y ámbitos
Tipos
typedef : ID '=' type ';' { deftype($1) } | TYPEID '=' type ';' | error ';' { Errorf("bad type declaration") Errflag = 0 } ;
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 22 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Definiciones y ámbitos
Variables (locales y globales)
vardef : ID ':' TYPEID ';' { defvar($1) } | error ';' { Errorf("bad variable declaration") Errflag = 0 } ;
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 23 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Definiciones y ámbitos
Con nuevos auxiliares para definir símbolos concretos...
func deftype(s *Sym) { s.kind = Stype s.id = TYPEID defsym(s)}
func defvar(s *Sym) { s.kind = Svar s.id = ID defsym(s)}
func defconst(s *Sym) { s.kind = Sconst s.id = ID defsym(s)}...
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 24 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Definiciones y ámbitos
parser con (algunas) declaraciones (src/lang/lang5.y)
tabla de símbolos mejorada (src/lang/dat2.go)
scanner (src/lang/lex.go)
entrada de prueba (src/lang/ferr.p)
salida (src/lang/f.out4)
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 25 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST
Hay que definir
los campos que tiene cada record
los parámetros de cada procedimiento/función
etc
Necesitamos construir trozos del árbol de parsing
En realidad, un árbol sintáctico abstracto (AST) decorado
Y utilizar luego esos árboles para el proceso
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 26 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST: Expresiones
Para cada nodo de interés vamos a utilizar
type Nd struct { op int sym *Sym ival int rval float64 sval string bval bool cval rune args []*Nd file string // where declared line int // where declared}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 27 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST: Expresiones
Y declaramos tipos para los no terminales
%union { sym *Sym ival int rval float64 bval bool cval rune sval string nd *Nd lst []*Nd}
%type <nd> lvalue literal primary expr caseexpr forcond parm field fieldcase%type <lst> args optargs parms optparms fields optfields ids fieldcases%type <bval> optref
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 28 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST: Expresiones
Ahora hay que construir los nodos
lvalue : ID { $$ = newnd(ID, $1) } | lvalue '[' expr ']' { $$ = newnd('[', nil, $1, $3) } | lvalue '.' ID { nd := newnd(ID, $3) $$ = newnd('.', nil, $1, nd) } | lvalue '^' { $$ = newnd('^', nil, $1) } ;
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 29 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST: Expresiones
Intentando aproximar su fichero y línea
func newnd(op int, sym *Sym, args ...*Nd) *Nd { nd := &Nd{op: op, sym: sym, args: args} if sym != nil { nd.file = sym.file nd.line = sym.line } else if len(args) > 1 { nd.file = args[0].file nd.line = args[0].line } else { nd.file = file nd.line = line } return nd}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 30 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST: Expresiones
Y las listas
optargs : args | { $$ = nil } ;
args : args ',' expr { $$ = append($1, $3) } | expr { $$ = []*Nd{$1} } ;
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 31 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST: Expresiones
Para los símbolos resulta interesante incluir
un nodo como valor
un símbolo para el tipo (para declaraciones, por ej.)
type Sym struct { name string // symbol name kind Skind // keyword, constant, var name, ... id int // token id
val *Nd tnd *Sym
file string // where declared line int // where declared
}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 32 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST: Expresiones
Continuamos y hacemos lo mismo con todo lo necesario
Incluyendo un nuevo flag para volcar nodos
Así podemos ver el AST como en
const = const<Maxword>{ val int<30>{ }}
type = type<Tindchar>{ val range<int>{ sym type<int> arg int<1>{ } arg id<Maxword>{ sym const<Maxword> } }}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 33 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST: tokens falsos
Como hemos utilizado los tokens como tipo para los nodos
Tenemos que definir algunos tokens falsos
la alternativa es un nuevo enumerado
con nuevas funciones de depuración
pero muchos de los tokens tienen nodos
%token CALL PARMS PARM%token ORD RANGE
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 34 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST
Esto nos deja este resultado
parser con nodos del AST (src/lang/lang7.y)
nueva tabla de símbolos (src/lang/dat5.go)
AST (src/lang/nd.go)
lex con strings to tokens para nodos (src/lang/lex2.go)
entrada de prueba (src/lang/f2.p)
salida (src/lang/f.out5)
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 35 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST Cntd.
Tendremos que hacer lo mismo para generar código con las sentencias y estructuras de control.
podemos aumentar los tipos de nodos
o definir otro tipo de árbol para sentencias
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 36 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST Cntd.
Por ejemplo
stmt : lvalue '=' expr ';' { $$ = newnd('=', nil, $1, $3) } | ID '(' optargs ')' ';' { $$ = newnd(CALL, $1, $3...) } | body ...
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 37 of 40http://127.0.0.1:3999/s09.symbol.slide#1
AST Cntd.
Y tendremos para
{ writeln(nc(max));}
este AST
main body = {}{ arg call<writeln>{ sym proc<writeln> arg call<nc>{ sym func<nc> arg id<max>{ sym var<max> } } }}
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 38 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Fuente con el AST
parser con nodos del AST (src/lang/lang8.y)
tabla de símbolos (src/lang/dat5.go)
AST (src/lang/nd.go)
scanner (src/lang/lex2.go)
entrada de prueba (src/lang/f.p)
salida (src/lang/f.out6)
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 39 of 40http://127.0.0.1:3999/s09.symbol.slide#1
¿Ahora qué?
Falta procesar parámetros en los procedimientos
hay que definir un símbolo para cada uno en su ámbito
Hay que modificar el acceso a campos en records
buscando en el símbolo del tipo si está o no definido
Hay que evaluar expresiones evaluables en compilación
Hay que comprobar
tipos de datos
variables usadas y no asignadas y asignadas y no usadas
Hay que reescribir-optimizar partes del AST
Un switch pueden ser varios if
Hay que generar código
1/25/16, 2:49 PMCompiladores: Símbolos y ámbitos - (c)2014 LSUB
Page 40 of 40http://127.0.0.1:3999/s09.symbol.slide#1
Questions?
Francisco J BallesterosLSUB, URJChttp://lsub.org (http://lsub.org)