diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# Ptera: A Generator for Parsers
+# Ptera: A Parser Generator for PEGs
 
-[![Hackage](https://img.shields.io/hackage/v/ptera.svg)](https://hackage.haskell.org/package/ptera)
+[![Hackage](https://img.shields.io/hackage/v/ptera-th.svg)](https://hackage.haskell.org/package/ptera-th)
 
 ## Installation
 
@@ -9,10 +9,8 @@
 ```
 build-depends:
     base,
-    bytestring,
     ptera,          -- main
     ptera-th,       -- for outputing parser with Template Haskell
-    charset,
     template-haskell,
 ```
 
@@ -21,47 +19,127 @@
 Write parser rules:
 
 ```haskell
-data Terminal
-    = Digit
-    | SymPlus
-    | SymMulti
-    deriving (Eq, Show, Enum)
+module Parser.Rules where
 
-data NonTerminal
-    | Expr
-    | Sum
-    | Product
-    | Value
+import Language.Haskell.TH
+import Language.Parser.Ptera.TH
+
+data Token
+    = TokDigit
+    | TokSymPlus
+    | TokSymMulti
+    | TokEndOfInput
     deriving (Eq, Show, Enum)
 
-type ParseRule = Rule Terminal NonTerminal
+data Ast
+    = Value
+    | Sum Ast Ast
+    | Product Ast Ast
 
+$(genGrammarToken (mkName "Tokens") [t|Token|]
+    [ ("+", [p|TokSymPlus|])
+    , ("*", [p|TokSymMulti|])
+    , ("n", [p|TokDigit|])
+    , ("^Z", [p|TokEndOfInput{}|])
+    ])
 
-data Ast
-    = GenValue
-    | GenSum (NonEmpty Ast)
-    | GenProduct Ast Ast
+$(Ptera.genRules
+    do TH.mkName "RuleDefs"
+    do GenRulesTypes
+        { genRulesCtxTy = [t|()|]
+        , genRulesTokensTy = [t|Tokens|]
+        , genRulesTokenTy = [t|Token|]
+        }
+    [ (TH.mkName "ruleExprEos", "expr ^Z", [t|Ast|])
+    , (TH.mkName "ruleExpr", "expr", [t|Ast|])
+    , (TH.mkName "ruleSum", "sum", [t|Ast|])
+    , (TH.mkName "ruleProduct", "product", [t|Ast|])
+    , (TH.mkName "ruleValue", "value", [t|Ast|])
+    ]
+    )
 
-rExpr :: ParseRule Ast
-rExpr = rule Expr rSum
+$(Ptera.genParsePoints
+    do TH.mkName "ParsePoints"
+    do TH.mkName "RuleDefs"
+    [ "expr ^Z"
+    ]
+    )
 
-rSum :: ParseRule Ast
-rSum = rule Sum do
-    (rProduct <,> manyP do token SymPlus *> rProduct) <&> \(e, es) -> GenSum do e :| es
+grammar :: Grammar RuleDefs Tokens Token ParsePoints
+grammar = fixGrammar $ RuleDefs
+    { ruleExprEos = rExprEos
+    , ruleExpr = rExpr
+    , ruleSum = rSum
+    , ruleProduct = rProduct
+    , ruleValue = rValue
+    }
 
-rProduct :: ParseRule Ast
-rProduct = rule Product do
-    orP
-        [
-            (rValue <* token SymMulti <,> rProduct) <&> \(e1, e2) -> GenProduct e1 e2,
-            rValue
-        ]
+type Rule = RuleExpr RuleDefs Tokens Token
 
-rValue :: ParseRule Ast
-rValue = rule Value do token Digit *> pure GenValue
+
+rExprEos :: Rule Ast
+rExprEos = ruleExpr
+    [ varA @"expr" <^> tokA @"^Z"
+        <:> \(e :* _ :* HNil) -> e
+    ]
+
+rExpr :: Rule Ast
+rExpr = ruleExpr
+    [ varA @"sum"
+        <:> \(e :* HNil) -> e
+    ]
+
+rSum :: Rule Ast
+rSum = ruleExpr
+    [ varA @"product" <^> tokA @"+" <^> varA @"sum"
+        <:> \(e1 :* _ :* e2 :* HNil) -> [|| Sum $$(e1) $$(e2) ||]
+    , varA @"product"
+        <:> \(e :* HNil) -> e
+    ]
+
+rProduct :: Rule Ast
+rProduct = ruleExpr
+    [ varA @"value" <^> tokA @"*" <^> varA @"product"
+        <:> \(e1 :* _ :* e2 :* HNil) -> [|| Product $$(e1) $$(e2) ||]
+    , varA @"value"
+        <:> \(e :* HNil) -> e
+    ]
+
+rValue :: Rule Ast
+rValue = ruleExpr
+    [ tokA @"n" <:> \(n :* HNil) ->
+        [|| case $$(n) of
+            TokDigit -> Value
+            _        -> error "unreachable: expected digit token"
+        ||]
+    ]
 ```
 
+And, generate parser:
+
+```haskell
+module Parser where
+
+import Parser.Rules
+import Language.Parser.Ptera.TH
+import Data.Proxy
+
+$(genRunner
+    (GenParam
+        { startsTy = [t|ParsePoints|]
+        , rulesTy  = [t|RuleDefs|]
+        , tokensTy = [t|Tokens|]
+        , tokenTy  = [t|Token|]
+        , customCtxTy = defaultCustomCtxTy
+        })
+    grammar
+    )
+
+exprParser :: Scanner posMark Token m => m (Result posMark Ast)
+exprParser = runParser (Proxy :: Proxy "expr EOS") pteraTHRunner
+```
+
 ## Examples
 
-* Small language: https://github.com/mizunashi-mana/ptera/tree/master/example/small-lang
+* Small language: https://github.com/mizunashi-mana/ptera/tree/master/example/small-lang-th
 * Haskell2010: https://github.com/mizunashi-mana/ptera/tree/master/example/haskell2010
diff --git a/ptera-th.cabal b/ptera-th.cabal
--- a/ptera-th.cabal
+++ b/ptera-th.cabal
@@ -2,7 +2,7 @@
 build-type:          Custom
 
 name:                ptera-th
-version:             0.1.0.0
+version:             0.2.0.0
 license:             Apache-2.0 OR MPL-2.0
 license-file:        LICENSE
 copyright:           (c) 2021 Mizunashi Mana
@@ -93,7 +93,7 @@
 
         -- project depends
         ptera-core              >= 0.1.0 && < 0.2,
-        ptera                   >= 0.1.0 && < 0.2,
+        ptera                   >= 0.2.0 && < 0.3,
         ghc-prim                >= 0.6.1 && < 0.7,
         containers              >= 0.6.0 && < 0.7,
         unordered-containers    >= 0.2.0 && < 0.3,
diff --git a/src/Language/Parser/Ptera/TH.hs b/src/Language/Parser/Ptera/TH.hs
--- a/src/Language/Parser/Ptera/TH.hs
+++ b/src/Language/Parser/Ptera/TH.hs
@@ -23,11 +23,13 @@
 import qualified Language.Parser.Ptera.TH.Pipeline.Grammar2ParserDec as Grammar2ParserDec
 import           Language.Parser.Ptera.TH.Syntax                     hiding (T,
                                                                       UnsafeSemActM,
-                                                                      unsafeSemanticAction, semAct, semActM)
+                                                                      semAct,
+                                                                      semActM,
+                                                                      unsafeSemanticAction)
 import           Language.Parser.Ptera.TH.Util                       (GenRulesTypes (..),
                                                                       genGrammarToken,
-                                                                      genRules,
-                                                                      genParsePoints)
+                                                                      genParsePoints,
+                                                                      genRules)
 import qualified Type.Membership                                     as Membership
 
 genRunner :: forall initials rules tokens ctx elem
diff --git a/src/Language/Parser/Ptera/TH/Syntax.hs b/src/Language/Parser/Ptera/TH/Syntax.hs
--- a/src/Language/Parser/Ptera/TH/Syntax.hs
+++ b/src/Language/Parser/Ptera/TH/Syntax.hs
@@ -39,10 +39,9 @@
     SafeGrammar.fixGrammar,
     SafeGrammar.ruleExpr,
     (SafeGrammar.<^>),
+    SafeGrammar.eps,
     (<:>),
-    eps,
     (<::>),
-    epsM,
     SafeGrammar.var,
     SafeGrammar.varA,
     SafeGrammar.tok,
@@ -54,10 +53,10 @@
 
 import qualified Language.Haskell.TH                      as TH
 import qualified Language.Haskell.TH.Syntax               as TH
+import qualified Language.Parser.Ptera.Data.HFList        as HFList
 import qualified Language.Parser.Ptera.Syntax             as Syntax
 import qualified Language.Parser.Ptera.Syntax.SafeGrammar as SafeGrammar
 import           Language.Parser.Ptera.TH.ParserLib
-import qualified Language.Parser.Ptera.Data.HFList as HFList
 
 
 type T ctx = GrammarM ctx
@@ -78,9 +77,6 @@
 
 infixl 4 <:>
 
-eps :: (HTExpList '[] -> TH.Q (TH.TExp a)) -> AltM ctx rules tokens elem a
-eps act = SafeGrammar.eps do semAct act HFList.HFNil
-
 (<::>)
     :: SafeGrammar.Expr rules tokens elem us
     -> (HTExpList us -> TH.Q (TH.TExp (ActionTask ctx a)))
@@ -88,11 +84,6 @@
 e@(SafeGrammar.UnsafeExpr ue) <::> act = e SafeGrammar.<:> semActM act ue
 
 infixl 4 <::>
-
-epsM
-    :: (HTExpList '[] -> TH.Q (TH.TExp (ActionTask ctx a)))
-    -> AltM ctx rules tokens elem a
-epsM act = SafeGrammar.eps do semActM act HFList.HFNil
 
 
 type HTExpList = HFList.T TExpQ
