diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@
   * (1.18.1): fix incomplete pattern match
   * (1.18.2): bugfix for erroneous boolean intepretation of some macro
               expansions in #if clauses
+  * (1.18.3): further rewrites of the #if expression parser
 
 Version 1.17
 ------------
diff --git a/Language/Preprocessor/Cpphs/CppIfdef.hs b/Language/Preprocessor/Cpphs/CppIfdef.hs
--- a/Language/Preprocessor/Cpphs/CppIfdef.hs
+++ b/Language/Preprocessor/Cpphs/CppIfdef.hs
@@ -18,8 +18,8 @@
   ) where
 
 
+import Text.Parse
 import Language.Preprocessor.Cpphs.SymTab
-import Text.ParserCombinators.HuttonMeijer
 import Language.Preprocessor.Cpphs.Position  (Posn,newfile,newline,newlines
                                              ,cppline,cpp2hask,newpos)
 import Language.Preprocessor.Cpphs.ReadFirst (readFirst)
@@ -28,11 +28,12 @@
 import Language.Preprocessor.Cpphs.HashDefine(HashDefine(..),parseHashDefine
                                              ,expandMacro)
 import Language.Preprocessor.Cpphs.MacroPass (preDefine,defineMacro)
-import Data.Char      (isDigit)
-import Numeric   (readHex,readOct,readDec)
+import Data.Char        (isDigit,isSpace,isAlphaNum)
+import Data.List        (intercalate)
+import Numeric          (readHex,readOct,readDec)
 import System.IO.Unsafe (unsafeInterleaveIO)
 import System.IO        (hPutStrLn,stderr)
-import Control.Monad (when)
+import Control.Monad    (when)
 
 -- | Run a first pass of cpp, evaluating \#ifdef's and processing \#include's,
 --   whilst taking account of \#define's and \#undef's as we encounter them.
@@ -88,8 +89,8 @@
 	"undef"  -> skipn (deleteST sym syms) True (Keep ps) xs
 	"ifndef" -> skipn syms False (keepIf (not (definedST sym syms))) xs
 	"ifdef"  -> skipn syms False (keepIf      (definedST sym syms)) xs
-	"if"     -> skipn syms False
-                               (keepIf (gatherDefined p syms (unwords line))) xs
+	"if"     -> do b <- gatherDefined p syms (unwords line)
+                       skipn syms False (keepIf b) xs
 	"else"   -> skipn syms False (Drop 1 False ps) xs
 	"elif"   -> skipn syms False (Drop 1 True ps) xs
 	"endif"  | null ps ->
@@ -136,7 +137,7 @@
                  | otherwise = Drop n b ps
         dend     | n==1      = Keep (tail ps)
                  | otherwise = Drop (n-1) b (tail ps)
-        delif s  | n==1 && not b && gatherDefined p syms s
+        delif v  | n==1 && not b && v
                              = Keep ps
                  | otherwise = Drop n b ps
         skipn ud xs' =
@@ -146,10 +147,11 @@
     in
     if      cmd == "ifndef" ||
             cmd == "if"     ||
-            cmd == "ifdef"  then  skipn (Drop (n+1) b (p:ps)) xs
-    else if cmd == "elif"   then  skipn (delif (unwords (tail ws))) xs
-    else if cmd == "else"   then  skipn  delse xs
-    else if cmd == "endif"  then
+            cmd == "ifdef" then    skipn (Drop (n+1) b (p:ps)) xs
+    else if cmd == "elif"  then do v <- gatherDefined p syms (unwords (tail ws))
+                                   skipn (delif v) xs
+    else if cmd == "else"  then    skipn  delse xs
+    else if cmd == "endif" then
             if null ps then do hPutStrLn stderr $ "Unmatched #endif at "++show p
                                return []
                        else skipn  dend  xs
@@ -174,55 +176,130 @@
 
 
 ----
-gatherDefined :: Posn -> SymTab HashDefine -> String -> Bool
+gatherDefined :: Posn -> SymTab HashDefine -> String -> IO Bool
 gatherDefined p st inp =
