Construcci - PowerPoint PPT Presentation

About This Presentation
Title:

Construcci

Description:

Construcci n de compiladores con Haskell Jos Mar a Carmona Cejudo Briseida Sarasola Guti rrez ndice Motivaci n Qu es un compilador? Historia Esquema de un ... – PowerPoint PPT presentation

Number of Views:47
Avg rating:3.0/5.0
Slides: 64
Provided by: Brise
Category:
Tags: construcci

less

Transcript and Presenter's Notes

Title: Construcci


1
Construcción de compiladores con Haskell
  • José María Carmona Cejudo
  • Briseida Sarasola Gutiérrez

2
Índice
  • Motivación
  • Qué es un compilador?
  • Historia
  • Esquema de un compilador
  • Técnicas en Haskell estándar
  • Análisis monádico
  • Herramientas software
  • Alex
  • Happy (Frown)
  • Parsec
  • Qué podemos concluir?
  • Bibliografía

3
Qué es un compilador?
  • Programa que traduce texto escrito en un lenguaje
    de programación (código fuente) a otro (código
    objeto).
  • Código fuente escrito en un lenguaje de alto
    nivel (Haskell, Java, C), que queremos pasar a
    un lenguaje de bajo nivel (ensamblador, lenguaje
    máquina).

4
Un poco de historia (I)
  • En principio, se programaba en código binario.
  • Años 40 Se crean mnemotécnicos para las
    operaciones binarias, usando los ordenadores para
    traducirlos a código máquina.
  • Años 50 Nacen lenguajes de alto nivel, para
    crear programas más independientes de la máquina.
  • Primer compilador Fortran, 1.957. Equipo de J.
    Backus, de IBM.

5
Un poco de historia (II)
  • Años 60 Se establecen muchos de los principios
    del diseño de compiladores. Aún se suelen
    programar en ensamblador
  • Años 70 Se usan lenguajes de alto nivel, como
    Pascal y C.
  • Otros tipos intérpretes (realizan el proceso
    sentencia a sentencia). Programas resultantes más
    lentos, pero más fáciles de depurar.

6
Esquema de un compilador
  • Dos fases
  • Análisis se lee el programa fuente y se estudia
    la estructura y el significado del mismo.
  • Síntesis se genera el programa objeto.
  • Otros elementos tabla de símbolos, rutinas de
    tratamiento de errores, etc.

7
Esquema de un compilador
  • Dos fases
  • Análisis se lee el programa fuente y se estudia
    la estructura y el significado del mismo.
  • Síntesis se genera el programa objeto.
  • Otros elementos tabla de símbolos, rutinas de
    tratamiento de errores, etc.

8
Esquema de un compilador
  • Dos fases
  • Análisis se lee el programa fuente y se estudia
    la estructura y el significado del mismo.
  • Síntesis se genera el programa objeto.
  • Otros elementos tabla de símbolos, rutinas de
    tratamiento de errores, etc.

9
Fase de análisis
  • Tres fases
  • Análisis léxico
  • Análisis sintáctico
  • Análisis semántico

10
Fase de análisis
  • Tres fases
  • Análisis léxico
  • identificar símbolos,
  • eliminar separadores,
  • eliminar comentarios,
  • crear símbolos de entrada al análisis sintáctico
    (tokens),
  • descubrir errores.
  • Análisis sintáctico
  • Análisis semántico

11
Fase de análisis
  • Tres fases
  • Análisis léxico
  • Análisis sintáctico
  • comprobar que las sentencias que componen el
    texto fuente son correctas en el lenguaje,
    creando una representación interna que
    corresponde a la sentencia analizada.
  • Análisis semántico

12
Fase de análisis
  • Tres fases
  • Análisis léxico
  • Análisis sintáctico
  • Análisis semántico
  • Se ocupa de analizar si la sentencia tiene algún
    significado. Incluye análisis de tipos, o en
    general, sentencias que carecen se sentido.

13
Análisis léxico en Haskell
  • Pretendemos reconocer expresiones regulares, que
    pueden ser reconocidas por un autómata finito
    determinista (AFD).
  • Implementación de los estados del AFD
  • f String -gt (String, Token)
  • Implementación de transición de A a B la función
    fA llama a fB después de leer un carácter y
    pasarle el resto a fB.

14
Análisis léxico en Haskell
  • Ejemplo

