diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp
index 7f328daf18a7b3f72de0e4b8036cf94bcc675954..22d748344494dc992c01cc6857f0eeb9faa00d75 100644
--- a/src/language/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ASTNodeDataTypeBuilder.cpp
@@ -231,5 +231,14 @@ ASTNodeDataTypeBuilder::ASTNodeDataTypeBuilder(ASTNode& node)
   node.m_data_type = ASTNodeDataType::void_t;
 
   this->_buildNodeDataTypes(node);
+
+  FunctionTable& function_table = node.m_symbol_table->functionTable();
+  for (size_t function_id = 0; function_id < function_table.size(); ++function_id) {
+    FunctionDescriptor& function_descriptor = function_table[function_id];
+    ASTNode& function_expression            = function_descriptor.definitionNode();
+
+    this->_buildNodeDataTypes(function_expression);
+  }
+
   std::cout << " - build node data types\n";
 }
diff --git a/src/language/ASTNodeExpressionBuilder.cpp b/src/language/ASTNodeExpressionBuilder.cpp
index 9f0a6f7eb8ef2d5fcdee10da3d122b381fb5598a..839404a00966c0e61c4d892d303c432f5713f996 100644
--- a/src/language/ASTNodeExpressionBuilder.cpp
+++ b/src/language/ASTNodeExpressionBuilder.cpp
@@ -11,6 +11,7 @@
 #include <node_processor/DoWhileProcessor.hpp>
 #include <node_processor/FakeProcessor.hpp>
 #include <node_processor/ForProcessor.hpp>
+#include <node_processor/FunctionProcessor.hpp>
 #include <node_processor/IfProcessor.hpp>
 #include <node_processor/NameProcessor.hpp>
 #include <node_processor/OStreamProcessor.hpp>
@@ -27,16 +28,11 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n)
               n.is<language::pluseq_op>() or n.is<language::minuseq_op>())) {
     ASTNodeAffectationExpressionBuilder{n};
 
-  } else if (n.is<language::let_declaration>()) {
-    std::cerr << rang::fgB::red << "\"let expression\" is not defined correctly (declaration should be removed)"
-              << rang::style::reset << '\n';
+  } else if (n.is<language::function_definition>()) {
     n.m_node_processor = std::make_unique<FakeProcessor>();
-    return;
 
   } else if (n.is<language::function_evaluation>()) {
-    std::cerr << rang::fgB::red << "\"function evaluation\" is not defined yet" << rang::style::reset << '\n';
-    n.m_node_processor = std::make_unique<FakeProcessor>();
-    return;
+    n.m_node_processor = std::make_unique<FunctionProcessor>(n);
 
   } else if (n.is<language::real>()) {
     n.m_node_processor = std::make_unique<FakeProcessor>();
@@ -105,12 +101,19 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n)
   }
 }
 