-  case papply (parseBoolExp st) inp of
-    []      -> error ("Cannot parse #if directive in file "++show p)
-    [(b,_)] -> b
-    _       -> error ("Ambiguous parse for #if directive in file "++show p)
+  case runParser (preExpand st) inp of
+    (Left msg, _) -> error ("Cannot expand #if directive in file "++show p
+                           ++":\n    "++msg)
+    (Right s, xs) -> do
+--      hPutStrLn stderr $ "Expanded #if at "++show p++" is:\n  "++s
+        when (any (not . isSpace) xs) $
+             hPutStrLn stderr ("Warning: trailing characters after #if"
+                              ++" macro expansion in file "++show p++": "++xs)
 
-parseBoolExp :: SymTab HashDefine -> Parser Bool
-parseBoolExp st =
-  do  a <- parseExp1 st
-      (do skip (string "||")
-          b <- first (skip (parseBoolExp st))
-          return (a || b)
-       +++
-       do return a)
+        case runParser parseBoolExp s of
+          (Left msg, _) -> error ("Cannot parse #if directive in file "++show p
+                                 ++":\n    "++msg)
+          (Right b, xs) -> do when (any (not . isSpace) xs) $
+                                   hPutStrLn stderr
+                                     ("Warning: trailing characters after #if"
+                                      ++" directive in file "++show p++": "++xs)
+                              return b
 
-parseExp1 :: SymTab HashDefine -> Parser Bool
-parseExp1 st =
-  do  a <- parseExp0 st
-      (do skip (string "&&")
-          b <- first (skip (parseExp1 st))
-          return (a && b)
-       +++
-       do return a)
+-- | The preprocessor must expand all macros (recursively) before evaluating
+--   the conditional.
+preExpand :: SymTab HashDefine -> TextParser String
+preExpand st =
+  do  eof
+      return ""
+  <|>
+  do  a <- many1 (satisfy notIdent)
+      commit $ pure (a++) `apply` preExpand st
+  <|>
+  do  b <- expandSymOrCall st
+      commit $ pure (b++) `apply` preExpand st
 
-parseExp0 :: SymTab HashDefine -> Parser Bool
-parseExp0 st =
-  do  skip (string "defined")
-      sym <- parens parseSym
-      return (definedST sym st)
-  +++
-  do  ()  <- expandSymOrCall st
-      parseBoolExp st
-  +++
-  do  parens (parseBoolExp st)
-  +++
-  do  skip (char '!')
-      a <- parseExp0 st
+-- | Expansion of symbols.
+expandSymOrCall :: SymTab HashDefine -> TextParser String
+expandSymOrCall st =
+  do  sym <- parseSym
+      ( do  args <- parenthesis (commit $ fragment `sepBy` skip (isWord ","))
+            args' <- flip mapM args $ \arg->
+                         case runParser (preExpand st) arg of
+                             (Left msg, _) -> fail msg
+                             (Right s, _)  -> return s
+            convert sym args'
+        <|>
+        do  convert sym [] )
+  where
+    fragment = many1 (satisfy (`notElem`",)"))
+    convert "defined" [arg] =
+      case lookupST arg st of
+        Nothing | all isDigit arg    -> return arg 
+        Nothing                      -> return "0"
+        Just (a@AntiDefined{})       -> return "0"
+        Just (a@SymbolReplacement{}) -> return "1"
+        Just (a@MacroExpansion{})    -> return "1"
+    convert sym args =
+      case lookupST sym st of
+        Nothing  -> if null args then return sym
+                    else fail (disp sym args++" is not a defined macro")
+        Just (a@SymbolReplacement{}) -> do reparse (replacement a)
+                                           return ""
+        Just (a@MacroExpansion{})    -> do reparse (expandMacro a args False)
+                                           return ""
+        Just (a@AntiDefined{})       ->
+                    if null args then return sym
+                    else fail (disp sym args++" explicitly undefined with -U")
+    disp sym args = let len = length args
+                        chars = map (:[]) ['a'..'z']
+                    in sym ++ if null args then ""
+                              else "("++intercalate "," (take len chars)++")"
+
+parseBoolExp :: TextParser Bool
+parseBoolExp =
+  do  a <- parseExp1
+      bs <- many (do skip (isWord "||")
+                     commit $ skip parseBoolExp)
+      return $ foldr (||) a bs
+
+parseExp1 :: TextParser Bool
+parseExp1 =
+  do  a <- parseExp0
+      bs <- many (do skip (isWord "&&")
+                     commit $ skip parseExp1)
+      return $ foldr (&&) a bs
+
+parseExp0 :: TextParser Bool
+parseExp0 =
+  do  skip (isWord "!")
+      a <- commit $ parseExp0
       return (not a)
