diff --git a/cimple.cabal b/cimple.cabal
--- a/cimple.cabal
+++ b/cimple.cabal
@@ -1,57 +1,57 @@
-name:                 cimple
-version:              0.0.17
-synopsis:             Simple C-like programming language
-homepage:             https://toktok.github.io/
-license:              GPL-3
-license-file:         LICENSE
-author:               Iphigenia Df <iphydf@gmail.com>
-maintainer:           Iphigenia Df <iphydf@gmail.com>
-copyright:            Copyright (c) 2016-2022, Iphigenia Df
-category:             Data
-stability:            Experimental
-cabal-version:        >= 1.10
-build-type:           Simple
+name:          cimple
+version:       0.0.18
+synopsis:      Simple C-like programming language
+homepage:      https://toktok.github.io/
+license:       GPL-3
+license-file:  LICENSE
+author:        Iphigenia Df <iphydf@gmail.com>
+maintainer:    Iphigenia Df <iphydf@gmail.com>
+copyright:     Copyright (c) 2016-2022, Iphigenia Df
+category:      Data
+stability:     Experimental
+cabal-version: >=1.10
+build-type:    Simple
 description:
   Parser and AST for Cimple, a simple C-like programming language.
 
 source-repository head
-  type:             git
-  location:         https://github.com/TokTok/hs-cimple
+  type:     git
+  location: https://github.com/TokTok/hs-cimple
 
 library
   default-language: Haskell2010
-  hs-source-dirs:
-      src
-  ghc-options:
-      -Wall
-  build-tools: alex, happy
+  hs-source-dirs:   src
+  ghc-options:      -Wall
+  build-tools:      alex >=0, happy >=0
   exposed-modules:
-      Language.Cimple
-    , Language.Cimple.Diagnostics
-    , Language.Cimple.IO
-    , Language.Cimple.MapAst
-    , Language.Cimple.Pretty
-    , Language.Cimple.Program
-    , Language.Cimple.TraverseAst
+    Language.Cimple
+    Language.Cimple.Diagnostics
+    Language.Cimple.IO
+    Language.Cimple.MapAst
+    Language.Cimple.Pretty
+    Language.Cimple.Program
+    Language.Cimple.TraverseAst
+
   other-modules:
-      Language.Cimple.Annot
-    , Language.Cimple.Ast
-    , Language.Cimple.CommentParser
-    , Language.Cimple.DescribeAst
-    , Language.Cimple.Flatten
-    , Language.Cimple.Graph
-    , Language.Cimple.Lexer
-    , Language.Cimple.ParseResult
-    , Language.Cimple.Parser
-    , Language.Cimple.SemCheck.Includes
-    , Language.Cimple.Tokens
-    , Language.Cimple.TranslationUnit
-    , Language.Cimple.TreeParser
+    Language.Cimple.Annot
+    Language.Cimple.Ast
+    Language.Cimple.CommentParser
+    Language.Cimple.DescribeAst
+    Language.Cimple.Flatten
+    Language.Cimple.Graph
+    Language.Cimple.Lexer
+    Language.Cimple.Parser
+    Language.Cimple.ParseResult
+    Language.Cimple.SemCheck.Includes
+    Language.Cimple.Tokens
+    Language.Cimple.TranslationUnit
+    Language.Cimple.TreeParser
+
   build-depends:
-      base < 5
-    , aeson
+      aeson
     , ansi-wl-pprint
     , array
+    , base                 <5
     , bytestring
     , containers
     , data-fix
@@ -65,74 +65,61 @@
 
 executable cimplefmt
   default-language: Haskell2010
-  hs-source-dirs:
-      tools
-  ghc-options:
-      -Wall
-  main-is: cimplefmt.hs
+  hs-source-dirs:   tools
+  ghc-options:      -Wall
+  main-is:          cimplefmt.hs
   build-depends:
-      base < 5
+      base        <5
     , bytestring
     , cimple
     , text
 
 executable dump-ast
   default-language: Haskell2010
-  hs-source-dirs:
-      tools
-  ghc-options:
-      -Wall
-  main-is: dump-ast.hs
+  hs-source-dirs:   tools
+  ghc-options:      -Wall
+  main-is:          dump-ast.hs
   build-depends:
-      base < 5
-    , bytestring
+      base        <5
     , cimple
     , groom
-    , text
 
 executable dump-tokens
   default-language: Haskell2010
-  hs-source-dirs:
-      tools
-  ghc-options:
-      -Wall
-  main-is: dump-tokens.hs
+  hs-source-dirs:   tools
+  ghc-options:      -Wall
+  main-is:          dump-tokens.hs
   build-depends:
