diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 5dcf7491e9a9b767e7108f5eff6dbf7bd72d37ee..9566276dc6981ac7556807af8503b9ea64af20e9 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -5,8 +5,20 @@
     "tasks": [
         {
             "type": "shell",
-            "label": "cargo run --example ex1",
-            "command": "cargo run --example ex1",
+            "label": "cargo run --example ex_lit",
+            "command": "cargo run --example ex_lit",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo run --example ex_lite",
+            "command": "cargo run --example ex_lite",
             "problemMatcher": [
                 "$rustc"
             ],
diff --git a/README.md b/README.md
index 5c5b7b9312c8362c5a695bc56a8505808cc59af9..089d1e65ea72262a382895ff05f96df92551890a 100644
--- a/README.md
+++ b/README.md
@@ -4,67 +4,71 @@ Disclaimer, I'm NOT the author of the `syn` and `nom` parsing frameworks, so no
 
 The same goes for all references to supporting crates and references to other Rust libraries, crates and the language itself, so use material at own risk :)
 
-## Parsing a `LitInt` and rejecting invalid range
-As a simple example let us start out with `mylit!(LitInt)`, where
+## Built in parsers
+
+The `syn::parse` function allows to parse any struct that implements the `syn::synom::Synom` trait. The `syn` crate provides a large set of structs which satisfies this requirement, which we can use directly or for building parser combinators.
+
+We can invoke custom parsers through procedural macros in Rust.
+
+As a simple example let us start out with simple macro `lit!` parsing a `LitInt`, where
 `LitInt` should be an intereger literal `x` in the range `10 <= x < 100`.
 
-Consider the following program (`ex1.rs`):
+Consider the following program (`ex_lit.rs`):
 
 ``` rust
 #![feature(proc_macro)]
 
 extern crate parsetest;
-use parsetest::mylit;
+use parsetest::lit;
 
 fn main() {
     // should pass
-    let _v = mylit!(99);
+    let _v = lit!(99);
 
     // should be rejected
-    let _v = mylit!(102);
+    let _v = lit!(102);
 
     // should be rejected
-    let _v = mylit!(9o9);
+    let _v = lit!(9o9);
 
     // should be rejected
-    let _v = mylit!((99));
+    let _v = lit!((99));
 }
-
 ```
 
-The expected outcome for `mylit!` is:
+The expected outcome for `lit!` is:
 
 ``` shell
-> Executing task: cargo run --example ex1 <
+> Executing task: cargo run --example ex_lit <
 
-   Compiling parsetest v0.1.0 (file:///home/pln/course/parsetest)
+   Compiling parsetest v0.1.0 (file:///home/pln/rtfm/parsetest)
 error: expected literal 10 <= x < 100, got 102
-  --> examples/ex1.rs:11:21
+  --> examples/ex_lit.rs:11:19
    |
-11 |     let _v = mylit!(102);
-   |                     ^^^
+11 |     let _v = lit!(102);
+   |                   ^^^
 
 error: expected literal 10 <= x < 100, got 9
-  --> examples/ex1.rs:14:21
+  --> examples/ex_lit.rs:14:19
    |
-14 |     let _v = mylit!(9o9);
-   |                     ^^^
+14 |     let _v = lit!(9o9);
+   |                   ^^^
 
 error: invalid suffix `o9` for numeric literal
-  --> examples/ex1.rs:14:21
+  --> examples/ex_lit.rs:14:19
    |
-14 |     let _v = mylit!(9o9);
-   |                     ^^^
+14 |     let _v = lit!(9o9);
+   |                   ^^^
    |
    = help: the suffix must be one of the integral types (`u32`, `isize`, etc)
 
 error: proc macro panicked
-  --> examples/ex1.rs:17:14
+  --> examples/ex_lit.rs:17:14
    |
-17 |     let _v = mylit!((99));
-   |              ^^^^^^^^^^^^
+17 |     let _v = lit!((99));
+   |              ^^^^^^^^^^
    |
-   = help: message: called `Result::unwrap()` on an `Err` value: ParseError(None)
+   = help: message: called `Result::unwrap()` on an `Err` value: ParseError(Some("failed to parse integer literal: failed to parse"))
 
 error: Could not compile `parsetest`.
 ```
@@ -87,6 +91,108 @@ use quote::ToTokens;
 
 use std::convert::From;
 
+/// Procedural macro `lit`
+/// Parsing a LinInt with compile time range checking
+#[proc_macro]
+pub fn lit(input: TokenStream) -> TokenStream {
+    let v: LitInt = syn::parse(input).unwrap();
+    let value = v.value();
+    if !(10 <= value && value < 100) {
+        v.span()
+            .unstable()
+            .error(format!("expected literal 10 <= x < 100, got {}", value,))
+            .emit();
+    }
+    From::from(v.into_tokens())
+}
+```
+
+The `syn::LitInt` type implement the `syn::synom::Synom` trait (required by the `syn::parse` function). The unwrapped result is of type `LitInt`, for which we can get the inner value representation (a `u64`).
+
+In this example we use that to (at compile time) ensure that the value is within a given range, (between 10 and 100), and reject faulty assignment with a sensible error message.
+
+The error message is presented as a `TokenStream` throught the `.emit()` function. This does NOT imply an immediate abort (unlike a `panic!`), thus rustc will continue compilation and catch all errors.
+
+For the first case (`lit!(99)`) the parsing succeeded and the returned token stream would amount to the literate integer 99. As our `v` is a `LitInt` we need to convert it into a `TokenStream`, a two stage process by first turning `v` into tokens, from wich we get a token stream. (You may comment out the failing parts and print the value of `_v` to convince yourself.)
+
+For the second and third cases, we see that appropriate errors and spans are reported by the built in parser. However the last case is somewhat unsatisfying, due to the `syn::parse` failing (unwrap on an `Err`). We can handle that as well as follows, for the example `ex_lite.rs`.
+
+``` rust
+#![feature(proc_macro)]
+
+extern crate parsetest;
+use parsetest::lite;
+
+fn main() {
+    // should be rejected
+    let _v = lite!((99));
+}
+```
+
+With the improved error reporting, we can get.
+
+``` shell
+> Executing task: cargo run --example ex_lite <
+Compiling parsetest v0.1.0 (file:///home/pln/rtfm/parsetest)
+error: failed to parse integer literal: failed to parse
+ --> examples/ex_lite.rs:8:14
+  |
+8 |     let _v = lite!((99));
+  |              ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+error: Could not compile `parsetest`.
+```
+
+The backing implementation now matches the parsed result and inserts a `compiler_error!`, instead of the previous unwrap.
+
+``` rust
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+#[macro_use]
+extern crate quote;
+#[macro_use]
+extern crate syn;
+
+use proc_macro::TokenStream;
+use syn::spanned::Spanned;
+use syn::synom::Synom;
+use syn::LitInt;
+use quote::ToTokens;
+
+use std::convert::From;
+use std::error::Error;
+
+/// Procedural macro `lite`
+/// Parsing a LinInt with compile time range checking
+#[proc_macro]
+pub fn lite(input: TokenStream) -> TokenStream {
+    match syn::parse::<LitInt>(input) {
+        Ok(v) => {
+            let value = v.value();
+            if !(10 <= value && value < 100) {
+                v.span()
+                    .unstable()
+                    .error(format!("expected literal 10 <= x < 100, got {}", value,))
+                    .emit();
+            }
+            From::from(v.into_tokens())
+        }
+        Err(err) => {
+            let desc = err.description();
+            let tokens = quote! {
+                compile_error!(#desc)
+            };
+            return tokens.into();
+        }
+```
+
+The description here is the default error, provided by the built in `LitInt` parser.
+
+### Direct approach
+
 /// MyLit
 struct MyLit {
     val: LitInt,
@@ -155,6 +261,3 @@ pub fn mylit(input: TokenStream) -> TokenStream {
 }
 ```
 
-Besides just parsing an `IntLit` (that is a `u64`), we want at compile time to ensure that it is in a given range, (between 10 and 100 in this example), and report a sensible error message for illegal usage. 
-
-The error message is presented as a `TokenStream` throught the `.emit()` function.
\ No newline at end of file
diff --git a/examples/ex_lit.rs b/examples/ex_lit.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ce02ca9f3da0891673359131980daf22728b39bd
--- /dev/null
+++ b/examples/ex_lit.rs
@@ -0,0 +1,18 @@
+#![feature(proc_macro)]
+
+extern crate parsetest;
+use parsetest::lit;
+
+fn main() {
+    // should pass
+    let _v = lit!(99);
+
+    // should be rejected
+    let _v = lit!(102);
+
+    // should be rejected
+    let _v = lit!(9o9);
+
+    // should be rejected
+    let _v = lit!((99));
+}
diff --git a/examples/ex_lite.rs b/examples/ex_lite.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3718a49dcb81dedcd35690fe21d97f2f9b3b5b5b
--- /dev/null
+++ b/examples/ex_lite.rs
@@ -0,0 +1,9 @@
+#![feature(proc_macro)]
+
+extern crate parsetest;
+use parsetest::lite;
+
+fn main() {
+    // should be rejected
+    let _v = lite!((99));
+}
diff --git a/src/lib.rs b/src/lib.rs
index 4c6cf70e195108446fc3194765f50b2c202d67ee..c889c5530edbcb35299df83c7daff563510958eb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,7 @@
 #![feature(proc_macro)]
 
 extern crate proc_macro;
-// #[macro_use]
+#[macro_use]
 extern crate quote;
 #[macro_use]
 extern crate syn;
@@ -13,7 +13,47 @@ use syn::LitInt;
 use quote::ToTokens;
 
 use std::convert::From;
-// use std::error::Error;
+use std::error::Error;
+
+/// Procedural macro `lit`
+/// Parsing a LinInt with compile time range checking
+#[proc_macro]
+pub fn lit(input: TokenStream) -> TokenStream {
+    let v: LitInt = syn::parse(input).unwrap();
+    let value = v.value();
+    if !(10 <= value && value < 100) {
+        v.span()
+            .unstable()
+            .error(format!("expected literal 10 <= x < 100, got {}", value,))
+            .emit();
+    }
+    From::from(v.into_tokens())
+}
+
+/// Procedural macro `lite`
+/// Parsing a LinInt with compile time range checking
+#[proc_macro]
+pub fn lite(input: TokenStream) -> TokenStream {
+    match syn::parse::<LitInt>(input) {
+        Ok(v) => {
+            let value = v.value();
+            if !(10 <= value && value < 100) {
+                v.span()
+                    .unstable()
+                    .error(format!("expected literal 10 <= x < 100, got {}", value,))
+                    .emit();
+            }
+            From::from(v.into_tokens())
+        }
+        Err(err) => {
+            let desc = err.description();
+            let tokens = quote! {
+                compile_error!(#desc)
+            };
+            return tokens.into();
+        }
+    }
+}
 
 /// MyLit
 struct MyLit {