-  +++
-  do  sym1 <- skip parseSym
-      op   <- parseOp st
-      sym2 <- skip parseSym
-      return (op (safeRead sym1) (safeRead sym2))
-  +++
-  do  sym <- skip parseSym
-      case safeRead sym of
+  <|>
+  do  val1 <- parseArithExp1
+      op   <- parseCmpOp
+      val2 <- parseArithExp1
+      return (val1 `op` val2)
+  <|>
+  do  sym <- parseArithExp1
+      case sym of
         0 -> return False
         _ -> return True
+  <|>
+  do  parenthesis (commit parseBoolExp)
+
+parseArithExp1 :: TextParser Integer
+parseArithExp1 =
+  do  val1 <- parseArithExp0
+      ( do op   <- parseArithOp1
+           val2 <- parseArithExp1
+           return (val1 `op` val2)
+        <|> return val1 )
+  <|>
+  do  parenthesis parseArithExp1
+
+parseArithExp0 :: TextParser Integer
+parseArithExp0 =
+  do  val1 <- parseNumber
+      ( do op   <- parseArithOp0
+           val2 <- parseArithExp0
+           return (val1 `op` val2)
+        <|> return val1 )
+  <|>
+  do  parenthesis parseArithExp0
+
+parseNumber :: TextParser Integer
+parseNumber = fmap safeRead $ skip parseSym
   where
     safeRead s =
       case s of
@@ -234,50 +311,52 @@
         []        -> 0 :: Integer
         ((n,_):_) -> n :: Integer
 
-parseOp :: SymTab HashDefine -> Parser (Integer -> Integer -> Bool)
-parseOp _ =
-  do  skip (string ">=")
+parseCmpOp :: TextParser (Integer -> Integer -> Bool)
+parseCmpOp =
+  do  skip (isWord ">=")
       return (>=)
-  +++
-  do  skip (char '>')
+  <|>
+  do  skip (isWord ">")
       return (>)
-  +++
-  do  skip (string "<=")
+  <|>
+  do  skip (isWord "<=")
       return (<=)
-  +++
-  do  skip (char '<')
+  <|>
+  do  skip (isWord "<")
       return (<)
-  +++
-  do  skip (string "==")
+  <|>
+  do  skip (isWord "==")
       return (==)
-  +++
-  do  skip (string "!=")
+  <|>
+  do  skip (isWord "!=")
       return (/=)
 
--- | Fails if no expansion is required, to prevent infinite recursion.
-expandSymOrCall :: SymTab HashDefine -> Parser ()
-expandSymOrCall st =
-  do  sym <- skip parseSym
-      args <- parens (parseSymOrCall st `sepby` skip (char ','))
-      convert sym args
-  +++
-  do  sym <- skip parseSym
-      convert sym []
-  where
-    convert sym args =
-      case lookupST sym st of
-        Nothing  -> fail "not a macro"
-        Just (a@SymbolReplacement{}) -> reparse (replacement a)
-        Just (a@MacroExpansion{})    -> reparse (expandMacro a args False)
-        Just (a@AntiDefined{})       -> fail "anti-defined"
+parseArithOp1 :: TextParser (Integer -> Integer -> Integer)
+parseArithOp1 =
+  do  skip (isWord "+")
+      return (+)
+  <|>
+  do  skip (isWord "-")
+      return (-)
 
+parseArithOp0 :: TextParser (Integer -> Integer -> Integer)
+parseArithOp0 =
+  do  skip (isWord "*")
+      return (*)
+  <|>
+  do  skip (isWord "/")
+      return (div)
+  <|>
+  do  skip (isWord "%")
+      return (rem)
+
 -- | Return the expansion of the symbol (if there is one).
-parseSymOrCall :: SymTab HashDefine -> Parser String
+parseSymOrCall :: SymTab HashDefine -> TextParser String
 parseSymOrCall st =
   do  sym <- skip parseSym
-      args <- parens (parseSymOrCall st `sepby` skip (char ','))
+      args <- parenthesis (commit $ parseSymOrCall st `sepBy` skip (isWord ","))
       return $ convert sym args
-  +++
+  <|>
   do  sym <- skip parseSym
       return $ convert sym []
   where
@@ -290,14 +369,28 @@
 
 recursivelyExpand :: SymTab HashDefine -> String -> String
 recursivelyExpand st inp =
