{ {-# OPTIONS -fno-warn-missing-signatures #-} {-# OPTIONS -fno-warn-unused-binds #-} {-# OPTIONS -fno-warn-unused-matches #-} {-# OPTIONS -fno-warn-name-shadowing #-} {-# OPTIONS -fno-warn-incomplete-patterns #-} {-# OPTIONS -fno-warn-lazy-unlifted-bindings #-} module Lexer where import Data.Ratio } %wrapper "posn" $sign = [\+\-] $exponent = [Ee] $numeric = 0-9 $non_zero_numeric = 1-9 $lower_alpha = a-z $upper_alpha = A-Z $alpha_numeric = [$lower_alpha$upper_alpha$numeric\_] $dollar = \$ $printable_char = . $viewable_char = [$printable_char\n] @not_star_slash = ( ([\n] | [^\*]) * ("*"+) ([\n] | [^\/\*]) )* ([\n] | [^\*])* @sq_char = [^\\\'] | [\\][\\\'] @do_char = [^\\\"] | [\\][\\\"] @decimal_natural = [0]| $non_zero_numeric $numeric* @signed_decimal = $sign @decimal_natural @decimal = @signed_decimal | @decimal_natural @dot_decimal = "." $numeric $numeric* @decimal_fraction = @decimal @dot_decimal @decimal_exponent = ( @decimal | @decimal_fraction ) $exponent @decimal tokens :- $white+ ; "(" { withPos $ const LP } "[" { withPos $ const Lbrack } "]" { withPos $ const Rbrack } ")" { withPos $ const RP } "," { withPos $ const Comma } "!="|"="|"<=>"|"<="|"=>"|"<~>"|"&"|"|" |"~|"|"~&"|"!"|"?"|":"|"~" { withPos $ Oper } "." { withPos $ const Dot } ("%"|"#")$printable_char* { withPos $ CommentToken } -- comment line "/*" @not_star_slash "*"("*"*)"/" { withPos $ CommentToken } -- comment block [\'] @sq_char* [\'] { withPos SingleQuoted } [\"] @do_char* [\"] { withPos DoubleQuoted } $dollar $dollar $lower_alpha $alpha_numeric* { withPos DollarDollarWord } $dollar $lower_alpha $alpha_numeric* { withPos DollarWord } $upper_alpha $alpha_numeric* { withPos UpperWord } $lower_alpha $alpha_numeric* { withPos LowerWord } "*" { withPos $ const Star } "+" { withPos $ const Plus } ">" { withPos $ const Rangle } @decimal_fraction | @decimal_exponent { withPos (Real . readDecimalFraction . stripPlus) } $sign @decimal_natural { withPos (SignedInt . readInteger . stripPlus) } @decimal_natural { withPos (UnsignedInt . readInteger . stripPlus) } "/" { withPos $ const Slash } { -- Each action has type :: String -> Token withPos f pos s = (pos, f s) -- The token type: data Token = LP | RP | Comma | Dot | Lbrack | Rbrack | Oper String | SingleQuoted String | DoubleQuoted String | DollarWord String | DollarDollarWord String | UpperWord String | LowerWord String | Star | Plus | Rangle | SignedInt Integer | UnsignedInt Integer | Real Rational | CommentToken String | Slash deriving (Eq,Ord,Show) -- alex defines: alexScanTokens stripPlus :: String -> String stripPlus ('+':xs) = xs stripPlus xs = xs readDecimalFraction :: String -> Rational readDecimalFraction ('-':cs) = -(readUnsignedDecimalFraction cs) readDecimalFraction cs = readUnsignedDecimalFraction cs readInteger :: String -> Integer readInteger = read readUnsignedDecimalFraction :: String -> Rational readUnsignedDecimalFraction cs = case break (=='.') cs of (_,"") -> case breakExponent cs of (cs2,_:cs2') -> readIntegerRat cs2 * readExponent cs2' (cs1,_:cs1') -> case breakExponent cs1' of (_,"") -> readIntegerRat cs1 + readFraction cs1' (cs2,_:cs2') -> (readIntegerRat cs1 + readFraction cs2) * readExponent cs2' where breakExponent = break (`elem` "Ee") readExponent :: String -> Rational readExponent = (10^^) . readInteger . stripPlus readFraction :: String -> Rational readFraction cs = readInteger cs % (10^(length cs)) readIntegerRat :: String -> Rational readIntegerRat = fromIntegral . readInteger }