-- Lexer15min.hs -- -- Lexer Module for the 15 minute example. -- module Lexer15min where -- needed for isChar, isAlpha, isSpace, isDigit import Data.Char -- Token datatype. -- Much like an enumerated type except the TokenInt and TokenId -- constructors also take a value. Deriving Show so they can -- be printed. data Token = TokenCIRCLE | TokenTRIANGLE | TokenNUM Int | TokenSemi | UnknownChar Char deriving (Show,Eq) ----------------------------------------------------------------- -- Function that performs lexical analysis. -- The following line declares the type of the function. -- The input parameter is a String type and the function returns -- a list of Tokens. lexer :: String -> [Token] -- Below has examples of pattern matching. The first pattern "[]" -- is an empty list. The later patterns match some character at the -- beginning of a list. -- See http://www.haskell.org/haskellwiki/How_to_work_on_lists. lexer [] = [] lexer (';':cs) = TokenSemi : lexer cs -- The below uses pattern matching to bind the variables c and cs, -- then it uses guards to determine what recursion to perform. -- See http://www.haskell.org/haskellwiki/Case#Guards -- and http://stackoverflow.com/questions/4156727/what-is-the-difference-between-pattern-matching-and-guards. -- Note that the guards are executed in order with only the first -- one returning true being executed. lexer (c:cs) | isSpace c = lexer cs | isAlpha c = lexKW (c:cs) | isDigit c = lexNum (c:cs) | True = UnknownChar c : lexer cs -- Function of processing integers. -- Uses a where clause. lexNum cs = TokenNUM (read num) : lexer rest where (num,rest) = span isDigit cs -- Function for processing keywords. -- The span function is built in to the Prelude. Look it up. -- This function implementation shows an example of the case expression, -- which also uses pattern matching. lexKW cs = case span isAlpha cs of ("Circle",rest) -> TokenCIRCLE : lexer rest ("Triangle",rest) -> TokenTRIANGLE : lexer rest (id,rest) -> error ("Lexer error: unknown keyword " ++ id)