-  case papply (parseSymOrCall st) inp of
-    [(b,_)] -> b
-    _       -> inp
+  case runParser (parseSymOrCall st) inp of
+    (Left msg, _) -> inp
+    (Right s,  _) -> s
 
-parseSym :: Parser String
-parseSym = many1 (alphanum+++char '\''+++char '`')
+parseSym :: TextParser String
+parseSym = many1 (satisfy (\c-> isAlphaNum c || c`elem`"'`_"))
+           `onFail`
+           do xs <- allAsString
+              fail $ "Expected an identifier, got \""++xs++"\""
 
-parens p = bracket (skip (char '(')) (skip p) (skip (char ')'))
+notIdent :: Char -> Bool
+notIdent c = not (isAlphaNum c || c`elem`"'`_")
+
+skip :: TextParser a -> TextParser a
+skip p = many (satisfy isSpace) >> p
+
+-- | The standard "parens" parser does not work for us here.  Define our own.
+parenthesis :: TextParser a -> TextParser a
+parenthesis p = do isWord "("
+                   x <- p
+                   isWord ")"
+                   return x
 
 -- | Determine filename in \#include
 file :: SymTab HashDefine -> String -> String
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 LIBRARY = cpphs
-VERSION = 1.18.2
+VERSION = 1.18.3
 
 DIRS	= Language/Preprocessor/Cpphs \
 	  Text/ParserCombinators
@@ -15,7 +15,6 @@
           Language/Preprocessor/Cpphs/SymTab.hs \
           Language/Preprocessor/Cpphs/Tokenise.hs \
           Language/Preprocessor/Unlit.hs \
-          Text/ParserCombinators/HuttonMeijer.hs \
           cpphs.hs
 
 AUX	= README LICENCE* CHANGELOG $(LIBRARY).cabal Setup.hs Makefile \
