diff --git a/HaTeX.cabal b/HaTeX.cabal
--- a/HaTeX.cabal
+++ b/HaTeX.cabal
@@ -1,5 +1,5 @@
 Name: HaTeX
-Version: 3.12.0.0
+Version: 3.13.0.0
 Author: Daniel Díaz
 Category: Text, LaTeX
 Build-type: Simple
@@ -45,13 +45,15 @@
   Default-language: Haskell2010
   Build-depends: base == 4.*
                , bytestring >= 0.9.2.1 && < 0.11
-               , transformers >= 0.2.2 && < 0.5
                , text >= 0.11.2.3 && < 2
-               , attoparsec >= 0.10.2 && < 0.12
-               , matrix
+               , transformers >= 0.2.2 && < 0.5
                , containers >= 0.4.2.1 && < 0.6
+               , matrix
+                 -- Testing
                , QuickCheck
-                 -- For pretty-printing
+                 -- Parsing
+               , parsec >= 3.1
+                 -- Pretty-printing
                , wl-pprint-extras >= 3.5
   Exposed-modules:
     Text.LaTeX
diff --git a/Text/LaTeX/Base/Parser.hs b/Text/LaTeX/Base/Parser.hs
--- a/Text/LaTeX/Base/Parser.hs
+++ b/Text/LaTeX/Base/Parser.hs
@@ -1,67 +1,84 @@
-{-# LANGUAGE CPP #-}
+
 {-# LANGUAGE OverloadedStrings #-}
--------------------------------------------------------------------------------
--- |
--- Module     : Text/LaTeX/Base/Parser.hs
--- Copyright  : (c) Tobias Schoofs
--- License    : LGPL 
--- Stability  : experimental
--- Portability: portable
+
+-- | The /LaTeX/ parser.
+-- 
+--   Use 'parseLaTeX' to parse a 'Text' containing /LaTeX/ code.
+--   If the 'Text' is in a file, you may want to use 'parseLaTeXFile'.
+--   Use this module together with "Text.LaTeX.Base.Syntax" to perform
+--   analysis and transformations of /LaTeX/ code. The parser ('parseLaTeX')
+--   is related with the renderer ('render') by the following property:
 --
--- LaTeX Parser based on Attoparsec
--------------------------------------------------------------------------------
+--   /If @t :: Text@ is a syntactically valid LaTeX block, then:/
+--
+-- > fmap render (parseLaTeX t) == Right t
+-- 
+--   This property says two things:
+--
+-- * Given a valid LaTeX input, 'parseLaTeX' returns a 'LaTeX' value.
+-- * If the parsed value is again rendered, you get the initial input.
+--
+--   In other words, 'parseLaTeX' is a partial function defined over the
+--   set of valid LaTeX files, and 'render' is its inverse.
+--
 module Text.LaTeX.Base.Parser (
+    -- * The parser
     parseLaTeX
+  , parseLaTeXFile
   , latexParser
   , latexBlockParser
-  , latexAtOnce
-#ifdef _TEST
-  , specials
-#endif
+    -- * Parsing errors
+  , ParseError
+  , errorPos
+  , errorMessages
+    -- ** Error messages
+  , Message (..)
+  , messageString
+    -- ** Source positions
+  , SourcePos
+  , sourceLine
+  , sourceColumn
+  , sourceName
     ) where
 
-import           Data.Attoparsec.Text hiding (take, takeTill)
-import qualified Data.Attoparsec.Text as A   (takeTill)
-import           Data.Char (toLower)
+import           Text.Parsec hiding ((<|>),many)
+import           Text.Parsec.Text
+import           Text.Parsec.Error
+import           Data.Char (toLower,digitToInt)
 import           Data.Monoid
 import           Data.Maybe (fromMaybe)
-import           Data.Text (Text)
 import qualified Data.Text as T 
 
-import           Control.Applicative ((<|>), (<$>),many)
+import           Control.Applicative
 import           Control.Monad (unless)
 
 import           Text.LaTeX.Base.Syntax
+import           Text.LaTeX.Base.Render
 
 -- | Parse a 'Text' sequence as a 'LaTeX' block. If it fails, it returns
 --   an error string.
-parseLaTeX :: Text -> Either String LaTeX
+parseLaTeX :: Text -> Either ParseError LaTeX
 parseLaTeX t | T.null t  = return TeXEmpty
-             | otherwise = 
-  case parse latexParser t of
-    Fail _ _ e     -> Left e
-    Done _ r       -> Right r
-    rx@(Partial _) -> -- Left "incomplete input"
-                      case feed rx T.empty of
-                        Fail _ _ e -> Left e
-                        Partial _  -> Left "incomplete input"
-                        Done _ r   -> Right r
-
-{-# DEPRECATED latexAtOnce "Use parseLaTeX instead." #-}
+             | otherwise = parse latexParser "parseLaTeX input" t
 
--- | Same as 'parseLaTeX'.
-latexAtOnce :: Text -> Either String LaTeX
-latexAtOnce = parseLaTeX
+-- | Read a file and parse it as 'LaTeX'.
+parseLaTeXFile :: FilePath -> IO (Either ParseError LaTeX)
+parseLaTeXFile fp = parse latexParser fp <$> readFileTex fp
 
-------------------------------------------------------------------------
--- | Incremental 'LaTeX' parser.
-------------------------------------------------------------------------
+-- | The 'LaTeX' parser.
 latexParser :: Parser LaTeX
-latexParser = mconcat <$> latexBlockParser `manyTill` endOfInput 
+latexParser = mconcat <$> latexBlockParser `manyTill` eof
 
 -- | Parser of a single 'LaTeX' constructor, no appending blocks.
 latexBlockParser :: Parser LaTeX
-latexBlockParser = foldr1 (<|>) [text, dolMath, comment, text2, environment, command]
+latexBlockParser = foldr1 (<|>)
+  [ text            <?> "text"
+  , dolMath         <?> "inline math ($)"
+  , comment         <?> "comment"
+  , text2           <?> "text2"
+  , try environment <?> "environment"
+  , command         <?> "command"
+    ]
 -- Note: text stops on ']'; if the other parsers fail on the rest
 --       text2 handles it, starting with ']' 
   
@@ -74,7 +91,7 @@
   case mbC of
     Nothing -> fail "text: Empty input."
     Just c | c `elem` "$%\\{]}" -> fail "not text"
-           | otherwise          -> TeXRaw <$> A.takeTill (`elem` "$%\\{]}")
+           | otherwise          -> TeXRaw <$> takeTill (`elem` "$%\\{]}")
 
 ------------------------------------------------------------------------
 -- Text without stopping on ']'
@@ -92,41 +109,43 @@
 environment = anonym <|> env
 
 anonym :: Parser LaTeX
-anonym = char '{' >> 
-    TeXBraces . mconcat <$> latexBlockParser `manyTill` char '}'
+anonym = do
+  _ <- char '{'
+  l <- TeXBraces . mconcat <$> many latexBlockParser
+  _ <- char '}'
+  return l
 
 env :: Parser LaTeX
 env = do
-  _  <- char '\\'
-  n  <- envName "begin"
+  n  <- char '\\' *> envName "begin"
   sps <- many $ char ' '
   let lsps = if null sps then mempty else TeXRaw $ T.pack sps
   as <- cmdArgs
   b  <- envBody n 
-  return $ TeXEnv (T.unpack n) (fromMaybe [] as) $
+  return $ TeXEnv n (fromMaybe [] as) $
     case as of
      Just [] -> lsps <> TeXBraces mempty <> b
      Nothing -> lsps <> b
      _ -> b
 
-envName :: Text -> Parser Text
+envName :: String -> Parser String
 envName k = do
   _ <- string k
   _ <- char '{'
-  n <- A.takeTill (== '}')
+  n <- takeTill (== '}')
   _ <- char '}'
-  return n
+  return $ T.unpack n
 
-envBody :: Text -> Parser LaTeX
+envBody :: String -> Parser LaTeX
 envBody n = mconcat <$> (bodyBlock n) `manyTill` endenv
-  where endenv = try $ string ("\\end") >> skipSpace >> string ("{" <> n <> "}")
+  where endenv = try $ string ("\\end") >> spaces >> string ("{" <> n <> "}")
 
-bodyBlock :: Text -> Parser LaTeX
+bodyBlock :: String -> Parser LaTeX
 bodyBlock n = do
   c <- peekChar
   case c of 
      Just _ -> latexBlockParser
-     _ -> fail $ "Environment '" <> T.unpack n <> "' not finalized."
+     _ -> fail $ "Environment '" <> n <> "' not finalized."
 
 ------------------------------------------------------------------------
 -- Command
@@ -140,7 +159,7 @@
     Just x  -> if isSpecial x
                   then special
                   else do
-                    c  <- A.takeTill endCmd
+                    c  <- takeTill endCmd
                     -- if c `elem` ["begin","end"]
                     --    then fail $ "Command not allowed: " ++ T.unpack c
                     --    else maybe (TeXCommS $ T.unpack c) (TeXComm $ T.unpack c) <$> cmdArgs
@@ -161,7 +180,7 @@
             '[' -> "]"
             '{' -> "}"
             _   -> error "this cannot happen!"
-  b <- mconcat <$> latexBlockParser `manyTill` string e
+  b <- mconcat <$> manyTill latexBlockParser (string e)
   case c of  
     '[' -> return $ OptArg b
     '{' -> return $ FixArg b
@@ -185,6 +204,7 @@
 ------------------------------------------------------------------------
 -- Line break
 ------------------------------------------------------------------------
+
 lbreak :: Parser LaTeX
 lbreak = do
   y <- try (char '[' <|> char '*' <|> return ' ')  
@@ -197,13 +217,13 @@
     _   -> return (TeXLineBreak Nothing False)
 
 linebreak :: Bool -> Parser LaTeX
-linebreak t = do m <- measure
+linebreak t = do m <- measure <?> "measure"
                  _ <- char ']'
                  s <- try (char '*' <|> return ' ')
                  return $ TeXLineBreak (Just m) (t || s == '*')
 
 measure :: Parser Measure
-measure = try (double >>= unit) <|> CustomMeasure <$> latexBlockParser
+measure = try (floating >>= unit) <|> (CustomMeasure . mconcat) <$> manyTill latexBlockParser (lookAhead $ char ']')
 
 unit :: Double -> Parser Measure
 unit f = do
@@ -241,7 +261,7 @@
   b <- mconcat <$> latexBlockParser `manyTill` char '$'
   return $ TeXMath Dollar b
 
-math :: MathType -> Text -> Parser LaTeX
+math :: MathType -> String -> Parser LaTeX
 math t eMath = do
    b <- mconcat <$> latexBlockParser `manyTill` try (string eMath)
    return $ TeXMath t b
@@ -252,7 +272,7 @@
 comment :: Parser LaTeX
 comment = do
   _  <- char '%'
-  c  <- A.takeTill (== '\n')
+  c  <- takeTill (== '\n')
   e  <- atEnd
   unless e (char '\n' >>= \_ -> return ())
   return $ TeXComment c
@@ -260,6 +280,7 @@
 ------------------------------------------------------------------------
 -- Helpers
 ------------------------------------------------------------------------
+
 isSpecial :: Char -> Bool
 isSpecial = (`elem` specials)
 
@@ -272,3 +293,40 @@
 
 specials :: String
 specials = "'(),.-\"!^$&#{}%~|/:;=[]\\` "
+
+peekChar :: Parser (Maybe Char)
+peekChar = Just <$> (try $ lookAhead anyChar) <|> pure Nothing
+
+atEnd :: Parser Bool
+atEnd = (eof *> pure True) <|> pure False
+
+takeTill :: (Char -> Bool) -> Parser Text
+takeTill p = T.pack <$> many (satisfy (not . p))
+
+-- Parsing doubles
+--
+-- Code for 'floating', 'fractExponent', and 'sign' comes from parsers package:
+--
+-- http://hackage.haskell.org/package/parsers
+--
+
+floating :: Parser Double
+floating = decimal <**> fractExponent
+
+fractExponent :: Parser (Integer -> Double)
+fractExponent = (\fract expo n -> (fromInteger n + fract) * expo) <$> fraction <*> option 1.0 exponent'
+            <|> (\expo n -> fromInteger n * expo) <$> exponent' where
+  fraction = foldr op 0.0 <$> (char '.' *> (some digit <?> "fraction"))
+  op d f = (f + fromIntegral (digitToInt d))/10.0
+  exponent' = ((\f e -> power (f e)) <$ oneOf "eE" <*> sign <*> (decimal <?> "exponent")) <?> "exponent"
+  power e
+    | e < 0     = 1.0/power(-e)
+    | otherwise = fromInteger (10^e)
+
+decimal :: Parser Integer
+decimal = read <$> many1 digit
+
+sign :: Parser (Integer -> Integer)
+sign = negate <$ char '-'
+   <|> id <$ char '+'
+   <|> pure id
diff --git a/Text/LaTeX/Base/Syntax.hs b/Text/LaTeX/Base/Syntax.hs
--- a/Text/LaTeX/Base/Syntax.hs
+++ b/Text/LaTeX/Base/Syntax.hs
@@ -256,7 +256,7 @@
 arbitraryChar = elements $
      ['A'..'Z']
   ++ ['a'..'z']
-  ++ "\n-+*/!\"$%&()[]{}^_.,:;'#@<>?\\ "
+  ++ "\n-+*/!\"$%&(){}^_.,:;'#@<>?\\ "
 
 -- | Utility for the instance of 'LaTeX' to 'Arbitrary'.
 --   We generate a short sequence of characters and
diff --git a/parsertest/parsertest.hs b/parsertest/parsertest.hs
--- a/parsertest/parsertest.hs
+++ b/parsertest/parsertest.hs
@@ -12,7 +12,7 @@
   t <- T.readFile $ "example" ++ show i ++ ".tex"
   case parseLaTeX t of
     Left err -> do putStrLn "Failed."
-                   putStrLn $ "The error was: " ++ err
+                   putStrLn $ "The error was: " ++ show err
                    return False
     Right _  -> putStrLn "Succeed." >> return True
 
@@ -23,4 +23,4 @@
   let b = and bs
   putStrLn $ "Parser Test Passed: " ++ show b
   if b then return ()
-       else putStrLn $ "Number of errors: " ++ show (length $ filter (==False) bs)
+       else putStrLn $ "Test result: " ++ show (length $ filter (==True) bs) ++ "/" ++ show (length bs)
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -6,6 +6,9 @@
 import qualified Test.Tasty.QuickCheck as QC
 import Test.QuickCheck
 
+instance Eq ParseError where
+  _ == _ = undefined
+
 main :: IO ()
 main = defaultMain $ testGroup "HaTeX"
   [ testGroup "LaTeX"
@@ -17,9 +20,7 @@
     ]
   , testGroup "Parser"
     [ QC.testProperty "render . parse = id" $
-         \l0 -> let t = render (l0 :: LaTeX)
-                in case parseLaTeX t of
-                     Left _ -> False
-                     Right l -> render l == t
+         \l -> let t = render (l :: LaTeX)
+               in  fmap render (parseLaTeX t) == Right t
     ]
   ]