-ASTNodeExpressionBuilder::ASTNodeExpressionBuilder(ASTNode& n)
+ASTNodeExpressionBuilder::ASTNodeExpressionBuilder(ASTNode& node)
 {
-  Assert(n.is_root());
-  n.m_node_processor = std::make_unique<ASTNodeListProcessor>(n);
-  for (auto& child : n.children) {
+  Assert(node.is_root());
+  node.m_node_processor = std::make_unique<ASTNodeListProcessor>(node);
+  for (auto& child : node.children) {
     this->_buildExpression(*child);
   }
-  std::cout << " - build node types\n";
+
+  // Build expressions of functions
+  FunctionTable& function_table = node.m_symbol_table->functionTable();
+  for (size_t function_id = 0; function_id < function_table.size(); ++function_id) {
+    FunctionDescriptor& function_descriptor = function_table[function_id];
+    ASTNode& function_expression            = function_descriptor.definitionNode();
+    this->_buildExpression(function_expression);
+  }
 }
diff --git a/src/language/FunctionTable.hpp b/src/language/FunctionTable.hpp
index 700439fff4d6d64f38af0c7d95e9f169d6a89507..682a87c4c9e5d4c9b097e88db2cb6ce37876ae00 100644
--- a/src/language/FunctionTable.hpp
+++ b/src/language/FunctionTable.hpp
@@ -49,6 +49,13 @@ class FunctionTable
   std::vector<FunctionDescriptor> m_function_descriptor_list;
 
  public:
+  PUGS_INLINE
+  size_t
+  size() const
+  {
+    return m_function_descriptor_list.size();
+  }
+
   PUGS_INLINE
   FunctionDescriptor& operator[](size_t function_id)
   {
diff --git a/src/language/node_processor/FunctionProcessor.hpp b/src/language/node_processor/FunctionProcessor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4527b0b6ebe3dd337b43f71ce7b88a1025d94038
--- /dev/null
+++ b/src/language/node_processor/FunctionProcessor.hpp
@@ -0,0 +1,58 @@
+#ifndef FUNCTION_PROCESSOR_HPP
+#define FUNCTION_PROCESSOR_HPP
+
+#include <FunctionTable.hpp>
+#include <SymbolTable.hpp>
+
+#include <PEGGrammar.hpp>
+
+#include <node_processor/INodeProcessor.hpp>
+
+class FunctionProcessor final : public INodeProcessor
+{
+ private:
+  ASTNode& m_node;
+
+  FunctionDescriptor& m_function_descriptor;
+
+ public:
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    // Compute arguments values
+    ASTNode& arguments_values = *m_node.children[1];
+    arguments_values.execute(exec_policy);
+
+    // Copy arguments to function arguments
+    ASTNode& definition_node = m_function_descriptor.definitionNode();
+    ASTNode& arguments       = *definition_node.children[0];
+
+    if (arguments.is<language::name>()) {
+      Assert(arguments_values.children.size() == 0);
+
+      auto [i_symbol, found] = arguments.m_symbol_table->find(arguments.string(), arguments.begin());
+      Assert(found);
+
+      i_symbol->attributes().value() = arguments_values.m_value;
+    } else {
+      throw parse_error("argument list not implemented yet!", definition_node.children[0]->begin());
+    }
+
+    ASTNode& function_expression = *definition_node.children[1];
+    function_expression.execute(exec_policy);
+
+    m_node.m_value = function_expression.m_value;
+  }
+
+  FunctionProcessor(ASTNode& node)
+    : m_node{node}, m_function_descriptor{[&]() -> FunctionDescriptor& {
+        auto [i_symbol, found] = m_node.m_symbol_table->find(m_node.children[0]->string(), m_node.begin());
+        Assert(found);
+        uint64_t function_id = std::get<uint64_t>(i_symbol->attributes().value());
+
+        return m_node.m_symbol_table->functionTable()[function_id];
+      }()}
+  {}
+};
+
+#endif   // FUNCTION_PROCESSOR_HPP
diff --git a/tests/test_ASTNodeExpressionBuilder.cpp b/tests/test_ASTNodeExpressionBuilder.cpp
index 394ed133a8ac2d79127d39845696a614befdb5de..d27c0927211731d479d2f9da30790454608c07d0 100644
--- a/tests/test_ASTNodeExpressionBuilder.cpp
+++ b/tests/test_ASTNodeExpressionBuilder.cpp
@@ -854,6 +854,7 @@ continue;
 
     string_input input{data, "test.pgs"};
     auto ast = ASTBuilder::build(input);
+    ASTSymbolTableBuilder{*ast};
     ASTNodeDataTypeBuilder{*ast};
 
     // One is sure that language::ignored is not treated so its a good candidate
diff --git a/tests/test_ASTNodeJumpPlacementChecker.cpp b/tests/test_ASTNodeJumpPlacementChecker.cpp
index 7a7679199089225fc33175f2fda16759b0bf0346..b80a8887dd1792216ddc73b5b2f99c02ae957655 100644
--- a/tests/test_ASTNodeJumpPlacementChecker.cpp
+++ b/tests/test_ASTNodeJumpPlacementChecker.cpp
@@ -1,6 +1,7 @@
 #include <catch2/catch.hpp>
 
 #include <ASTBuilder.hpp>
+#include <ASTSymbolTableBuilder.hpp>
 
 #include <ASTNodeDataTypeBuilder.hpp>
 #include <ASTNodeJumpPlacementChecker.hpp>
@@ -19,7 +20,7 @@ for(;;) {
 
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
-
+      ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
       REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
@@ -35,7 +36,7 @@ while(true) {
 
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
-
+      ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
       REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
@@ -51,7 +52,7 @@ do {
 
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
-
+      ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
       REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
@@ -67,7 +68,7 @@ do {
 
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
-
+      ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
       ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;
@@ -88,7 +89,7 @@ for(;;) {
 
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
-
+      ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
       REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
@@ -104,7 +105,7 @@ while(true) {
 
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
-
+      ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
       REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
@@ -120,7 +121,7 @@ do {
 
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
-
+      ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
       REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
@@ -136,7 +137,7 @@ do {
 
       string_input input{data, "test.pgs"};
       auto ast = ASTBuilder::build(input);
-
+      ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
       ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;