15
Análisis léxico en Haskell
  • Ejemplos
  • funciones analizadoras simples
  • éxito a -gt ReadS a
  • éxito x \s -gt (x, s)
  • épsilon ReadS ()
  • épsilon éxito ()
  • fallo ReadS a
  • fallo \s -gt
  • Alternativa
  • infixl 5 --
  • (--) ReadS a -gt ReadS a -gt ReadS a
  • p1 -- p2 \s -gt p1 s p2 s
  • Lectura condicional del primer carácter
  • rSat (Char -gt Bool) -gt ReadS Char
  • rSat p \s -gt case s of
  • -gt
  • xxs -gt if p x then (x,xs)
    else
  • MAINgt rSat isUpper ABC
  • (A, BC)

16
Análisis léxico en Haskell
  • Ejemplos
  • combinación de analizadores para conseguir uno
    más complejo (parser combinator)
  • infixl 7 gtlt
  • (gtlt) ReadS a -gt ReadS b -gt ReadS (a,b)
  • p1 gtlt p2 \s -gt ((x1,x2),s2) (x1,s1) lt- p1
    s,
  • (x2,s2) lt- p2
    s1
  • MAINgt (rChar a gtlt rChar b) abcd
  • ((a, b), cd)

17
Análisis sintáctico en Haskell
  • En un lenguaje funcional como Haskell, es fácil
    traducir las reglas gramaticales directamente a
    especificación funcional.

exp -gt term rest rest -gt exp epsilon exp term ltgt rest rest token AddOp ltgt exp ltgt epsilon
18
Análisis sintáctico en Haskell
  • El paradigma funcional nos da una expresividad a
    la hora de representar reglas gramaticales
    impensable en el paradigma imperativo.
  • Ejemplo función many
  • many Parser a b -gt Parser a b
  • exp term ltgt many (token addOp ltgt term lt_at_ f4)
    lt_at_ f5

19
Análisis sintáctico en Haskell
  • Lo que hemos visto se refiere a análisis de
    arriba a abajo.
  • Realizar análisis de abajo a arriba es más
    complejo.
  • Happy es una herramienta que nos facilita la
    creación de un analizador abajo a arriba.

20
Análisis semántico.
  • Una vez construido al árbol sintáctico, los demás
    algoritmos se pueden expresar como recorridos en
    ese árbol.
  • La programación funcional es muy potente a la
    hora de realizar recorridos en un árbol, como
    veremos.

21
Análisis semántico.
  • Atributos de los nodos del árbol
  • Se usan para asignar un valor parcial a cada nodo
    del árbol, para ir calculando, por ejemplo, los
    valores de una expresión paso a paso.
  • Atributo sintetizado
  • Para calcularlo, necesitamos calcular antes los
    atributos de los sucesores.
  • Ejemplo Inferencia de Tipos
  • Se corresponde a un recorrido de abajo a arriba.
  • Funciones de orden superior como foldTree son
    muy útiles, y nos dan una sencillez y
    expresividad grandes.

22
Análisis semántico.
23
Análisis semántico.
  • Atributos heredados.
  • Su valor ya está calculado, arriba o al mismo
    nivel en el árbol.
  • Se corresponden a un recorrido de arriba a abajo.
  • Se puede representar mediante una función
    recursiva (posiblemente de cola), acumulando los
    atributos.
  • Veamos en el árbol anterior cuáles serían
    atributos heredados.

24
Análisis semántico
25
Analizadores monádicos
  • Wadler, en 1995, introdujo el uso de las mónadas
    para implementar analizadores.
  • Usando el parser combinator gtlt que hemos visto,
    tenemos tuplas anidadas, engorrosas de manipular.
  • La función monádica bind (gtgt) junto con el uso
    de lambda-abstracciones nos permite una notación
    más manejable.
  • Además, podemos usar otros combinadores monádicos.

26
Analizadores monádicos
  • Ejemplo secuencia
  • Como se ha visto en clase, algo bueno de las
    mónadas es que permiten simular secuenciación al
    estilo imperativo

aplica Analiz a -gt String -gt(a, Estado) aplica (AN p) ent p ent dosElementosAnaliz String dosElementosdo a lt- elemento b lt- elemento returna,b MAINgt aplica dosElementos abcdca (ab, cdca) (String, String)
27
Analizadores monádicos
  • Mediante MonadPlus, podemos implementar el
    concepto de alternancia. Mplus toma dos
    analizadores, y concatena el resultado de ambos
    sobre la cadena entrada mzero falla siempre.

