{ module Main where import Char } %name parser Exp %tokentype { Token } %error { parseError } %token 'let' { TokenIdent "let" } 'in' { TokenIdent "in" } ident { TokenIdent $$ } int { TokenInt $$ } '=' { TokenSymbol "=" } '+' { TokenSymbol "+" } '-' { TokenSymbol "-" } '*' { TokenSymbol "*" } '/' { TokenSymbol "/" } '(' { TokenSymbol "(" } ')' { TokenSymbol ")" } %expect 1 %% Exp : 'let' Ident '=' 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 : Term '*' Factor { Times $1 $3 } | Term '/' Factor { Div $1 $3 } | Factor { Factor $1 } Factor : int { Int $1 } | Ident { $1 } | '(' Exp ')' { Brack $2 } Ident : ident { Var $1 } | Keyword { $1 } Keyword : 'let' { Var "let" } | 'in' { Var "in" } { parseError :: [Token] -> a parseError _ = error "Parse error" data Exp = Let Factor Exp Exp | Exp1 Exp1 deriving Show data Exp1 = Plus Exp1 Term | Minus Exp1 Term | Term Term deriving Show data Term = Times Term Factor | Div Term Factor | Factor Factor deriving Show data Factor = Int Int | Var String | Brack Exp deriving Show data Token = TokenInt Int | TokenIdent String | TokenSymbol String | TokenEnd deriving Show -- Lexer lexer :: String -> [Token] lexer [] = [] lexer (c:cs) | isSpace c = lexer cs | isIdentFirst c = lexIdent (c:cs) | isDigit c = lexNum (c:cs) | isSymbol c = lexSymbol (c:cs) --- Indentifiers isIdent :: String -> Bool isIdent (c:cs) = isIdentFirst c where (var, rest) = span isIdentRest (c:cs) isIdentFirst c = isAlpha c || (c == '_') isIdentRest c = isAlpha c || isDigit c || c == '_' || c == '-' || c == '\'' lexIdent cs = TokenIdent var : lexer rest where (var, rest) = span isIdentRest cs --- Symbols isSymbol c = c `elem` symChar symChar = "!@#$%&*+./<=>?\\^|:-~_" lexSymbol cs = TokenSymbol var : lexer rest where (var, rest) = span isSymbol cs --- Numbers lexNum cs = TokenInt (read num) : lexer rest where (num, rest) = span isDigit cs -- Main main = do line <- getLine process line process = print . parser . lexer }