diff --git a/Text/Trifecta.hs b/Text/Trifecta.hs
--- a/Text/Trifecta.hs
+++ b/Text/Trifecta.hs
@@ -16,8 +16,10 @@
   , module Text.Trifecta.Parser.Prim
   , module Text.Trifecta.Parser.Result
   , module Text.Trifecta.Parser.Step
-  , module Text.Trifecta.Parser.Token
   , module Text.Trifecta.Parser.Token.Class
+  , module Text.Trifecta.Parser.Token.Combinators
+  , module Text.Trifecta.Parser.Token.Prim
+  , module Text.Trifecta.Parser.Token.Style
   , module Text.Trifecta.Parser.Expr
   , module Text.Trifecta.Path
   , module Text.Trifecta.Render.Caret
@@ -43,8 +45,10 @@
 import Text.Trifecta.Parser.Prim
 import Text.Trifecta.Parser.Result
 import Text.Trifecta.Parser.Step
-import Text.Trifecta.Parser.Token
 import Text.Trifecta.Parser.Token.Class
+import Text.Trifecta.Parser.Token.Combinators
+import Text.Trifecta.Parser.Token.Prim
+import Text.Trifecta.Parser.Token.Style
 import Text.Trifecta.Parser.Expr
 import Text.Trifecta.Path
 import Text.Trifecta.Render.Caret
diff --git a/Text/Trifecta/Parser/Class.hs b/Text/Trifecta/Parser/Class.hs
--- a/Text/Trifecta/Parser/Class.hs
+++ b/Text/Trifecta/Parser/Class.hs
@@ -24,6 +24,7 @@
 import Control.Monad (MonadPlus(..))
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.State.Lazy as Lazy
+import Control.Monad.Trans.State.Strict as Strict
 import Data.ByteString as Strict
 import Data.Semigroup
 import Data.Set as Set
@@ -53,6 +54,17 @@
   satisfy = lift . satisfy
   try (Lazy.StateT m) = Lazy.StateT $ try . m
   labels (Lazy.StateT m) ss = Lazy.StateT $ \s -> labels (m s) ss
+  line = lift line
+  liftIt = lift . liftIt
+  mark = lift mark 
+  release = lift . release
+  unexpected = lift . unexpected
+  satisfyAscii = lift . satisfyAscii
+
+instance MonadParser m => MonadParser (Strict.StateT s m) where
+  satisfy = lift . satisfy
+  try (Strict.StateT m) = Strict.StateT $ try . m
+  labels (Strict.StateT m) ss = Strict.StateT $ \s -> labels (m s) ss
   line = lift line
   liftIt = lift . liftIt
   mark = lift mark 