Instance MonadPlus analiz where mplus (AN
p)(AN q) AN(\ent -gt p ent q ent) mzero
AN (\ent -gt )
28
Analizadores monádicos
  • Tomando (!) como sinónimo de mplus, podemos
    construir lo siguiente elemento ! dosElementos,
    que captura un solo carácter, o dos.
  • Otro ejemplo filtros

unoODosElementos elemento ! dosElementos gt aplica unoODosElementos "abcdca" ("a","bcdca"),("ab","cdca")
(!gt) Analiz a -gt (a -gt Bool) -gt Analiz a k !gt p
do a lt- k if p a then return a else mzero
29
Analizadores monádicos
  • Reconocimiento de una letra, o bien de un número

letraAnalizChar letraelemento !gt
isAlpha digitoAnalizChar digitoelemento !gt
isDigit letraODigito letra ! digito.
30
Analizadores monádicos
  • Ejemplo reconocimiento de expresiones

term constante ( term term ) ( term / term )
31
Analizadores monádicos
  • Ejemplo reconocimiento de expresiones

anaConstAnalizTerm anaConstdo a lt- número return(Const a) anaSumAnalizTerm anaSumdo _ lt- literal ( u lt- term _ lt- literal v lt- term _ lt- literal ) return(uv) anaDivAnalizTerm anaDivdo _ lt- literal ( u lt- term _ lt- literal / v lt- term _ lt- literal ) return(u/v) termAnalizTerm termanaConst ! anaSum ! anaDiv
32
Software específico
  • Alex
  • Happy
  • Frown
  • Parsec

33
Alex
  • Analizador léxico (Lex).
  • Características
  • Basado en expresiones regulares
  • Y en autómatas finitos deterministas (DFAs)
  • Definir
  • Macros
  • Reglas
  • Contextos
  • Expresiones start
  • Facilita envoltorios (wrappers)

34
Alex. Wrappers
  • basic
  • El más simple dada una cadena, devuelve una
    lista de Tokens.
  • posn
  • Da más funcionalidades (número de línea/columna)
  • monad
  • El más flexible
  • Es una plantilla para construir nuestras propias
    mónadas
  • gscan
  • Presente por razones históricas

35
Alex. Ejemplo
  • module Main (main) where
  • wrapper "basic"
  • digit 0-9
  • alpha a-zA-Z
  • tokens -
  • white
  • "--".
  • let \s -gt Let
  • in \s -gt In
  • digit \s -gt Int (read s)
  • \\\-\\/\(\)
  • \s -gt Sym (head s)
  • alpha alpha digit \- \' \s -gt
    Var s
  • -- Each action has type String -gt Token
  • -- The token type
  • data Token
  • Let
  • In
  • Sym Char
  • Var String
  • Int Int
  • deriving (Eq,Show)
  • main do
  • s lt- getContents
  • print (alexScanTokens s)

36
Alex. Fichero resultante
  • -- The token type
  • data Token
  • Let
  • In
  • Sym Char
  • Var String
  • Int Int
  • deriving (Eq,Show)
  • main do
  • s lt- getContents
  • print (alexScanTokens s)
  • alex_action_2 \s -gt Let
  • alex_action_3 \s -gt In
  • alex_action_4 \s -gt Int (read s)
  • alex_action_5 \s -gt Sym (head s)
  • alex_action_6 \s -gt Var s
  • type AlexInput (Char,String)
  • alexGetChar (_, ) Nothing
  • alexGetChar (_, ccs) Just (c, (c,cs))
  • alexInputPrevChar (c,_) c
  • -- alexScanTokens String -gt token
  • alexScanTokens str go ('\n',str)
  • where go inp_at_(_,str)
  • case alexScan inp 0 of
  • AlexEOF -gt
  • AlexError _ -gt error "lexical error"
  • AlexSkip inp' len -gt go inp'
  • AlexToken inp' len act -gt act (take len str)
    go inp'

37
Happy
  • Utiliza análisis LALR(1).
  • Trabaja en conjunción con un analizador léxico.
  • Genera distintos tipos de código
  • Haskell 98
  • Haskell estándar con arrays
  • Haskell con extensiones GHC
  • Haskell GHC con arrays codificados como cadenas
  • Flexibilidad
  • Velocidad