diff --git a/Text/ParserCombinators/HuttonMeijer.hs b/Text/ParserCombinators/HuttonMeijer.hs
deleted file mode 100644
--- a/Text/ParserCombinators/HuttonMeijer.hs
+++ /dev/null
@@ -1,228 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  ParseLib
--- Copyright   :  ...
--- Copyright   :  Graham Hutton (University of Nottingham), Erik Meijer (University of Utrecht)
--- 
--- Maintainer  :  Malcolm Wallace <Malcolm.Wallace@cs.york.ac.uk>
--- Stability   :  Stable
--- Portability :  All
---
---                  A LIBRARY OF MONADIC PARSER COMBINATORS
--- 
---                               29th July 1996
--- 
---                  Graham Hutton               Erik Meijer
---             University of Nottingham    University of Utrecht
--- 
--- This Haskell script defines a library of parser combinators, and is
--- taken from sections 1-6 of our article "Monadic Parser Combinators".
--- Some changes to the library have been made in the move from Gofer
--- to Haskell:
--- 
---    * Do notation is used in place of monad comprehension notation;
--- 
---    * The parser datatype is defined using "newtype", to avoid the overhead
---      of tagging and untagging parsers with the P constructor.
------------------------------------------------------------------------------
-
-
-module Text.ParserCombinators.HuttonMeijer
-   (Parser(..), item, first, papply, (+++), sat, {-tok,-} many, many1,
-    sepby, sepby1, chainl,
-    chainl1, chainr, chainr1, ops, bracket, char, digit, lower, upper,
-    letter, alphanum, string, ident, nat, int, spaces, comment, junk,
-    skip, token, natural, integer, symbol, identifier, reparse) where
-
-import Data.Char
-import Control.Monad
-
-infixr 5 +++
-
-type Token = Char
-
----------------------------------------------------------
--- | The parser monad
-
-newtype Parser a   = P ([Token] -> [(a,[Token])])
-
-instance Functor Parser where
-   -- map         :: (a -> b) -> (Parser a -> Parser b)
-   fmap f (P p)    = P (\inp -> [(f v, out) | (v,out) <- p inp])
-
-instance Monad Parser where
-   -- return      :: a -> Parser a
-   return v        = P (\inp -> [(v,inp)])
-
-   -- >>=         :: Parser a -> (a -> Parser b) -> Parser b
-   (P p) >>= f     = P (\inp -> concat [papply (f v) out | (v,out) <- p inp])
-
-   -- fail        :: String -> Parser a
-   fail _          = P (\_ -> [])
-
-instance MonadPlus Parser where
-   -- mzero       :: Parser a
-   mzero           = P (\_ -> [])
-
-   -- mplus       :: Parser a -> Parser a -> Parser a
-   (P p) `mplus` (P q)  = P (\inp -> (p inp ++ q inp))
-
--- ------------------------------------------------------------
--- * Other primitive parser combinators
--- ------------------------------------------------------------
-
-item               :: Parser Token
-item                = P (\inp -> case inp of
-                                   []     -> []
-                                   (x:xs) -> [(x,xs)])
-
-first             :: Parser a -> Parser a
-first (P p)        = P (\inp -> case p inp of
-                                   []    -> []
-                                   (x:_) -> [x])
-
-papply            :: Parser a -> [Token] -> [(a,[Token])]
-papply (P p) inp   = p inp
-
--- ------------------------------------------------------------
--- * Derived combinators
--- ------------------------------------------------------------
-
-(+++)             :: Parser a -> Parser a -> Parser a
-p +++ q            = first (p `mplus` q)
-
-sat               :: (Token -> Bool) -> Parser Token
-sat p              = do {x <- item; if p x then return x else mzero}
-
---tok               :: Token -> Parser Token
---tok t              = do {x <- item; if t==snd x then return t else mzero}
-
-many              :: Parser a -> Parser [a]
-many p             = many1 p +++ return []
---many p           = force (many1 p +++ return [])
-
-many1             :: Parser a -> Parser [a]
-many1 p            = do {x <- p; xs <- many p; return (x:xs)}
-
-sepby             :: Parser a -> Parser b -> Parser [a]
-p `sepby` sep      = (p `sepby1` sep) +++ return []
-
-sepby1            :: Parser a -> Parser b -> Parser [a]
-p `sepby1` sep     = do {x <- p; xs <- many (do {sep; p}); return (x:xs)}
-
-chainl            :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
-chainl p op v      = (p `chainl1` op) +++ return v
-
-chainl1           :: Parser a -> Parser (a -> a -> a) -> Parser a
-p `chainl1` op     = do {x <- p; rest x}
-                     where
-                        rest x = do {f <- op; y <- p; rest (f x y)}
-                                 +++ return x
-
-chainr            :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
-chainr p op v      = (p `chainr1` op) +++ return v
-
-chainr1           :: Parser a -> Parser (a -> a -> a) -> Parser a
-p `chainr1` op     = do {x <- p; rest x}
-                     where
-                        rest x = do {f <- op; y <- p `chainr1` op; return (f x y)}
-                                 +++ return x
-
-ops               :: [(Parser a, b)] -> Parser b
-ops xs             = foldr1 (+++) [do {p; return op} | (p,op) <- xs]
-
-bracket           :: Parser a -> Parser b -> Parser c -> Parser b
-bracket open p close = do {open; x <- p; close; return x}
-
--- ------------------------------------------------------------
--- * Useful parsers
--- ------------------------------------------------------------
-
-char              :: Char -> Parser Char
-char x             = sat (\y -> x == y)
-
-digit             :: Parser Char
-digit              = sat isDigit
-
-lower             :: Parser Char
-lower              = sat isLower
-
-upper             :: Parser Char
-upper              = sat isUpper
-
-letter            :: Parser Char
-letter             = sat isAlpha
-
-alphanum          :: Parser Char
-alphanum           = sat isAlphaNum +++ char '_'
-
-string            :: String -> Parser String
-string ""          = return ""
-string (x:xs)      = do {char x; string xs; return (x:xs)}
-
-ident             :: Parser String
-ident              = do {x <- lower; xs <- many alphanum; return (x:xs)}
-
-nat               :: Parser Int
-nat                = do {x <- digit; return (fromEnum x - fromEnum '0')} `chainl1` return op
-                     where
-                        m `op` n = 10*m + n
-
-int               :: Parser Int
-int                = do {char '-'; n <- nat; return (-n)} +++ nat
-
--- ------------------------------------------------------------
--- * Lexical combinators
--- ------------------------------------------------------------
-
-spaces            :: Parser ()
-spaces             = do {many1 (sat isSpace); return ()}
-
-comment           :: Parser ()
---comment            = do {string "--"; many (sat (\x -> x /= '\n')); return ()}
---comment            = do 
---                       _ <- string "--"
---                       _ <- many (sat (\x -> x /= '\n'))
---                       return ()
-comment            = do
-                       bracket (string "/*") (many item) (string "*/")
-                       return ()
-
-junk              :: Parser ()
-junk               = do {many (spaces +++ comment); return ()}
-
-skip              :: Parser a -> Parser a
-skip p             = do {junk; p}
-
-token             :: Parser a -> Parser a
-token p            = do {v <- p; junk; return v}
-
--- ------------------------------------------------------------
--- * Token parsers
--- ------------------------------------------------------------
-
-natural           :: Parser Int
-natural            = token nat
-
-integer           :: Parser Int
-integer            = token int
-
-symbol            :: String -> Parser String
-symbol xs          = token (string xs)
-
-identifier        :: [String] -> Parser String
-identifier ks      = token (do {x <- ident;
-                                if not (elem x ks) then return x
-                                else return mzero})
-
---- Push some tokens back onto the input stream and reparse ------------------
-
--- | This is useful for recursively expanding macros.  When the
---   user-parser recognises a macro use, it can lookup the macro
---   expansion from the parse state, lex it, and then stuff the
---   lexed expansion back down into the parser.
-reparse    :: [Token] -> Parser ()
-reparse ts  = P (\inp-> [((), ts++inp)])
-
-------------------------------------------------------------------------------
-
diff --git a/cpphs.cabal b/cpphs.cabal
--- a/cpphs.cabal
+++ b/cpphs.cabal
@@ -1,5 +1,5 @@
 Name: cpphs