diff --git a/Text/Trifecta/Parser/Token.hs b/Text/Trifecta/Parser/Token.hs
deleted file mode 100644
--- a/Text/Trifecta/Parser/Token.hs
+++ /dev/null
@@ -1,374 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Text.Trifecta.Parser.Token
--- Copyright   :  (c) Edward Kmett 2011,
---                (c) Daan Leijen 1999-2001
--- License     :  BSD3
--- 
--- Maintainer  :  ekmett@gmail.com
--- Stability   :  provisional
--- Portability :  non-portable
--- 
------------------------------------------------------------------------------
-module Text.Trifecta.Parser.Token
-  ( identifier
-  , reserved
-  , operator
-  , reservedOp
-  , charLiteral
-  , stringLiteral
-  , natural
-  , integer
-  , double
-  , naturalOrDouble
-  , decimal
-  , hexadecimal
-  , octal
-  , symbol
-  , symbolic
-  , lexeme
-  , parens
-  , braces
-  , angles
-  , brackets
-  , semi
-  , comma
-  , colon
-  , dot
-  , semiSep
-  , semiSep1
-  , commaSep
-  , commaSep1
-  ) where
-
-import Data.Char (digitToInt)
-import Data.ByteString as Strict hiding (map, zip, foldl, foldr)
-import Control.Applicative
-import Control.Monad (when)
-import Text.Trifecta.Parser.Class
-import Text.Trifecta.Parser.Char
-import Text.Trifecta.Parser.Combinators
-import Text.Trifecta.Parser.Token.Class
-
--- | This lexeme parser parses a legal identifier. Returns the identifier
--- string. This parser will fail on identifiers that are reserved
--- words. Legal identifier (start) characters and reserved words are
--- defined in the 'LanguageDef' that is passed to
--- 'makeTokenParser'. An @identifier@ is treated as
--- a single token using 'try'.
-identifier :: MonadTokenParser m => m ByteString
-identifier = lexeme $ try $ do 
-  name <- sliced ident 
-  b <- isReservedName name
-  when b $ unexpected $ "reserved word " ++ show name
-  return name
-  where 
-    ident = identStart *> skipMany identLetter
-        <?> "identifier"
-
--- | The lexeme parser @reserved name@ parses @symbol 
--- name@, but it also checks that the @name@ is not a prefix of a
--- valid identifier. A @reserved@ word is treated as a single token
--- using 'try'. 
-reserved :: MonadTokenParser m => ByteString -> m ()
-reserved name = lexeme $ try $ do
-  _ <- byteString name
-  notFollowedBy identLetter <?> "end of " ++ show name
-
--- | This lexeme parser parses a legal operator. Returns the name of the
--- operator. This parser will fail on any operators that are reserved
--- operators. Legal operator (start) characters and reserved operators
--- are defined in the 'LanguageDef' that is passed to
--- 'makeTokenParser'. An @operator@ is treated as a
--- single token using 'try'. 
-operator :: MonadTokenParser m => m ByteString
-operator = lexeme $ try $ do
-  name <- sliced (opStart *> skipMany opLetter) <?> "operator"
-  b <- isReservedOpName name
-  when b $ unexpected $ "reserved operator " ++ show name
-  return name
-
--- |The lexeme parser @reservedOp name@ parses @symbol
--- name@, but it also checks that the @name@ is not a prefix of a
--- valid operator. A @reservedOp@ is treated as a single token using
--- 'try'. 
-reservedOp :: MonadTokenParser m => String -> m ()
-reservedOp name = lexeme $ try $ do
-   _ <- string name 
-   notFollowedBy opLetter <?> "end of " ++ show name
-
--- | This lexeme parser parses a single literal character. Returns the
--- literal character value. This parsers deals correctly with escape
--- sequences. The literal character is parsed according to the grammar
--- rules defined in the Haskell report (which matches most programming
--- languages quite closely). 
-charLiteral :: MonadTokenParser m => m Char
-charLiteral = lexeme (between (char '\'') (char '\'' <?> "end of character") characterChar)
-          <?> "character" 
-
-characterChar, charEscape, charLetter :: MonadTokenParser m => m Char
-characterChar = charLetter <|> charEscape
-            <?> "literal character"
-charEscape = char '\\' *> escapeCode
-charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))
-
--- | This lexeme parser parses a literal string. Returns the literal
--- string value. This parsers deals correctly with escape sequences and
--- gaps. The literal string is parsed according to the grammar rules
--- defined in the Haskell report (which matches most programming
--- languages quite closely). 
-
-stringLiteral :: MonadTokenParser m => m String
-stringLiteral = lexeme lit where
-  lit = foldr (maybe id (:)) "" <$> between (char '"') (char '"' <?> "end of string") (many stringChar) 
-    <?> "literal string"
-  stringChar = Just <$> stringLetter 
-           <|> stringEscape 
-       <?> "string character"
-  stringLetter    = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))
-
-  stringEscape = char '\\' *> esc where
-    esc = Nothing <$ escapeGap 
-      <|> Nothing <$ escapeEmpty 
-      <|> Just <$> escapeCode
-  escapeEmpty = char '&'
-  escapeGap = do skipSome space
-                 char '\\' <?> "end of string gap"
-
-escapeCode :: MonadTokenParser m => m Char
-escapeCode = (charEsc <|> charNum <|> charAscii <|> charControl) <?> "escape code"
-  where 
-  charControl = (\c -> toEnum (fromEnum c - fromEnum 'A')) <$> (char '^' *> upper)
-  charNum     = toEnum . fromInteger <$> num where
-    num = decimal 
-      <|> (char 'o' *> number 8 octDigit)
-      <|> (char 'x' *> number 16 hexDigit)
-  charEsc = choice $ parseEsc <$> escMap
-  parseEsc (c,code) = code <$ char c
-  escMap = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")
-  charAscii = choice $ parseAscii <$> asciiMap
-  parseAscii (asc,code) = try $ code <$ string asc
-  asciiMap = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)
-  ascii2codes, ascii3codes :: [String]
-  ascii2codes = [ "BS","HT","LF","VT","FF","CR","SO"
-                , "SI","EM","FS","GS","RS","US","SP"]
-  ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK"
-                ,"BEL","DLE","DC1","DC2","DC3","DC4","NAK"
-                ,"SYN","ETB","CAN","SUB","ESC","DEL"]
-  ascii2, ascii3 :: [Char]
-  ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI'
-           ,'\EM','\FS','\GS','\RS','\US','\SP']
-  ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK'
-           ,'\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK'
-           ,'\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']
-  
-
--- | This lexeme parser parses a natural number (a positive whole
--- number). Returns the value of the number. The number can be
--- specified in 'decimal', 'hexadecimal' or
--- 'octal'. The number is parsed according to the grammar
--- rules in the Haskell report. 
-
-natural :: MonadTokenParser m => m Integer
-natural = lexeme nat <?> "natural"
-
-number :: MonadTokenParser m => Integer -> m Char -> m Integer
-number base baseDigit = do
-  digits <- some baseDigit
-  return $! foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits
-
--- | This lexeme parser parses an integer (a whole number). This parser
--- is like 'natural' except that it can be prefixed with
--- sign (i.e. \'-\' or \'+\'). Returns the value of the number. The
--- number can be specified in 'decimal', 'hexadecimal'
--- or 'octal'. The number is parsed according
--- to the grammar rules in the Haskell report. 
-        
-integer :: MonadTokenParser m => m Integer
-integer = lexeme int <?> "integer"
-
-sign :: MonadTokenParser m => m (Integer -> Integer)
-sign = negate <$ char '-'
-   <|> id <$ char '+'
-   <|> pure id
-
-nat, int, zeroNumber :: MonadTokenParser m => m Integer
-nat = zeroNumber <|> decimal
-int = lexeme sign <*> nat
-zeroNumber = char '0' *> (hexadecimal <|> octal <|> decimal <|> return 0) <?> ""
-
--- | This lexeme parser parses a floating point value. Returns the value
--- of the number. The number is parsed according to the grammar rules
--- defined in the Haskell report. 
-
-double :: MonadTokenParser m => m Double
-double = lexeme floating <?> "double"
-
-floating :: MonadTokenParser m => m Double
-floating = decimal >>= fractExponent
-
-fractExponent :: MonadTokenParser m => Integer -> m Double
-fractExponent n = (\fract expo -> (fromInteger n + fract) * expo) <$> fraction <*> option 1.0 exponent'
-              <|> (fromInteger n *) <$> exponent' where
-  fraction = foldr op 0.0 <$> (char '.' *> (some digit <?> "fraction"))
-  op d f = (f + fromIntegral (digitToInt d))/10.0
-  exponent' = do
-       _ <- oneOf "eE"
-       f <- sign
-       e <- decimal <?> "exponent"
-       return (power (f e))
-    <?> "exponent"
-  power e  
-    | e < 0     = 1.0/power(-e)
-    | otherwise = fromInteger (10^e)
-
--- | This lexeme parser parses either 'natural' or a 'float'.
--- Returns the value of the number. This parsers deals with
--- any overlap in the grammar rules for naturals and floats. The number
--- is parsed according to the grammar rules defined in the Haskell report. 
-
-naturalOrDouble :: MonadTokenParser m => m (Either Integer Double)
-naturalOrDouble = lexeme natDouble <?> "number"
-
-natDouble , zeroNumFloat, decimalFloat :: MonadTokenParser m => m (Either Integer Double)
-natDouble 
-    = char '0' *> zeroNumFloat
-  <|> decimalFloat
-zeroNumFloat
-    = Left <$> (hexadecimal <|> octal)
-  <|> decimalFloat
-  <|> fractFloat 0
-  <|> return (Left 0)
-decimalFloat = do 
-  n <- decimal
-  option (Left n) (fractFloat n)
-
-fractFloat :: MonadTokenParser m => Integer -> m (Either Integer Double)
-fractFloat n = Right <$> fractExponent n
-
--- | Parses a positive whole number in the decimal system. Returns the
--- value of the number. 
-
-decimal :: MonadTokenParser m => m Integer
-decimal = number 10 digit
-
--- | Parses a positive whole number in the hexadecimal system. The number
--- should be prefixed with \"0x\" or \"0X\". Returns the value of the
--- number. 
-
-hexadecimal :: MonadTokenParser m => m Integer
-hexadecimal = oneOf "xX" *> number 16 hexDigit
-
--- | Parses a positive whole number in the octal system. The number
--- should be prefixed with \"0o\" or \"0O\". Returns the value of the
--- number. 
-
-octal :: MonadTokenParser m => m Integer
-octal = oneOf "oO" *> number 8 octDigit
-
--- | Lexeme parser @symbol s@ parses 'string' @s@ and skips
--- trailing white space. 
-
-symbol :: MonadTokenParser m => ByteString -> m ByteString
-symbol name = lexeme (byteString name)
-
--- | Lexeme parser @symbolic s@ parses 'char' @s@ and skips
--- trailing white space. 
-
-symbolic :: MonadTokenParser m => Char -> m Char
-symbolic name = lexeme (char name)
-
--- | @lexeme p@ first applies parser @p@ and than the 'whiteSpace'
--- parser, returning the value of @p@. Every lexical
--- token (lexeme) is defined using @lexeme@, this way every parse
--- starts at a point without white space. Parsers that use @lexeme@ are
--- called /lexeme/ parsers in this document.
--- 
--- The only point where the 'whiteSpace' parser should be
--- called explicitly is the start of the main parser in order to skip
--- any leading white space.
---
--- >    mainParser  = do{ whiteSpace
--- >                     ; ds <- many (lexeme digit)
--- >                     ; eof
--- >                     ; return (sum ds)
--- >                     }
-
-lexeme :: MonadTokenParser m => m a -> m a
-lexeme p = p <* whiteSpace
-
--- | Lexeme parser @parens p@ parses @p@ enclosed in parenthesis,
--- returning the value of @p@.
-
-parens :: MonadTokenParser m => m a -> m a
-parens = between (symbolic '(') (symbolic ')')
-
-
--- | Lexeme parser @braces p@ parses @p@ enclosed in braces (\'{\' and
--- \'}\'), returning the value of @p@. 
-
-braces :: MonadTokenParser m => m a -> m a
-braces = between (symbolic '{') (symbolic '}')
-
--- | Lexeme parser @angles p@ parses @p@ enclosed in angle brackets (\'\<\'
--- and \'>\'), returning the value of @p@. 
-
-angles :: MonadTokenParser m => m a -> m a
-angles = between (symbolic '<') (symbolic '>')
-
--- | Lexeme parser @brackets p@ parses @p@ enclosed in brackets (\'[\'
--- and \']\'), returning the value of @p@. 
-
-brackets :: MonadTokenParser m => m a -> m a
-brackets = between (symbolic '<') (symbolic '>')
-
--- | Lexeme parser |semi| parses the character \';\' and skips any
--- trailing white space. Returns the string \";\". 
-
-semi :: MonadTokenParser m => m Char
-semi = symbolic ';'
-
--- | Lexeme parser @comma@ parses the character \',\' and skips any
--- trailing white space. Returns the string \",\". 
-
-comma :: MonadTokenParser m => m Char
-comma = symbolic ','
-
--- | Lexeme parser @colon@ parses the character \':\' and skips any
--- trailing white space. Returns the string \":\". 
-
-colon :: MonadTokenParser m => m Char
-colon = symbolic ':'
-
--- | Lexeme parser @dot@ parses the character \'.\' and skips any
--- trailing white space. Returns the string \".\". 
-
-dot :: MonadTokenParser m => m Char
-dot = symbolic '.'
-
--- | Lexeme parser @semiSep p@ parses /zero/ or more occurrences of @p@
--- separated by 'semi'. Returns a list of values returned by
--- @p@.
-
-semiSep :: MonadTokenParser m => m a -> m [a]
-semiSep p = sepBy p semi
-
--- | Lexeme parser @semiSep1 p@ parses /one/ or more occurrences of @p@
--- separated by 'semi'. Returns a list of values returned by @p@. 
-
-semiSep1 :: MonadTokenParser m => m a -> m [a]
-semiSep1 p = sepBy1 p semi
-
--- | Lexeme parser @commaSep p@ parses /zero/ or more occurrences of
--- @p@ separated by 'comma'. Returns a list of values returned
--- by @p@. 
-
-commaSep :: MonadTokenParser m => m a -> m [a]
-commaSep p = sepBy p comma
-
--- | Lexeme parser @commaSep1 p@ parses /one/ or more occurrences of
--- @p@ separated by 'comma'. Returns a list of values returned
--- by @p@. 
-
-commaSep1 :: MonadTokenParser m => m a -> m [a]
-commaSep1 p = sepBy p comma
diff --git a/Text/Trifecta/Parser/Token/Class.hs b/Text/Trifecta/Parser/Token/Class.hs
--- a/Text/Trifecta/Parser/Token/Class.hs
+++ b/Text/Trifecta/Parser/Token/Class.hs
@@ -13,9 +13,10 @@
   ( MonadTokenParser(..)
   ) where
 
+import Control.Applicative
 import Control.Monad.Trans.Class
-import Data.ByteString
 import Control.Monad.Trans.State.Lazy as Lazy
+import Control.Monad.Trans.State.Strict as Strict
 import Text.Trifecta.Parser.Class
 
 class MonadParser m => MonadTokenParser m where
@@ -24,37 +25,29 @@
   -- line) comment. Block comments may be nested. How comments are
   -- started and ended is defined by this method.
   whiteSpace       :: m ()
-
-  -- | This parser should accept any start characters of identifiers. For
-  -- example @letter \<|> char \"_\"@. 
-  identStart       :: m Char
-
-  -- | This parser should accept any legal tail characters of identifiers.
-  -- For example @alphaNum \<|> char \"_\"@. 
-  identLetter      :: m Char
-
-  -- | This parser should accept any start characters of operators. For
-  -- example @oneOf \":!#$%&*+.\/\<=>?\@\\\\^|-~\"@  
-  opStart          :: m Char
-
-  -- | This parser should accept any legal tail characters of operators.
-  -- Note that this parser should even be defined if the language doesn't
-  -- support user-defined operators, or otherwise the 'reservedOp'
-  -- parser won't work correctly.  
-  opLetter         :: m Char
-
-  -- | Check the list of reserved identifiers.  
-  isReservedName   :: ByteString -> m Bool
-
-  -- | Check the list of reserved operators. 
-  isReservedOpName :: ByteString -> m Bool
+  
+  -- | @lexeme p@ first applies parser @p@ and than the 'whiteSpace'
+  -- parser, returning the value of @p@. Every lexical
+  -- token (lexeme) is defined using @lexeme@, this way every parse
+  -- starts at a point without white space. Parsers that use @lexeme@ are
+  -- called /lexeme/ parsers in this document.
+  -- 
+  -- The only point where the 'whiteSpace' parser should be
+  -- called explicitly is the start of the main parser in order to skip
+  -- any leading white space.
+  --
+  -- >    mainParser  = do { whiteSpace
+  -- >                     ; ds <- many (lexeme digit)
+  -- >                     ; eof
+  -- >                     ; return (sum ds)
+  -- >                     }
+  lexeme :: m a -> m a
+  lexeme p = p <* whiteSpace
 
 instance MonadTokenParser m => MonadTokenParser (Lazy.StateT s m) where
   whiteSpace = lift whiteSpace
-  identStart = lift identStart
-  identLetter = lift identLetter
-  opStart = lift opStart
-  opLetter = lift opLetter
-  isReservedName = lift . isReservedName
-  isReservedOpName = lift . isReservedOpName
+  lexeme (Lazy.StateT m) = Lazy.StateT $ lexeme . m
 
+instance MonadTokenParser m => MonadTokenParser (Strict.StateT s m) where
+  whiteSpace = lift whiteSpace
+  lexeme (Strict.StateT m) = Strict.StateT $ lexeme . m
diff --git a/Text/Trifecta/Parser/Token/Combinators.hs b/Text/Trifecta/Parser/Token/Combinators.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Parser/Token/Combinators.hs
@@ -0,0 +1,302 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Trifecta.Parser.Token.Combinators
+-- Copyright   :  (c) Edward Kmett 2011,
+--                (c) Daan Leijen 1999-2001
+-- License     :  BSD3
+-- 
+-- Maintainer  :  ekmett@gmail.com
+-- Stability   :  provisional
+-- Portability :  non-portable
+-- 
+-----------------------------------------------------------------------------
+module Text.Trifecta.Parser.Token.Combinators
+  ( charLiteral
+  , stringLiteral
+  , natural
+  , integer
+  , double
+  , naturalOrDouble
+  , decimal
+  , hexadecimal
+  , octal
+  , symbol
+  , symbolic
+  , parens
+  , braces
+  , angles
+  , brackets
+  , semi
+  , comma
+  , colon
+  , dot
+  , semiSep
+  , semiSep1
+  , commaSep
+  , commaSep1
+  ) where
+
+import Data.Char (digitToInt)
+import Data.ByteString as Strict hiding (map, zip, foldl, foldr)
+import Control.Applicative
+import Text.Trifecta.Parser.Class
+import Text.Trifecta.Parser.Char
+import Text.Trifecta.Parser.Combinators
+import Text.Trifecta.Parser.Token.Class
+
+-- | This lexeme parser parses a single literal character. Returns the
+-- literal character value. This parsers deals correctly with escape
+-- sequences. The literal character is parsed according to the grammar
+-- rules defined in the Haskell report (which matches most programming
+-- languages quite closely). 
+charLiteral :: MonadTokenParser m => m Char
+charLiteral = lexeme (between (char '\'') (char '\'' <?> "end of character") characterChar)
+          <?> "character" 
+
+characterChar, charEscape, charLetter :: MonadTokenParser m => m Char
+characterChar = charLetter <|> charEscape
+            <?> "literal character"
+charEscape = char '\\' *> escapeCode
+charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))
+
+-- | This lexeme parser parses a literal string. Returns the literal
+-- string value. This parsers deals correctly with escape sequences and
+-- gaps. The literal string is parsed according to the grammar rules
+-- defined in the Haskell report (which matches most programming
+-- languages quite closely). 
+
+stringLiteral :: MonadTokenParser m => m String
+stringLiteral = lexeme lit where
+  lit = foldr (maybe id (:)) "" <$> between (char '"') (char '"' <?> "end of string") (many stringChar) 
+    <?> "literal string"
+  stringChar = Just <$> stringLetter 
+           <|> stringEscape 
+       <?> "string character"
+  stringLetter    = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))
+
+  stringEscape = char '\\' *> esc where
+    esc = Nothing <$ escapeGap 
+      <|> Nothing <$ escapeEmpty 
+      <|> Just <$> escapeCode
+  escapeEmpty = char '&'
+  escapeGap = do skipSome space
+                 char '\\' <?> "end of string gap"
+
+escapeCode :: MonadTokenParser m => m Char
+escapeCode = (charEsc <|> charNum <|> charAscii <|> charControl) <?> "escape code"
+  where 
+  charControl = (\c -> toEnum (fromEnum c - fromEnum 'A')) <$> (char '^' *> upper)
+  charNum     = toEnum . fromInteger <$> num where
+    num = decimal 
+      <|> (char 'o' *> number 8 octDigit)
+      <|> (char 'x' *> number 16 hexDigit)
+  charEsc = choice $ parseEsc <$> escMap
+  parseEsc (c,code) = code <$ char c
+  escMap = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")
+  charAscii = choice $ parseAscii <$> asciiMap
+  parseAscii (asc,code) = try $ code <$ string asc
+  asciiMap = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)
+  ascii2codes, ascii3codes :: [String]
+  ascii2codes = [ "BS","HT","LF","VT","FF","CR","SO"
+                , "SI","EM","FS","GS","RS","US","SP"]
+  ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK"
+                ,"BEL","DLE","DC1","DC2","DC3","DC4","NAK"
+                ,"SYN","ETB","CAN","SUB","ESC","DEL"]
+  ascii2, ascii3 :: [Char]
+  ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI'
+           ,'\EM','\FS','\GS','\RS','\US','\SP']
+  ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK'
+           ,'\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK'
+           ,'\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']
+  
+
+-- | This lexeme parser parses a natural number (a positive whole
+-- number). Returns the value of the number. The number can be
+-- specified in 'decimal', 'hexadecimal' or
+-- 'octal'. The number is parsed according to the grammar
+-- rules in the Haskell report. 
+
+natural :: MonadTokenParser m => m Integer
+natural = lexeme nat <?> "natural"
+
+number :: MonadTokenParser m => Integer -> m Char -> m Integer
+number base baseDigit = do
+  digits <- some baseDigit
+  return $! foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits
+
+-- | This lexeme parser parses an integer (a whole number). This parser
+-- is like 'natural' except that it can be prefixed with
+-- sign (i.e. \'-\' or \'+\'). Returns the value of the number. The
+-- number can be specified in 'decimal', 'hexadecimal'
+-- or 'octal'. The number is parsed according
+-- to the grammar rules in the Haskell report. 
+        
+integer :: MonadTokenParser m => m Integer
+integer = lexeme int <?> "integer"
+
+sign :: MonadTokenParser m => m (Integer -> Integer)
+sign = negate <$ char '-'
+   <|> id <$ char '+'
+   <|> pure id
+
+nat, int, zeroNumber :: MonadTokenParser m => m Integer
+nat = zeroNumber <|> decimal
+int = lexeme sign <*> nat
+zeroNumber = char '0' *> (hexadecimal <|> octal <|> decimal <|> return 0) <?> ""
+
+-- | This lexeme parser parses a floating point value. Returns the value
+-- of the number. The number is parsed according to the grammar rules
+-- defined in the Haskell report. 
+
+double :: MonadTokenParser m => m Double
+double = lexeme floating <?> "double"
+
+floating :: MonadTokenParser m => m Double
+floating = decimal >>= fractExponent
+
+fractExponent :: MonadTokenParser m => Integer -> m Double
+fractExponent n = (\fract expo -> (fromInteger n + fract) * expo) <$> fraction <*> option 1.0 exponent'
+              <|> (fromInteger n *) <$> exponent' where
+  fraction = foldr op 0.0 <$> (char '.' *> (some digit <?> "fraction"))
+  op d f = (f + fromIntegral (digitToInt d))/10.0
+  exponent' = do
+       _ <- oneOf "eE"
+       f <- sign
+       e <- decimal <?> "exponent"
+       return (power (f e))
+    <?> "exponent"
+  power e  
+    | e < 0     = 1.0/power(-e)
+    | otherwise = fromInteger (10^e)
+
+-- | This lexeme parser parses either 'natural' or a 'float'.
+-- Returns the value of the number. This parsers deals with
+-- any overlap in the grammar rules for naturals and floats. The number
+-- is parsed according to the grammar rules defined in the Haskell report. 
+
+naturalOrDouble :: MonadTokenParser m => m (Either Integer Double)
+naturalOrDouble = lexeme natDouble <?> "number"
+
+natDouble , zeroNumFloat, decimalFloat :: MonadTokenParser m => m (Either Integer Double)
+natDouble 
+    = char '0' *> zeroNumFloat
+  <|> decimalFloat
+zeroNumFloat
+    = Left <$> (hexadecimal <|> octal)
+  <|> decimalFloat
+  <|> fractFloat 0
+  <|> return (Left 0)
+decimalFloat = do 
+  n <- decimal
+  option (Left n) (fractFloat n)
+
+fractFloat :: MonadTokenParser m => Integer -> m (Either Integer Double)
+fractFloat n = Right <$> fractExponent n
+
+-- | Parses a positive whole number in the decimal system. Returns the
+-- value of the number. 
+
+decimal :: MonadTokenParser m => m Integer
+decimal = number 10 digit
+
+-- | Parses a positive whole number in the hexadecimal system. The number
+-- should be prefixed with \"0x\" or \"0X\". Returns the value of the
+-- number. 
+
+hexadecimal :: MonadTokenParser m => m Integer
+hexadecimal = oneOf "xX" *> number 16 hexDigit
+
+-- | Parses a positive whole number in the octal system. The number
+-- should be prefixed with \"0o\" or \"0O\". Returns the value of the
+-- number. 
+
+octal :: MonadTokenParser m => m Integer
+octal = oneOf "oO" *> number 8 octDigit
+
+-- | Lexeme parser @symbol s@ parses 'string' @s@ and skips
+-- trailing white space. 
+
+symbol :: MonadTokenParser m => ByteString -> m ByteString
+symbol name = lexeme (byteString name)
+
+-- | Lexeme parser @symbolic s@ parses 'char' @s@ and skips
+-- trailing white space. 
+
+symbolic :: MonadTokenParser m => Char -> m Char
+symbolic name = lexeme (char name)
+
+-- | Lexeme parser @parens p@ parses @p@ enclosed in parenthesis,
+-- returning the value of @p@.
+
+parens :: MonadTokenParser m => m a -> m a
+parens = between (symbolic '(') (symbolic ')')
+
+
+-- | Lexeme parser @braces p@ parses @p@ enclosed in braces (\'{\' and
+-- \'}\'), returning the value of @p@. 
+
+braces :: MonadTokenParser m => m a -> m a
+braces = between (symbolic '{') (symbolic '}')
+
+-- | Lexeme parser @angles p@ parses @p@ enclosed in angle brackets (\'\<\'
+-- and \'>\'), returning the value of @p@. 
+
+angles :: MonadTokenParser m => m a -> m a
+angles = between (symbolic '<') (symbolic '>')
+
+-- | Lexeme parser @brackets p@ parses @p@ enclosed in brackets (\'[\'
+-- and \']\'), returning the value of @p@. 
+
+brackets :: MonadTokenParser m => m a -> m a
+brackets = between (symbolic '<') (symbolic '>')
+
+-- | Lexeme parser |semi| parses the character \';\' and skips any
+-- trailing white space. Returns the string \";\". 
+
+semi :: MonadTokenParser m => m Char
+semi = symbolic ';'
+
+-- | Lexeme parser @comma@ parses the character \',\' and skips any
+-- trailing white space. Returns the string \",\". 
+
+comma :: MonadTokenParser m => m Char
+comma = symbolic ','
+
+-- | Lexeme parser @colon@ parses the character \':\' and skips any
+-- trailing white space. Returns the string \":\". 
+
+colon :: MonadTokenParser m => m Char
+colon = symbolic ':'
+
+-- | Lexeme parser @dot@ parses the character \'.\' and skips any
+-- trailing white space. Returns the string \".\". 
+
+dot :: MonadTokenParser m => m Char
+dot = symbolic '.'
+
+-- | Lexeme parser @semiSep p@ parses /zero/ or more occurrences of @p@
+-- separated by 'semi'. Returns a list of values returned by
+-- @p@.
+
+semiSep :: MonadTokenParser m => m a -> m [a]
+semiSep p = sepBy p semi
+
+-- | Lexeme parser @semiSep1 p@ parses /one/ or more occurrences of @p@
+-- separated by 'semi'. Returns a list of values returned by @p@. 
+
+semiSep1 :: MonadTokenParser m => m a -> m [a]
+semiSep1 p = sepBy1 p semi
+
+-- | Lexeme parser @commaSep p@ parses /zero/ or more occurrences of
+-- @p@ separated by 'comma'. Returns a list of values returned
+-- by @p@. 
+
+commaSep :: MonadTokenParser m => m a -> m [a]
+commaSep p = sepBy p comma
+
+-- | Lexeme parser @commaSep1 p@ parses /one/ or more occurrences of
+-- @p@ separated by 'comma'. Returns a list of values returned
+-- by @p@. 
+
+commaSep1 :: MonadTokenParser m => m a -> m [a]
+commaSep1 p = sepBy p comma
diff --git a/Text/Trifecta/Parser/Token/Prim.hs b/Text/Trifecta/Parser/Token/Prim.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Parser/Token/Prim.hs
@@ -0,0 +1,71 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Trifecta.Parser.Token.Prim
+-- Copyright   :  (c) Edward Kmett 2011
+-- License     :  BSD3
+-- 
+-- Maintainer  :  ekmett@gmail.com
+-- Stability   :  provisional
+-- Portability :  non-portable
+-- 
+-----------------------------------------------------------------------------
+module Text.Trifecta.Parser.Token.Prim
+  ( CommentStyle(..)
+  , emptyCommentStyle
+  , javaCommentStyle
+  , haskellCommentStyle
+  , buildWhiteSpaceParser
+  ) where
+
+import Data.Char (isSpace)
+import Control.Applicative
+import Data.List (nub)
+import Text.Trifecta.Parser.Class
+import Text.Trifecta.Parser.Char
+import Text.Trifecta.Parser.Combinators
+
+data CommentStyle = CommentStyle 
+  { commentStart   :: String
+  , commentEnd     :: String
+  , commentLine    :: String
+  , commentNesting :: Bool
+  } 
+
+emptyCommentStyle, javaCommentStyle, haskellCommentStyle :: CommentStyle
+emptyCommentStyle   = CommentStyle "" "" "" True
+javaCommentStyle    = CommentStyle "/*" "*/" "//" True
+haskellCommentStyle = CommentStyle "{-" "-}" "--" True
+
+-- | Use this to easily build the definition of whiteSpace for your MonadTokenParser
+buildWhiteSpaceParser :: MonadParser m => CommentStyle -> m ()
+buildWhiteSpaceParser (CommentStyle startStyle endStyle lineStyle nestingStyle)
+  | noLine && noMulti  = skipMany (simpleSpace <?> "")
+  | noLine             = skipMany (simpleSpace <|> multiLineComment <?> "")
+  | noMulti            = skipMany (simpleSpace <|> oneLineComment <?> "")
+  | otherwise          = skipMany (simpleSpace <|> oneLineComment <|> multiLineComment <?> "")
+  where
+    noLine  = null lineStyle
+    noMulti = null startStyle
+    simpleSpace = skipSome (satisfy isSpace)
+    oneLineComment = do
+      _ <- try $ string lineStyle
+      skipMany (satisfyAscii (/= '\n')) -- TODO: use skipping/restOfLine and fiddle with the last byte
+      return ()
+    multiLineComment = do
+      _ <- try $ string startStyle
+      inComment
+    inComment
+      | nestingStyle = inCommentMulti
+      | otherwise    = inCommentSingle
+    inCommentMulti
+      =   () <$ try (string endStyle)
+      <|> multiLineComment *> inCommentMulti
+      <|> skipSome (noneOf startEnd) *> inCommentMulti
+      <|> oneOf startEnd *> inCommentMulti
+      <?> "end of comment"
+    startEnd = nub (endStyle ++ startStyle)
+    inCommentSingle
+      =   () <$ try (string endStyle)
+      <|> skipSome (noneOf startEnd) *> inCommentSingle
+      <|> oneOf startEnd *> inCommentSingle
+      <?> "end of comment"
diff --git a/Text/Trifecta/Parser/Token/Style.hs b/Text/Trifecta/Parser/Token/Style.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Parser/Token/Style.hs
@@ -0,0 +1,98 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Trifecta.Parser.Token.Style
+-- Copyright   :  (c) Edward Kmett 2011
+-- License     :  BSD3
+-- 
+-- Maintainer  :  ekmett@gmail.com
+-- Stability   :  provisional
+-- Portability :  non-portable
+-- 
+-----------------------------------------------------------------------------
+module Text.Trifecta.Parser.Token.Style
+  ( Style(..)
+ 
+  -- identifier styles
+  , emptyIdents, haskellIdents, haskell98Idents
+
+  -- operator styles
+  , emptyOps, haskellOps, haskell98Ops
+
+  -- reading identifiers
+  , ident
+  , reserved
+  , reservedByteString
+  ) where
+
+import Data.ByteString as Strict hiding (map, zip, foldl, foldr)
+import Data.ByteString.UTF8 as UTF8
+import Data.HashSet as HashSet
+import Data.Monoid
+import Control.Applicative
+import Control.Monad (when)
+import Text.Trifecta.Parser.Class
+import Text.Trifecta.Parser.Char
+import Text.Trifecta.Parser.Combinators
+import Text.Trifecta.Parser.Token.Class
+
+data Style m = Style
+  { styleName         :: String
+  , styleStart        :: m ()
+  , styleLetter       :: m ()
+  , styleReserved     :: HashSet ByteString
+  }
+
+-- | parse a reserved operator or identifier
+reserved :: MonadTokenParser m => Style m -> String -> m ()
+reserved s name = reservedByteString s $! UTF8.fromString name
+
+-- | parse a reserved operator or identifier specified by bytestring
+reservedByteString :: MonadTokenParser m => Style m -> ByteString -> m ()
+reservedByteString s name = lexeme $ try $ do
+   _ <- byteString name 
+   notFollowedBy (styleLetter s) <?> "end of " ++ show name
+
+-- | parse an non-reserved identifier or symbol
+ident :: MonadTokenParser m => Style m -> m ByteString
+ident s = lexeme $ try $ do
+  name <- sliced (styleStart s *> skipMany (styleLetter s)) <?> styleName s
+  when (member name (styleReserved s)) $ unexpected $ "reserved " ++ styleName s ++ " " ++ show name
+  return name
+
+set :: [String] -> HashSet ByteString
+set = HashSet.fromList . fmap UTF8.fromString
+
+emptyOps, haskell98Ops, haskellOps :: MonadTokenParser m => Style m
+emptyOps = Style
+  { styleName     = "operator"
+  , styleStart    = styleLetter emptyOps
+  , styleLetter   = () <$ oneOf ":!#$%&*+./<=>?@\\^|-~"
+  , styleReserved = mempty
+  }
+haskell98Ops = emptyOps 
+  { styleReserved = set ["::","..","=","\\","|","<-","->","@","~","=>"]
+  }
+haskellOps = haskell98Ops
+
+emptyIdents, haskell98Idents, haskellIdents :: MonadTokenParser m => Style m
+emptyIdents = Style
+  { styleName     = "identifier"
+  , styleStart    = () <$ (letter <|> char '_')
+  , styleLetter   = () <$ (alphaNum <|> oneOf "_'")
+  , styleReserved = set [] }
+
+haskell98Idents = emptyIdents
+  { styleReserved = set haskell98ReservedIdents }
+haskellIdents = haskell98Idents
+  { styleLetter	  = styleLetter haskell98Idents <|> () <$ char '#'
+  , styleReserved = set $ haskell98ReservedIdents ++
+      ["foreign","import","export","primitive","_ccall_","_casm_" ,"forall"]
+  }
+
+haskell98ReservedIdents :: [String]
+haskell98ReservedIdents = 
+  ["let","in","case","of","if","then","else","data","type"
+  ,"class","default","deriving","do","import","infix"
+  ,"infixl","infixr","instance","module","newtype"
+  ,"where","primitive" -- "as","qualified","hiding"
+  ]
diff --git a/trifecta.cabal b/trifecta.cabal
--- a/trifecta.cabal
+++ b/trifecta.cabal
@@ -1,6 +1,6 @@
 name:          trifecta
 category:      Text, Parsing, Diagnostics, Pretty Printer, Logging
-version:       0.15.1
+version:       0.16
 license:       BSD3
 cabal-version: >= 1.6
 license-file:  LICENSE
@@ -34,8 +34,10 @@
     Text.Trifecta.Parser.Result
     Text.Trifecta.Parser.Combinators
     Text.Trifecta.Parser.Step
-    Text.Trifecta.Parser.Token
     Text.Trifecta.Parser.Token.Class
+    Text.Trifecta.Parser.Token.Combinators
+    Text.Trifecta.Parser.Token.Prim
+    Text.Trifecta.Parser.Token.Style
     Text.Trifecta.Parser.Expr
     Text.Trifecta.Path
     Text.Trifecta.Render.Prim
@@ -52,25 +54,26 @@
   ghc-options: -Wall
 
   build-depends: 
-    base               >= 4       && < 5,
-    array              >= 0.3.0.2 && < 0.4, 
-    containers         >= 0.3     && < 0.5,
-    bifunctors         >= 0.1.1.3 && < 0.2,
-    intern             >= 0.5.1.1 && < 0.6,
-    hashable           >= 1.1.2.1 && < 1.2,
-    bytestring         >= 0.9.1   && < 0.10,
-    mtl                >= 2.0.1   && < 2.1,
-    semigroups         >= 0.7.1   && < 0.8, 
-    fingertree         >= 0.0.1   && < 0.1,
-    reducers           >= 0.1.2   && < 0.2,
-    profunctors        >= 0.1.1   && < 0.2,
-    parsec             >= 3.1.1   && < 3.2,
-    utf8-string        >= 0.3.6   && < 0.4,
-    semigroupoids      >= 1.2.4   && < 1.3,
-    parallel           >= 3.1.0.1 && < 3.2,
-    transformers       >= 0.2.2   && < 0.3,
-    comonad            >= 1.1.1   && < 1.2,
-    terminfo           >= 0.3.2   && < 0.4,
-    keys               >= 2.0.1   && < 2.1,
-    wl-pprint-extras   >= 1.4     && < 1.5,
-    wl-pprint-terminfo >= 0.4     && < 0.5
+    base                 >= 4       && < 5,
+    array                >= 0.3.0.2 && < 0.4, 
+    containers           >= 0.3     && < 0.5,
+    unordered-containers >= 0.1.4   && < 0.2,
+    bifunctors           >= 0.1.1.3 && < 0.2,
+    intern               >= 0.5.1.1 && < 0.6,
+    hashable             >= 1.1.2.1 && < 1.2,
+    bytestring           >= 0.9.1   && < 0.10,
+    mtl                  >= 2.0.1   && < 2.1,
+    semigroups           >= 0.7.1   && < 0.8, 
+    fingertree           >= 0.0.1   && < 0.1,
+    reducers             >= 0.1.2   && < 0.2,
+    profunctors          >= 0.1.1   && < 0.2,
+    parsec               >= 3.1.1   && < 3.2,
+    utf8-string          >= 0.3.6   && < 0.4,
+    semigroupoids        >= 1.2.4   && < 1.3,
+    parallel             >= 3.1.0.1 && < 3.2,
+    transformers         >= 0.2.2   && < 0.3,
+    comonad              >= 1.1.1   && < 1.2,
+    terminfo             >= 0.3.2   && < 0.4,
+    keys                 >= 2.0.1   && < 2.1,
+    wl-pprint-extras     >= 1.4     && < 1.5,
+    wl-pprint-terminfo   >= 0.4     && < 0.5