38
Happy
  • Utiliza análisis LALR(1).
  • Trabaja en conjunción con un analizador léxico.
  • Genera distintos tipos de código
  • Haskell 98
  • Haskell estándar con arrays
  • Haskell con extensiones GHC
  • Haskell GHC con arrays codificados como cadenas
  • Flexibilidad
  • Velocidad

39
Happy
  • Utiliza análisis LALR(1).
  • Trabaja en conjunción con un analizador léxico.
  • Genera distintos tipos de código
  • Haskell 98
  • Haskell estándar con arrays
  • Haskell con extensiones GHC
  • Haskell GHC con arrays codificados como cadenas
  • Flexibilidad
  • Velocidad

40
Happy
  • Utiliza análisis LALR(1).
  • Trabaja en conjunción con un analizador léxico.
  • Genera distintos tipos de código
  • Haskell 98
  • Haskell estándar con arrays
  • Haskell con extensiones GHC
  • Haskell GHC con arrays codificados como cadenas
  • Flexibilidad
  • Velocidad

41
Happy
  • Utiliza análisis LALR(1).
  • Trabaja en conjunción con un analizador léxico.
  • Genera distintos tipos de código
  • Haskell 98
  • Haskell estándar con arrays
  • Haskell con extensiones GHC
  • Haskell GHC con arrays codificados como cadenas
  • Flexibilidad
  • Velocidad

42
Happy. Ejemplo
  • module Main where
  • name calc
  • tokentype Token
  • token
  • let TokenLet
  • in TokenIn
  • int TokenInt
  • var TokenVar
  • '' TokenEq
  • '' TokenPlus
  • '-' TokenMinus
  • '(' TokenOB
  • ')' TokenCB
  • Exp let var '' Exp in Exp Let 2 4 6
  • Exp1 Exp1 1
  • Exp1 Exp1 '' Term Plus 1 3
  • Exp1 '-' Term Minus 1 3
  • Term Term 1
  • Term int Int 1
  • var Var 1
  • '(' Exp ')' Brack 2
  • n t_1 .. t_n E

43
Happy. Ejemplo
  • happyError Token -gt a
  • happyError _ error "Parse error"
  • data Exp
  • Let String Exp Exp
  • Exp1 Exp1
  • data Exp1
  • Plus Exp1 Term
  • Minus Exp1 Term
  • Term Term
  • data Term
  • Int Int
  • Var String
  • Brack Exp
  • data Token
  • lexer String -gt Token
  • lexer
  • lexer (ccs)
  • isSpace c lexer cs
  • isAlpha c lexVar (ccs)
  • isDigit c lexNum (ccs)
  • lexer (''cs) TokenEq lexer cs
  • lexer (''cs) TokenPlus lexer cs
  • lexer ('-'cs) TokenMinus lexer cs
  • lexer ('('cs) TokenOB lexer cs
  • lexer (')'cs) TokenCB lexer cs
  • lexNum cs TokenInt (read num) lexer rest
  • where (num,rest) span isDigit cs
  • lexVar cs
  • case span isAlpha cs of
  • ("let",rest) -gt TokenLet lexer rest
  • ("in",rest) -gt TokenIn lexer rest

44
Frown
  • Utiliza análisis LALR(k)
  • Eficiencia
  • Funcionales

45
Frown
  • Utiliza análisis LALR(k)
  • Eficiencia
  • Funcionales

46
Frown
  • Utiliza análisis LALR(k)
  • Eficiencia
  • Funcionales

47
Parsec
  • Es una librería de combinadores monádicos.
  • Se trabaja directamente en Haskell.
  • Está incluído en GHC y en Hugs.
  • Es más eficiente con gramáticas LL(1).

48
Parsec. Un ejemplo
  • El código
  • module Main where
  • import Text.ParserCombinators.Parsec
  • simple Parser Char
  • simple letter
  • ejecuta Show a gt Parser a -gt String -gt IO ()
  • ejecuta p input
  • case (parse p "" input) of
  • Left err -gt do putStr "error al
    analizar "
  • print err
  • Right x -gt print x

49
Parsec. Un ejemplo
  • Ejecución
  • Maingt ejecuta simple ""
  • Loading package parsec-1.0 ... linking ... done.
  • error al analizar (line 1, column 1)
  • unexpected end of input
  • expecting letter
  • Maingt ejecuta simple "123"
  • error al analizar (line 1, column 1)
  • unexpected "1"
  • expecting letter
  • Maingt ejecuta simple "a"
  • 'a'

