diff --git a/grimoire/src/ast/expr.rs b/grimoire/src/ast/expr.rs
index 89ad2fd0eb4ea2b744df945cf03ca42024cfe847..bfd3b87d9fc5c53b8104e9e969f55552605031f3 100644
--- a/grimoire/src/ast/expr.rs
+++ b/grimoire/src/ast/expr.rs
@@ -37,8 +37,8 @@ pub enum UnOp {
 impl UnOp {
     pub fn as_str(&self) -> &'static str {
         match self {
-            UnOp::Not => todo!(),
-            UnOp::Neg => todo!(),
+            UnOp::Not => "!",
+            UnOp::Neg => "-",
         }
     }
 }
@@ -70,20 +70,20 @@ pub enum BinOp {
 impl BinOp {
     pub fn as_str(&self) -> &'static str {
         match self {
-            BinOp::Add => todo!(),
-            BinOp::Sub => todo!(),
-            BinOp::Mul => todo!(),
-            BinOp::Div => todo!(),
-            BinOp::Mod => todo!(),
-            BinOp::CompGE => todo!(),
-            BinOp::CompGT => todo!(),
-            BinOp::CompLT => todo!(),
-            BinOp::CompLE => todo!(),
-            BinOp::Or => todo!(),
-            BinOp::And => todo!(),
-            BinOp::Xor => todo!(),
-            BinOp::CompEQ => todo!(),
-            BinOp::CompNEQ => todo!(),
+            BinOp::Add => "+",
+            BinOp::Sub => "-",
+            BinOp::Mul => "*",
+            BinOp::Div => "/",
+            BinOp::Mod => "%",
+            BinOp::CompGE => ">=",
+            BinOp::CompGT => ">",
+            BinOp::CompLT => "<=",
+            BinOp::CompLE => "<",
+            BinOp::Or => "|",
+            BinOp::And => "&",
+            BinOp::Xor => "^",
+            BinOp::CompEQ => "=",
+            BinOp::CompNEQ => "!=",
         }
     }
 }
diff --git a/grimoire/src/parser/error.rs b/grimoire/src/parser/error.rs
index 2185b01b7d845e887fb2e1bb4fd0c7aee8a6a9eb..331ef71f1f752bbf56f1b2eaf262755d70f4e9a1 100644
--- a/grimoire/src/parser/error.rs
+++ b/grimoire/src/parser/error.rs
@@ -4,13 +4,16 @@ use std::num::{ParseFloatError, ParseIntError};
 
 #[derive(Debug, thiserror::Error)]
 pub enum ParserError {
-    #[error("{0:?}, {1}")]
+    #[error("{0:?}: {1}")]
     ParseFloat(Location, ParseFloatError),
 
-    #[error("{0:?}, {1}")]
+    #[error("{0:?}: {1}")]
     ParseInt(Location, ParseIntError),
 
-    #[error("{0:?}, {1:?}")]
+    #[error("{0:?} use of a reserved keyword: '{1}'")]
+    UseOfReservedKeyword(Location, &'static str),
+
+    #[error("{0:?}: nom error {1:?}")]
     Nom(Location, ErrorKind),
 }
 
diff --git a/grimoire/src/parser/expr.rs b/grimoire/src/parser/expr.rs
index cb91241aa98611e2c39c116fd8dfc53d1d9d755f..4fde857f9f91af45dfd371451886b49446af831c 100644
--- a/grimoire/src/parser/expr.rs
+++ b/grimoire/src/parser/expr.rs
@@ -2,21 +2,27 @@ use crate::{
     ast::{AstSpan, expr::*},
     parser::*,
 };
-
 use nom::{
-    Parser, branch::alt, bytes::complete::tag, character::complete::multispace0, combinator::map,
-    multi::many0, sequence::preceded,
+    Parser,
+    branch::alt,
+    bytes::complete::tag,
+    character::complete::{char, multispace0},
+    combinator::{map, value},
+    multi::many0,
+    sequence::preceded,
 };
 
 fn var_or_constant(s: Span) -> ParserResult<Expression> {
+    // Note: the order is important!
     utils::map_with_locaiton(
         alt((
             map(utils::number, VarOrConstant::Int),
             map(utils::float, VarOrConstant::Flt),
             map(utils::string, VarOrConstant::Str),
-            map(utils::keyword("true"), |_| VarOrConstant::Bool(true)),
-            map(utils::keyword("false"), |_| VarOrConstant::Bool(false)),
-            map(utils::identifier, VarOrConstant::Var),
+            value(VarOrConstant::Bool(true), utils::keyword(keywords::TRUE)),
+            value(VarOrConstant::Bool(false), utils::keyword(keywords::FALSE)),
+            map(preceded(char('$'), utils::identifier), VarOrConstant::Var),
+            map(utils::identifier, VarOrConstant::Ident),
         )),
         Expression::Leaf,
     )
diff --git a/grimoire/src/parser/keywords.rs b/grimoire/src/parser/keywords.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4ba2f7d7ac75c2b8147ecc43ee679db2618033fa
--- /dev/null
+++ b/grimoire/src/parser/keywords.rs
@@ -0,0 +1,26 @@
+pub const TRUE: &str = "true";
+pub const FALSE: &str = "false";
+
+pub fn check(keyword: &str) -> Result<&str, &'static str> {
+    const RESERVED: &[&str] = &[TRUE, FALSE];
+    const _: () = {
+        let mut i = 0usize;
+        while i < RESERVED.len() {
+            let mut j = 0usize;
+            let reserved = RESERVED[i].as_bytes();
+            while j < reserved.len() {
+                assert!(
+                    u8::is_ascii_lowercase(&reserved[j]),
+                    "reserved keyword must be ascii-lowercase composed..."
+                );
+                j += 1;
+            }
+            i += 1;
+        }
+    };
+
+    match RESERVED.iter().find(|&&r| r == keyword.trim()) {
+        Some(&reserved) => Err(reserved),
+        None => Ok(keyword),
+    }
+}
diff --git a/grimoire/src/parser/mod.rs b/grimoire/src/parser/mod.rs
index 245e522113860f9efef2ce136d4ab06a9c87ffae..ea673b90694982f90a2bc957df13d225c6ffff92 100644
--- a/grimoire/src/parser/mod.rs
+++ b/grimoire/src/parser/mod.rs
@@ -1,5 +1,6 @@
 mod error;
 mod expr;
+pub mod keywords;
 mod location;
 mod span;
 pub mod utils;
diff --git a/grimoire/src/parser/utils.rs b/grimoire/src/parser/utils.rs
index dcdbb44a501c713098a365b48cbb27b37c4356b0..5b870a800c032220872b18447e666dfb98381cee 100644
--- a/grimoire/src/parser/utils.rs
+++ b/grimoire/src/parser/utils.rs
@@ -1,6 +1,6 @@
 use crate::{
     ast::AstSpan,
-    parser::{error::*, span::*},
+    parser::{error::*, keywords, span::*},
 };
 use nom::{
     Parser,
@@ -68,7 +68,11 @@ pub fn identifier(s: Span) -> ParserResult<String> {
         alt((alpha1, tag("_"))),
         many0(alt((alphanumeric1, tag("_")))),
     ))
-    .map(String::from)
+    .map_res(|ident: Span| {
+        keywords::check(ident.into_fragment())
+            .map_err(|reserved| ParserError::UseOfReservedKeyword(ident.into(), reserved))
+            .map(String::from)
+    })
     .parse(s)
 }