-------------------------------------------------------------
-- Parser for Tiger from Appel's book on compilers.
-- Semantic checks have been omitted for now.
-- Scope rules and such are as a consequence not implemented.
-------------------------------------------------------------
module Tiger( prettyTigerFromFile ) where
import TigerAS
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language( javaStyle )
prettyTigerFromFile fname
= do{ input <- readFile fname
; putStr input
; case parse program fname input of
Left err -> do{ putStr "parse error at "
; print err
}
Right x -> print x
}
{-
main = do putStr "Parsec Tiger parser\n"
putStr "Type filename (without suffix): "
basename <- getLine
tokens <- scanner False keywordstxt
keywordsops
specialchars
opchars
(basename ++ ".sl")
Nothing
let ((exprpp,proof), errors) = parse pRoot tokens
putStr (if null errors then "" else "Errors:\n" ++ errors)
putStr ("Result:\n" ++ (disp exprpp 140 ""))
writeFile (basename ++ ".tex") (disp proof 500 "")
putStr ("\nGenerated proof in file " ++ (basename ++ ".tex"))
-}
-----------------------------------------------------------
-- A program is simply an expression.
-----------------------------------------------------------
program
= do{ whiteSpace
; e <- expr
; return e
}
----------------------------------------------------------------
-- Declarations for types, identifiers and functions
----------------------------------------------------------------
decs
= many dec
dec
= tydec
<|>
vardec
<|>
fundec
----------------------------------------------------------------
-- Type declarations
-- int and string are predefined, but not reserved.
----------------------------------------------------------------
tydec :: Parser Declaration
tydec
= do{ reserved "type"
; tid <- identifier
; symbol "="
; t <- ty
; return (TypeDec tid t)
}
ty
= do{ fields <- braces tyfields
; return (Record fields)
}
<|>
do{ reserved "array"
; reserved "of"
; tid <- identifier
; return (Array tid)
}
<|>
do{ id <- identifier
; return (Var id)
}
tyfields
= commaSep field
noType = "*"
voidType = "void"
field
= do{ id <- identifier
; symbol ":"
; tid <- identifier
; return (TypedVar id tid)
}
----------------------------------------------------------------
-- identifier declarations
-- Lacks: 11, 12
----------------------------------------------------------------
vardec
= do{ reserved "var"
; id <- identifier
; t <- option noType (try (do{ symbol ":"
; identifier
}))
; symbol ":="
; e <- expr
; return (VarDec id t e)
}
----------------------------------------------------------------
-- Function declarations
----------------------------------------------------------------
fundec
= do{ reserved "function"
; name <- identifier
; parms <- parens tyfields
; rettype <- option voidType (do{ symbol ":"
; identifier
})
; symbol "="
; body <- expr
; return (FunDec name parms rettype body)
}
----------------------------------------------------------------
-- Lvalues
-- This may not be what we want. I parse lvalues as
-- a list of dot separated array indexings (where the indexing)
-- may be absent. Possibly, we'd want the . and []
----------------------------------------------------------------
-- This combinator does ab* in a leftassociative way.
-- Applicable when you have a cfg rule with left recursion
-- which you might rewrite into EBNF X -> YZ*.
lfact :: Parser a -> Parser (a -> a) -> Parser a
lfact p q = do{ a <- p
; fs <- many q
; return (foldl (\x f -> f x) a fs)
}
{-
chainl op expr = lfact expr (do { o <- op
; e <- expr
; return (`o` e)
})
-}
lvalue = lfact variable (recordref <|> subscripted)
recordref = do{ symbol "."
; id <- variable
; return (\x -> Dot x id)
}
subscripted = do{ indexexpr <- brackets expr
; return (\x -> Sub x indexexpr)
}
{- Alternatively (an lvalue is then a sequence of, possibly (mutli-)indexed, identifiers separated by dots)
lvalue :: Parser Expr
lvalue = do{ flds <- sepBy1 subscripted (symbol ".")
; return (if length flds < 2 then head flds else Dots flds)
}
subscripted :: Parser Expr
subscripted = do{ id <- identifier
; indexes <- many (brackets expr)
; return (if null indexes then Ident id
else Subscripted id indexes)
}
-}
----------------------------------------------------------------
-- All types of expression(s)
----------------------------------------------------------------
exprs = many expr
expr :: Parser Expr
expr = choice
[ do{ reserved "break"
; return Break
}
, ifExpr
, whileExpr
, forExpr
, letExpr
, sequenceExpr
, infixExpr
-- , sequenceExpr -- I am not sure about this one.
]
recordExpr :: Parser Expr
recordExpr = do{ tid <- identifier
; symbol "{"
; fields <- commaSep1 fieldAssign
; symbol "}"
; return (RecordVal tid fields)
}
fieldAssign :: Parser AssignField
fieldAssign = do{ id <- identifier
; symbol "="
; e <- expr
; return (AssignField id e)
}
arrayExpr :: Parser Expr
arrayExpr = do{ tid <- identifier
; size <- brackets expr
; reserved "of"
; initvalue <- expr
; return (ArrayVal tid size initvalue)
}
assignExpr :: Parser Expr
assignExpr = do{ lv <- lvalue
; symbol ":="
; e <- expr
; return (Assign lv e)
}
ifExpr :: Parser Expr
ifExpr = do{ reserved "if"
; cond <- expr
; reserved "then"
; thenpart <- expr
; elsepart <- option Skip (do{ reserved "else"; expr})
; return (If cond thenpart elsepart)
}
whileExpr :: Parser Expr
whileExpr = do{ reserved "while"
; cond <- expr
; reserved "do"
; body <- expr
; return (While cond body)
}
forExpr :: Parser Expr
forExpr = do{ reserved "for"
; id <- identifier
; symbol ":="
; lowerbound <- expr
; reserved "to"
; upperbound <- expr
; reserved "do"
; body <- expr
; return (For id lowerbound upperbound body)
}
letExpr :: Parser Expr
letExpr = do{ reserved "let"
; ds <- decs
; reserved "in"
; es <- semiSep expr
; reserved "end"
; return (Let ds es)
}
sequenceExpr :: Parser Expr
sequenceExpr = do{ exps <- parens (semiSep1 expr)
; return (if length exps < 2 then head exps else Seq exps)
}
infixExpr :: Parser Expr
infixExpr = buildExpressionParser operators simpleExpr
operators =
[ [ prefix "-"]
, [ op "*" AssocLeft, op "/" AssocLeft ]
, [ op "+" AssocLeft, op "-" AssocLeft ]
, [ op "=" AssocNone, op "<>" AssocNone, op "<=" AssocNone
, op "<" AssocNone, op ">=" AssocNone, op ">" AssocNone ]
, [ op "&" AssocRight ] -- Right for shortcircuiting
, [ op "|" AssocRight ] -- Right for shortcircuiting
, [ op ":=" AssocRight ]
]
where
op name assoc = Infix (do{ reservedOp name
; return (\x y -> Op name x y)
}) assoc
prefix name = Prefix (do{ reservedOp name
; return (\x -> UnOp name x)
})
simpleExpr = choice [ do{ reserved "nil"
; return Nil
}
, intLiteral
, strLiteral
, parens expr
, try funCallExpr
, try recordExpr
, try arrayExpr
, lvalue
]
funCallExpr = do{ id <- identifier
; parms <- parens (commaSep expr)
; return (Apply id parms)
}
intLiteral = do{ i <- integer; return (IntLit i) }
strLiteral = do{ s <- stringLiteral; return (StringLit s) }
variable = do{ id <- identifier
; return (Ident id)
}
-----------------------------------------------------------
-- The lexer
-----------------------------------------------------------
lexer = P.makeTokenParser tigerDef
tigerDef = javaStyle
{ -- Kept the Java single line comments, but officially the language has no comments
P.reservedNames = [ "array", "break", "do", "else", "end", "for", "function",
"if", "in", "let",
"nil", "of", "then", "to", "type", "var", "while" ]
, P.reservedOpNames= [ "<", "<=", ">", ">=", ":=", "+", "&", "-", "/"]
, P.opLetter = oneOf (concat (P.reservedOpNames tigerDef))
, P.caseSensitive = True
}
parens = P.parens lexer
braces = P.braces lexer
semiSep = P.semiSep lexer
semiSep1 = P.semiSep1 lexer
commaSep = P.commaSep lexer
commaSep1 = P.commaSep1 lexer
brackets = P.brackets lexer
whiteSpace = P.whiteSpace lexer
symbol = P.symbol lexer
identifier = P.identifier lexer
reserved = P.reserved lexer
reservedOp = P.reservedOp lexer
integer = P.integer lexer
charLiteral = P.charLiteral lexer
stringLiteral = P.stringLiteral lexer
|