50
Parsec. Otro ejemplo
  • Código
  • parens Parser ()
  • parens do char '('
  • parens
  • char ')'
  • parens
  • ltgt return ()

51
Parsec. Otro ejemplo
  • Ejecución
  • Maingt ejecuta parens "((()())())()"
  • Reading file "C\Documents and Settings\Brise\Mis
    documentos\PDA\parsec.hs"
  • ()
  • Maingt ejecuta parens "(()"
  • error al analizar (line 1, column 4)
  • unexpected end of input
  • expecting "(" or ")"

52
Qué podemos concluir?
  • Los LF respetan la estructura en fases lexing,
    parsing, análisis semántico, etc.

53
Qué podemos concluir?
  • Los LF respetan la estructura en fases lexing,
    parsing, análisis semántico, etc.

54
Qué podemos concluir?
  • Los LF respetan la estructura en fases lexing,
    parsing, análisis semántico, etc.

lexer String -gt Token parser
Token -gt ÁrbolAbstracto semántica
ÁrbolAbstracto -gt ÁrbolEtiquetado genera
ciónDeCódigo ÁrbolEtiquetado -gt Código
máquina compilador generaciónDeCódigo .
semántica . parser . lexer
55
Qué podemos concluir?
  • Evaluación perezosa
  • La salida del analizador léxico sería una lista
    perezosa de tokens.

56
Qué podemos concluir?
  • Evaluación perezosa
  • La salida del analizador léxico sería una lista
    perezosa de tokens.

lexer String -gt Token parser
Token -gt ÁrbolAbstracto semántica
ÁrbolAbstracto -gt ÁrbolEtiquetado genera
ciónDeCódigo ÁrbolEtiquetado -gt Código
máquina compilador generaciónDeCódigo .
semántica . parser . lexer
57
Qué podemos concluir?
  • Tipos de datos
  • Tokens tipo enumerado
  • data Token Id String IntConst Int SumaOp
    ProdOp PuntoYComa

58
Qué podemos concluir?
  • Tipos de datos
  • Tokens tipo enumerado
  • data Token Id String IntConst Int SumaOp
    ProdOp PuntoYComa
  • Tabla de símbolos árboles AVL o Tablas Hash

59
Qué podemos concluir?
  • Tipos de datos
  • Tokens tipo enumerado
  • data Token Id String IntConst Int SumaOp
    ProdOp PuntoYComa
  • Tabla de símbolos árboles AVL o Tablas Hash
  • Árboles abstractos tipos mutuamente recursivos

60
Qué podemos concluir?
  • Tipos de datos
  • Tokens tipo enumerado
  • data Token Id String IntConst Int SumaOp
    ProdOp PuntoYComa
  • Tabla de símbolos árboles AVL o Tablas Hash
  • Árboles abstractos tipos mutuamente recursivos
  • Funciones de orden superior
  • Combinadores de analizadores.

61
Qué podemos concluir?
  • Recursión
  • La recursión y el reconocimiento de patrones que
    existen en Haskell son un método potente para
    tratar este tipo de estructuras recursivas.

62
Qué podemos concluir?
  • Recursión
  • La recursión y el reconocimiento de patrones que
    existen en Haskell son un método potente para
    tratar este tipo de estructuras recursivas.
  • Polimorfismo

data Instr a Asignar String a (Expr a)
While (Expr a) (Instr a) If (Expr
a) (Instr a) (Instr a) ...
63
Bibliografía
  • Blas C. Ruiz, Francisco Gutiérrez, Paco Guerrero,
    José E. Gallardo. Razonando con Haskell.
    Thomson, Madrid 2004. Cap. 14, Analizadores.
  • Ricardo Peña. Compile Construction in a
    Functional Setting. Universidad Complutense de
    Madrid.
  • Jeroen Fokker. Functional Parsers. Universidad de
    Utrecht.
  • Graham Hutton y Erik Meijer. Monadic Parser
    Combinators. Universidades de Nottingham y
    Utrecht.
  • Referencias web
  • http//www.haskell.org
  • http//www.informatik.uni-bonn.de/ralf/frown
  • http//www.cs.uu.nl/daan/parsec.html
Write a Comment
User Comments (0)
About PowerShow.com