-      base < 5
+      base        <5
     , bytestring
     , cimple
     , groom
-    , text
 
 executable include-graph
   default-language: Haskell2010
-  hs-source-dirs:
-      tools
-  ghc-options:
-      -Wall
-  main-is: include-graph.hs
+  hs-source-dirs:   tools
+  ghc-options:      -Wall
+  main-is:          include-graph.hs
   build-depends:
-      base < 5
+      base    <5
     , cimple
     , groom
 
 test-suite testsuite
-  type: exitcode-stdio-1.0
-  default-language: Haskell2010
-  hs-source-dirs: test
-  main-is: testsuite.hs
+  type:               exitcode-stdio-1.0
+  default-language:   Haskell2010
+  hs-source-dirs:     test
+  main-is:            testsuite.hs
   other-modules:
-      Language.Cimple.AstSpec
-    , Language.Cimple.ParserSpec
-    , Language.Cimple.PrettySpec
-  ghc-options:
-      -Wall
-      -fno-warn-unused-imports
-  build-tool-depends:
-      hspec-discover:hspec-discover
+    Language.Cimple.AstSpec
+    Language.Cimple.ParserSpec
+    Language.Cimple.PrettySpec
+
+  ghc-options:        -Wall -Wno-unused-imports
+  build-tool-depends: hspec-discover:hspec-discover
   build-depends:
-      base < 5
-    , ansi-wl-pprint
+      ansi-wl-pprint
+    , base                 <5
     , cimple
     , data-fix
     , hspec
