sintactico semantico resueltos prueba lexico jflex fuente ejercicios ejemplo descargar compiladores codigo analizador haskell parsec

haskell - semantico - Ejemplos de analizador completo con parsec?



analizador sintactico jflex (3)

El libro Write Yourself a Scheme in 48 Hours es un excelente resumen en profundidad y tutorial de la funcionalidad de Parsec. Lo guía a través de todo con ejemplos en profundidad, y al final ha implementado una parte bastante significativa del esquema en un intérprete de parsec.

Estoy intentando hacer un analizador para un lenguaje funcional simple, un poco como Caml, pero parece que estoy atascado con las cosas más simples.

Así que me gustaría saber si hay algunos ejemplos más completos de analizadores parsec , algo que va más allá de "así es como se analizan 2 + 3". Especialmente las llamadas de función en términos y similares.

Y he leído "Escríbele un esquema", pero la sintaxis del esquema es bastante simple y no ayuda mucho para aprender.

El mayor número de problemas que tengo es cómo usar try , <|> y choice correctamente, porque realmente no entiendo por qué Parsec nunca analiza a(6) como una llamada de función usando este analizador:

expr = choice [number, call, ident] number = liftM Number float <?> "Number" ident = liftM Identifier identifier <?> "Identifier" call = do name <- identifier args <- parens $ commaSep expr return $ FuncCall name args <?> "Function call"

EDITAR Agregado un código para completar, aunque en realidad no es lo que pedí:

AST.hs

module AST where data AST = Number Double | Identifier String | Operation BinOp AST AST | FuncCall String [AST] deriving (Show, Eq) data BinOp = Plus | Minus | Mul | Div deriving (Show, Eq, Enum)

Lexer.hs

module Lexer ( identifier, reserved, operator, reservedOp, charLiteral, stringLiteral, natural, integer, float, naturalOrFloat, decimal, hexadecimal, octal, symbol, lexeme, whiteSpace, parens, braces, angles, brackets, semi, comma, colon, dot, semiSep, semiSep1, commaSep, commaSep1 ) where import Text.Parsec import qualified Text.Parsec.Token as P import Text.Parsec.Language (haskellStyle) lexer = P.makeTokenParser haskellStyle identifier = P.identifier lexer reserved = P.reserved lexer operator = P.operator lexer reservedOp = P.reservedOp lexer charLiteral = P.charLiteral lexer stringLiteral = P.stringLiteral lexer natural = P.natural lexer integer = P.integer lexer float = P.float lexer naturalOrFloat = P.naturalOrFloat lexer decimal = P.decimal lexer hexadecimal = P.hexadecimal lexer octal = P.octal lexer symbol = P.symbol lexer lexeme = P.lexeme lexer whiteSpace = P.whiteSpace lexer parens = P.parens lexer braces = P.braces lexer angles = P.angles lexer brackets = P.brackets lexer semi = P.semi lexer comma = P.comma lexer colon = P.colon lexer dot = P.dot lexer semiSep = P.semiSep lexer semiSep1 = P.semiSep1 lexer commaSep = P.commaSep lexer commaSep1 = P.commaSep1 lexer

Parser.hs

module Parser where import Control.Monad (liftM) import Text.Parsec import Text.Parsec.String (Parser) import Lexer import AST expr = number <|> callOrIdent number = liftM Number float <?> "Number" callOrIdent = do name <- identifier liftM (FuncCall name) (parens $ commaSep expr) <|> return (Identifier name)


Escribí una serie de ejemplos sobre cómo analizar los números romanos con parsec. Es bastante básico, pero a ti oa otros recién llegados les puede resultar útil:

https://github.com/russell91/roman


Hmm

*Expr> parse expr "" "a(6)" Right (FuncCall "a" [Number 6.0])

Esa parte me funciona después de rellenar las piezas faltantes.

Edición: llené las piezas faltantes escribiendo mi propio analizador float , que podría analizar literales enteros. El analizador float de Text.Parsec.Token por otro lado, solo analiza literales con una parte fraccionada o un exponente, por lo que no pudo analizar el "6".

Sin embargo,

*Expr> parse expr "" "variable" Left (line 1, column 9): unexpected end of input expecting "("

cuando la llamada falla después de haber analizado un identificador, esa parte de la entrada se consume, por lo tanto, no se intenta identificar y el análisis general falla. Puede a) hacer que try call en la lista de opciones de expr , de modo que la llamada falle sin consumir datos, o b) escribir un analizador callOrIdent para usar en expr , por ejemplo

callOrIdent = do name <- identifier liftM (FuncCall name) (parens $ commaSep expr) <|> return (Identifier name)

lo que evita try y por lo tanto puede rendir mejor.