-Version: 1.18.2
+Version: 1.18.3
 Copyright: 2004-2014, Malcolm Wallace
 License: LGPL
 License-File: LICENCE-LGPL
@@ -23,21 +23,20 @@
 Extra-Source-Files: README, LICENCE-GPL, LICENCE-commercial, CHANGELOG, docs/cpphs.1, docs/index.html
 
 Library
-    Build-Depends: base>3&&<6, old-locale, old-time, directory
+    Build-Depends: base>3&&<6, old-locale, old-time, directory, polyparse>=1.9
     Exposed-Modules:
         Language.Preprocessor.Cpphs
         Language.Preprocessor.Unlit
     Other-Modules:
-        Language.Preprocessor.Cpphs.CppIfdef,
-        Language.Preprocessor.Cpphs.HashDefine,
-        Language.Preprocessor.Cpphs.MacroPass,
-        Language.Preprocessor.Cpphs.Options,
-        Language.Preprocessor.Cpphs.Position,
-        Language.Preprocessor.Cpphs.ReadFirst,
-        Language.Preprocessor.Cpphs.RunCpphs,
-        Language.Preprocessor.Cpphs.SymTab,
-        Language.Preprocessor.Cpphs.Tokenise,
-        Text.ParserCombinators.HuttonMeijer
+        Language.Preprocessor.Cpphs.CppIfdef
+        Language.Preprocessor.Cpphs.HashDefine
+        Language.Preprocessor.Cpphs.MacroPass
+        Language.Preprocessor.Cpphs.Options
+        Language.Preprocessor.Cpphs.Position
+        Language.Preprocessor.Cpphs.ReadFirst
+        Language.Preprocessor.Cpphs.RunCpphs
+        Language.Preprocessor.Cpphs.SymTab
+        Language.Preprocessor.Cpphs.Tokenise
 
 Executable cpphs
     Build-Depends: base>3&&<6, old-locale, old-time, directory
@@ -45,16 +44,15 @@
     Other-Modules:
         Language.Preprocessor.Cpphs
         Language.Preprocessor.Unlit
-        Language.Preprocessor.Cpphs.CppIfdef,
-        Language.Preprocessor.Cpphs.HashDefine,
-        Language.Preprocessor.Cpphs.MacroPass,
-        Language.Preprocessor.Cpphs.Options,
-        Language.Preprocessor.Cpphs.Position,
-        Language.Preprocessor.Cpphs.ReadFirst,
-        Language.Preprocessor.Cpphs.RunCpphs,
-        Language.Preprocessor.Cpphs.SymTab,
-        Language.Preprocessor.Cpphs.Tokenise,
-        Text.ParserCombinators.HuttonMeijer
+        Language.Preprocessor.Cpphs.CppIfdef
+        Language.Preprocessor.Cpphs.HashDefine
+        Language.Preprocessor.Cpphs.MacroPass
+        Language.Preprocessor.Cpphs.Options
+        Language.Preprocessor.Cpphs.Position
+        Language.Preprocessor.Cpphs.ReadFirst
+        Language.Preprocessor.Cpphs.RunCpphs
+        Language.Preprocessor.Cpphs.SymTab
+        Language.Preprocessor.Cpphs.Tokenise
 
 Source-Repository head
     Type:     darcs