diff --git a/src/Language/Cimple/Ast.hs b/src/Language/Cimple/Ast.hs
--- a/src/Language/Cimple/Ast.hs
+++ b/src/Language/Cimple/Ast.hs
@@ -1,10 +1,8 @@
-{-# LANGUAGE DeriveFunctor     #-}
 {-# LANGUAGE DeriveGeneric     #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE DerivingVia       #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE Strict            #-}
-{-# LANGUAGE StrictData        #-}
 module Language.Cimple.Ast
     ( AssignOp (..)
     , BinaryOp (..)
diff --git a/src/Language/Cimple/CommentParser.y b/src/Language/Cimple/CommentParser.y
--- a/src/Language/Cimple/CommentParser.y
+++ b/src/Language/Cimple/CommentParser.y
@@ -30,6 +30,7 @@
     '@deprecated'		{ L _ CmtCommand "@deprecated"	}
     '@extends'			{ L _ CmtCommand "@extends"	}
     '@implements'		{ L _ CmtCommand "@implements"	}
+    '@note'			{ L _ CmtCommand "@note"	}
     '@param'			{ L _ CmtCommand "@param"	}
     '@private'			{ L _ CmtCommand "@private"	}
     '@ref'			{ L _ CmtCommand "@ref"		}
diff --git a/src/Language/Cimple/DescribeAst.hs b/src/Language/Cimple/DescribeAst.hs
--- a/src/Language/Cimple/DescribeAst.hs
+++ b/src/Language/Cimple/DescribeAst.hs
@@ -1,7 +1,6 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE Strict            #-}
-{-# LANGUAGE StrictData        #-}
 module Language.Cimple.DescribeAst
     ( HasLocation (..)
     , describeLexeme
@@ -34,7 +33,7 @@
     PreprocIf{}     -> "#if/#endif block"
     PreprocIfdef{}  -> "#ifdef/#endif block"
     PreprocIfndef{} -> "#ifndef/#endif block"
-    _               -> show $ (const ellipsis) <$> unFix node
+    _               -> show $ ellipsis <$ unFix node
   where
     ellipsis :: String
     ellipsis = "..."
diff --git a/src/Language/Cimple/Diagnostics.hs b/src/Language/Cimple/Diagnostics.hs
--- a/src/Language/Cimple/Diagnostics.hs
+++ b/src/Language/Cimple/Diagnostics.hs
@@ -1,7 +1,6 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE Strict            #-}
-{-# LANGUAGE StrictData        #-}
 module Language.Cimple.Diagnostics
   ( Diagnostics
   , HasDiagnostics (..)
diff --git a/src/Language/Cimple/Flatten.hs b/src/Language/Cimple/Flatten.hs
--- a/src/Language/Cimple/Flatten.hs
+++ b/src/Language/Cimple/Flatten.hs
@@ -3,7 +3,6 @@
 {-# LANGUAGE FlexibleInstances     #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE Strict                #-}
-{-# LANGUAGE StrictData            #-}
 {-# LANGUAGE TypeOperators         #-}
 module Language.Cimple.Flatten (lexemes) where
 
@@ -81,7 +80,7 @@
     gconcatsFlatten (Fix (DocRParen x)) = gconcatsFlatten x
     gconcatsFlatten (Fix (DocSee r x)) = r : gconcatsFlatten x
     gconcatsFlatten (Fix (DocSentence x p)) = gconcatsFlatten x ++ [p]
-    gconcatsFlatten (Fix (DocULItem i x)) = concat [gconcatsFlatten i, gconcatsFlatten x]
+    gconcatsFlatten (Fix (DocULItem i x)) = gconcatsFlatten i ++ gconcatsFlatten x
     gconcatsFlatten (Fix (DocWord x)) = [x]
 
 instance GenConcatsFlatten t a => GenConcats (Rec0 t) a where
diff --git a/src/Language/Cimple/IO.hs b/src/Language/Cimple/IO.hs
--- a/src/Language/Cimple/IO.hs
+++ b/src/Language/Cimple/IO.hs
@@ -1,9 +1,10 @@
-{-# LANGUAGE Strict     #-}
-{-# LANGUAGE StrictData #-}
+{-# LANGUAGE Strict #-}
 module Language.Cimple.IO
-    ( parseFile
+    ( parseExpr
+    , parseFile
     , parseFiles
     , parseProgram
+    , parseStmt
     , parseText
     ) where
 
@@ -16,7 +17,7 @@
 import           Data.Text                       (Text)
 import qualified Data.Text.Encoding              as Text
 import           Language.Cimple.Ast             (Node)
-import           Language.Cimple.Lexer           (Lexeme, runAlex)
+import           Language.Cimple.Lexer           (Alex, Lexeme, runAlex)
 import           Language.Cimple.MapAst          (TextActions, mapAst,
                                                   textActions)
 import qualified Language.Cimple.Parser          as Parser
@@ -43,8 +44,17 @@
                 return text
 
 
+runText :: Alex a -> Text -> Either String a
+runText f = flip runAlex f . LBS.fromStrict . Text.encodeUtf8
+
+parseExpr :: Text -> Either String TextNode
+parseExpr = runText Parser.parseStmt
+
+parseStmt :: Text -> Either String TextNode
+parseStmt = runText Parser.parseStmt
+
 parseText :: Text -> Either String [TextNode]
-parseText = fmap cacheText . flip runAlex Parser.parseTranslationUnit . LBS.fromStrict . Text.encodeUtf8
+parseText = fmap cacheText . runText Parser.parseTranslationUnit
 
 parseBytes :: LBS.ByteString -> Either String [TextNode]
 parseBytes = flip runAlex Parser.parseTranslationUnit
@@ -64,13 +74,9 @@
     addSource (Right ok) = Right (source, ok)
 
 
-parseFiles' :: [FilePath] -> IO (Either String [TranslationUnit Text])
-parseFiles' sources = sequenceA <$> P.mapM parseFile sources
-
-
 parseFiles :: [FilePath] -> IO (Either String [TranslationUnit Text])
-parseFiles sources = fmap Program.toList . (>>= Program.fromList) <$> parseFiles' sources
+parseFiles sources = sequenceA <$> P.mapM parseFile sources
 
 
 parseProgram :: [FilePath] -> IO (Either String (Program Text))
-parseProgram sources = (>>= Program.fromList) <$> parseFiles' sources
+parseProgram sources = (>>= Program.fromList) <$> parseFiles sources
diff --git a/src/Language/Cimple/Lexer.x b/src/Language/Cimple/Lexer.x
--- a/src/Language/Cimple/Lexer.x
+++ b/src/Language/Cimple/Lexer.x
@@ -116,14 +116,16 @@
 <ppSC>		\"[^\"]*\"				{ mkL LitString }
 <ppSC>		\n					{ mkL PpNewline `andBegin` 0 }
 <ppSC>		\\\n					;
-<ppSC>		$white					;
+<ppSC>		" "					;
+<ppSC>		$white					{ mkE ErrorToken }
 
 <ignoreSC>	"//!TOKSTYLE+"				{ mkL IgnEnd `andBegin` 0 }
 <ignoreSC>	([^\/]+|.|\n)				{ mkL IgnBody }
 
 <0,ppSC>	"//"\n					;
 <0,ppSC>	"// ".*					;
-<0>		$white+					;
+<0>		[\ \n]+					;
+<0>		$white					{ mkE ErrorToken }
 <0>		"//!TOKSTYLE-"				{ mkL IgnStart `andBegin` ignoreSC }
 <0>		"/*"					{ mkL CmtStart `andBegin` cmtSC }
 <0>		"/**"					{ mkL CmtStartDoc `andBegin` cmtSC }
@@ -308,6 +310,10 @@
 
 mkL :: LexemeClass -> AlexInput -> Int64 -> Alex (Lexeme Text)
 mkL c (p, _, str, _) len = pure $ L p c (piece str)
+  where piece = Text.decodeUtf8 . LBS.toStrict . LBS.take len
+
+mkE :: LexemeClass -> AlexInput -> Int64 -> Alex (Lexeme Text)
+mkE c (p, _, str, _) len = alexError $ ": " <> show (L p c (piece str))
   where piece = Text.decodeUtf8 . LBS.toStrict . LBS.take len
 
 lexemePosn :: Lexeme text -> AlexPosn
diff --git a/src/Language/Cimple/MapAst.hs b/src/Language/Cimple/MapAst.hs
--- a/src/Language/Cimple/MapAst.hs
+++ b/src/Language/Cimple/MapAst.hs
@@ -4,7 +4,6 @@
 {-# LANGUAGE RecordWildCards       #-}
 {-# LANGUAGE ScopedTypeVariables   #-}
 {-# LANGUAGE Strict                #-}
-{-# LANGUAGE StrictData            #-}
 {-# LANGUAGE TypeFamilies          #-}
 module Language.Cimple.MapAst
     ( mapAst
diff --git a/src/Language/Cimple/Parser.y b/src/Language/Cimple/Parser.y
--- a/src/Language/Cimple/Parser.y
+++ b/src/Language/Cimple/Parser.y
@@ -1,7 +1,9 @@
 {
 {-# LANGUAGE OverloadedStrings #-}
 module Language.Cimple.Parser
-    ( parseTranslationUnit
+    ( parseExpr
+    , parseStmt
+    , parseTranslationUnit
     ) where
 
 import           Data.Fix               (Fix (..))
@@ -20,6 +22,8 @@
 %expect 2
 
 %name parseTranslationUnit TranslationUnit
+%name parseExpr Expr
+%name parseStmt Stmt
 
 %error {parseError}
 %errorhandlertype explist
diff --git a/src/Language/Cimple/Pretty.hs b/src/Language/Cimple/Pretty.hs
--- a/src/Language/Cimple/Pretty.hs
+++ b/src/Language/Cimple/Pretty.hs
@@ -1,6 +1,8 @@
 {-# OPTIONS_GHC -Wno-missing-signatures #-}
 {-# LANGUAGE LambdaCase        #-}
 {-# LANGUAGE OverloadedStrings #-}
+{- HLINT ignore "Functor law" -}
+{- HLINT ignore "Use <$" -}
 module Language.Cimple.Pretty
     ( plain
     , render
@@ -275,8 +277,9 @@
 ppCommentInfo :: Comment (Lexeme Text) -> Doc
 ppCommentInfo = foldFix go
   where
-  ppBody     = vcat . zipWith (<>) (        repeat (dullyellow (text " * "  )))
-  ppIndented = vcat . zipWith (<>) (empty : repeat (dullyellow (text " *   ")))
+  commentStart t = repeat (dullyellow (text t))
+  ppBody     = vcat . zipWith (<>) (        commentStart " * "  )
+  ppIndented = vcat . zipWith (<>) (empty : commentStart " *   ")
   ppRef      = underline . cyan . ppLexeme
   ppAttr     = maybe empty (blue . ppLexeme)
 
diff --git a/src/Language/Cimple/SemCheck/Includes.hs b/src/Language/Cimple/SemCheck/Includes.hs
--- a/src/Language/Cimple/SemCheck/Includes.hs
+++ b/src/Language/Cimple/SemCheck/Includes.hs
@@ -1,5 +1,4 @@
-{-# LANGUAGE Strict     #-}
-{-# LANGUAGE StrictData #-}
+{-# LANGUAGE Strict #-}
 module Language.Cimple.SemCheck.Includes
   ( collectIncludes
   , normaliseIncludes
diff --git a/src/Language/Cimple/TraverseAst.hs b/src/Language/Cimple/TraverseAst.hs
--- a/src/Language/Cimple/TraverseAst.hs
+++ b/src/Language/Cimple/TraverseAst.hs
@@ -5,7 +5,6 @@
 {-# LANGUAGE RecordWildCards       #-}
 {-# LANGUAGE ScopedTypeVariables   #-}
 {-# LANGUAGE Strict                #-}
-{-# LANGUAGE StrictData            #-}
 {-# LANGUAGE TypeFamilies          #-}
 module Language.Cimple.TraverseAst
     ( traverseAst
diff --git a/test/Language/Cimple/AstSpec.hs b/test/Language/Cimple/AstSpec.hs
--- a/test/Language/Cimple/AstSpec.hs
+++ b/test/Language/Cimple/AstSpec.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
 {-# LANGUAGE LambdaCase        #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ViewPatterns      #-}