diff --git a/cpphs.hs b/cpphs.hs
--- a/cpphs.hs
+++ b/cpphs.hs
@@ -20,7 +20,7 @@
 import Data.List   ( isPrefixOf )
 
 version :: String
-version = "1.18.1"
+version = "1.18.3"
 
 main :: IO ()
 main = do
diff --git a/docs/index.html b/docs/index.html
--- a/docs/index.html
+++ b/docs/index.html
@@ -198,12 +198,12 @@
 <b>Current stable version:</b>
 
 <p>
-cpphs-1.18.2, release date 2014.02.24<br>
+cpphs-1.18.3, release date 2014.03.03<br>
 By HTTP:
 <a href="http://hackage.haskell.org/package/cpphs">Hackage</a>.
 <ul>
-<li> bugfix for erroneous boolean interpretation of some macro
-     expansions in #if clauses
+<li> further rewrites of the #if expression parser, for better error messages,
+     support for integer operations, and fewer precedence bugs
 </ul>
 
 <p>
@@ -225,6 +225,15 @@
 
 <p>
 <b>Older versions:</b>
+
+<p>
+cpphs-1.18.2, release date 2014.02.24<br>
+By HTTP:
+<a href="http://hackage.haskell.org/package/cpphs">Hackage</a>.
+<ul>
+<li> bugfix for erroneous boolean interpretation of some macro
+     expansions in #if clauses
+</ul>
 
 <p>
 cpphs-1.18.1, release date 2014.02.18<br>
diff --git a/tests/booleanchain b/tests/booleanchain
new file mode 100644
--- /dev/null
+++ b/tests/booleanchain
@@ -0,0 +1,21 @@
+#define MIN_VERSION_base(x,y,z) (x>=4) && (y>=9) && (z>=0)
+This file tests the #if boolean expression parser/evaluator.
+#if !MIN_VERSION_base(4, 7, 0)
+SUCCEED with not and no parens
+#endif
+#if !(MIN_VERSION_base(4, 7, 0))
+SUCCEED with not and parens
+#endif
+
+Then we check for arithmetic.
+#define AT_LEAST_4(x) ((x)>=4)
+#if AT_LEAST_4(2+3)
+simple ARITHMETIC works
+#else
+simple ARITHMETIC broken
+#endif
+#if 2+3 > 4 && 1+12*2*1+2 == 27
+complex ARITHMETIC works
+#else
+complex ARITHMETIC broken
+#endif
diff --git a/tests/expect58 b/tests/expect58
new file mode 100644
--- /dev/null
+++ b/tests/expect58
@@ -0,0 +1,22 @@
+#line 1 "booleanchain"
+
+This file tests the #if boolean expression parser/evaluator.
+
+
+
+
+SUCCEED with not and parens
+
+
+Then we check for arithmetic.
+
+
+simple ARITHMETIC works
+
+
+
+
+complex ARITHMETIC works
+
+
+
diff --git a/tests/minversion b/tests/minversion
new file mode 100644
--- /dev/null
+++ b/tests/minversion
@@ -0,0 +1,13 @@
+#define MIN_VERSION_base(x,y,z) (x>=4) && (y>=5) && (z>=1)
+
+#if !(MIN_VERSION_base(4, 7, 0))
+import Data.Typeable     (Typeable2, typeOf2, mkTyConApp)
+version not 4.7.0
+#endif
+#if MIN_VERSION_base(4, 4, 0)
+import Data.Typeable     (mkTyCon3)
+version 4.4.0
+#else
+import Data.Typeable     (mkTyCon)
+version any
+#endif
diff --git a/tests/runtests b/tests/runtests
--- a/tests/runtests
+++ b/tests/runtests
@@ -75,4 +75,5 @@
 runtest "$CPPHS ballard" expect55
 runtest "$CPPHS th" expect56
 runtest "$CPPHS cheplyaka" expect57
+runtest "$CPPHS booleanchain" expect58
 exit $FAIL
