diff --git a/generateChangemarks/dockerfile.pandoc b/generateChangemarks/dockerfile.pandoc
index 54dae98615f4d677512748839f85f49171dc0802..fca9e306463362cb11f2c00e815232e1c101db7c 100644
--- a/generateChangemarks/dockerfile.pandoc
+++ b/generateChangemarks/dockerfile.pandoc
@@ -1,9 +1,8 @@
-FROM pandoc/core:3.4.0-ubuntu
+FROM pandoc/latex:3.4.0-ubuntu
 
 RUN apt-get update -y && \
     apt-get install -y npm &&\
-    npm install --global mermaid-filter &&\
-    apt-get install -y texlive-latex-base texlive-latex-recommended texlive-fonts-recommended
+    npm install --global mermaid-filter
 
 CMD ["/bin/sh"]
 
diff --git a/toMkdocs/mkdocs.yml b/toMkdocs/mkdocs.yml
index c1c3ac830acc31c58e920a332beb60220d7b38dd..dc5cf7752586908c27fa0c2b642e495810845c16 100644
--- a/toMkdocs/mkdocs.yml
+++ b/toMkdocs/mkdocs.yml
@@ -60,6 +60,8 @@ markdown_extensions:
       pygments_lang_class: true
   - pymdownx.inlinehilite
   - pymdownx.snippets
+  - pymdownx.arithmatex:
+      generic: true
   - pymdownx.superfences:
       custom_fences:
         - name: mermaid
@@ -69,6 +71,10 @@ markdown_extensions:
      alternate_style: true
   - tables
 
+extra_javascript:
+  - javascripts/mathjax.js
+  - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js
+
 ##############################################################################
 
 extra:
diff --git a/toMkdocs/toMkdocs.py b/toMkdocs/toMkdocs.py
index 49778dee08a1293f371d8c44f9b403ad0c6992a2..4206440fe45952715c01c6d81198537048c851e1 100644
--- a/toMkdocs/toMkdocs.py
+++ b/toMkdocs/toMkdocs.py
@@ -7,6 +7,8 @@
 #	directory structure.
 #
 from __future__ import annotations
+
+import logging
 from enum import Enum, auto
 import argparse, re, os, shutil, hashlib, base64
 from dataclasses import dataclass
@@ -416,9 +418,15 @@ _matchCodefenceStart = re.compile(r'\s*```\s?.*', re.IGNORECASE)
 _matchCodefenceEnd = re.compile(r'\s*```\s?', re.IGNORECASE)
 _matchNote = re.compile(r'^\s*>\s*', re.IGNORECASE)
 _matchStandAloneImage = re.compile(r'^\s*!\[[^\]]*\]\(([^)]*)\)\s*', re.IGNORECASE)
-_matchTable = re.compile(r'^\s*\|.*\|\s$', re.IGNORECASE)
+_matchTable = re.compile(r'^\s*\|.*\|\s*$', re.IGNORECASE)
 _matchTableSeparator = re.compile(r'^\s*\|([-: ]+\|)+\s*$', re.IGNORECASE)
+_matchGridTable = re.compile(r'^\s*\+-.*\+\s$', re.IGNORECASE)
+_matchGridTableSeparator = re.compile(r'\s*\+([-:=]+\+)+\s*$', re.IGNORECASE)
+_matchGridTableBodySeparator = re.compile(r'.*\+([:-]+\+)+.*$', re.IGNORECASE)
+_matchGridTableHeaderSeparator = re.compile(r'.*\+([=:]+\+)+.*$', re.IGNORECASE)
+_matchGridTableBodySeparatorLine = re.compile(r'[-:]+$', re.IGNORECASE)
 _match2spaceListIndention = re.compile(r'^\s{2}-', re.IGNORECASE)
+_matchListInContent = re.compile(r'^(?:\s*(P<marker>[-*+]|\s*\d+\.))\s+(P<content>.+)$', re.IGNORECASE)
 _markdownLink = re.compile(r'[^!]\[[^\]]*\]\((#[^)]*)\)', re.IGNORECASE)
 _htmlLink = re.compile(r'<a\s+href="([^"\']*)">[^<]*</a>', re.IGNORECASE)
 _htmlAnchorLink = re.compile(r'<a\s+name="([^"]*)">[^<]*</a>', re.IGNORECASE)
@@ -447,6 +455,437 @@ def shortHash(value:str, length:int) -> str:
 				).digest()
 			 ).decode()[:length]
 
+def parse_pandoc_table_with_spans(pandoc_table):
+	"""
+	Parse a Pandoc-style grid table into a structure for HTML conversion with rowspan and colspan.
+
+	:param pandoc_table: String of the Pandoc-style grid table.
+	:return: List of lists representing the table with metadata for spans.
+	"""
+	# Split the input into lines
+	lines = [line.strip() for line in pandoc_table.strip().split("\n")]
+
+	class Cell:
+		"""	Represents the document object. """
+		content: str
+		rowspan: int
+		colspan: int
+		colspan_adjusted: bool
+		alignment: str
+		position: int
+		list_flag: bool
+		auxiliar_index: int
+
+		def __init__(self):
+			self.content = None
+			self.rowspan = 0
+			self.colspan = 0
+			self.colspan_adjusted = False
+			self.alignment = "align=\"center\""
+			self.position = 0
+			self.list_flag = False
+			self.auxiliar_index = None
+
+		def set_alignment(self):
+			header_delimiter_index = 0
+			while header_delimiter_index in range(len(default_alignments)) and self.position > header_delimiter_positions[header_delimiter_index]:
+				header_delimiter_index += 1
+			if header_delimiter_index in range(len(default_alignments)):
+				if self.position < header_delimiter_positions[header_delimiter_index]:
+					self.alignment = default_alignments[header_delimiter_index]
+				elif self.position == header_delimiter_positions[header_delimiter_index]:
+					self.alignment = default_alignments[header_delimiter_index]
+					header_delimiter_index += 1
+			else:
+				raise ValueError("Invalid table formatting")
+
+	class Row():
+		"""	Represents a row in the markdown file. """
+		cells:list[Cell] = []
+
+		def __init__(self, length: int = 1) -> None:
+			self.cells = [Cell() for _ in range(length)]
+
+		def __getitem__(self, item):
+			return self.cells[item]
+
+		def __setitem__(self, key, value):
+			self.cells[key] = value
+
+	# Detect separator lines by pattern (it does not take into account partial separators
+	def is_separator(line):
+		return _matchGridTableSeparator.match(line)
+
+	def handling_content(cell, content):
+		if cell.content is None:
+			cell.rowspan += 1
+			cell.colspan += 1
+			if content.strip().startswith("- "):  # List
+				cell.list_flag = True
+				#print(content)
+				cell.content = content.strip() + "\n"  # Add newline to know when the list element ends
+			elif cell.list_flag and cells[i].strip() != "":  # any other content when handling list is concatenated to the last list element
+				cell.content += content.strip() + "\n"
+			elif cells[i].strip == "":  # separation between list and other paragraph
+				cell.list_flag = False
+				cell.content += "\n" #if not cell['content'].endswith("\n") else ""
+			else:
+				cell.content = re.sub(r'\\\s*$', "\n", content.strip())
+		else:
+			if content.strip().startswith("- "):  # List
+				if not cell.list_flag:
+					cell.content += "\n"
+					#cell['content'] = cell['content'].strip("\n")
+				cell.list_flag = True
+				cell.content += content.strip() + "\n"  # Add newline to know when the list element ends
+			elif cell.list_flag and cells[i].strip() != "":  # any other content when handling list is concatenated to the last list element
+				cell.content = cell.content.strip("\n")
+				cell.content += " " + content.strip() + "\n"
+			elif cells[i].strip() == "":  # separation between list and other paragraph
+				cell.list_flag = False
+				#content = re.sub(r'\\\s*$', "\n", content.strip())
+				cell.content += "\n" if not cell.content.endswith("\n") else ""
+			else:
+				content = re.sub(r'\\\s*$', "\n", content.strip())
+				cell.content += " " + content
+		#print(cell['content'])
+		return cell
+
+	def adjust_colspan(row, column_index, number_of_parts, line, number_of_columns, delimiter_positions):
+		for j in range(column_index, number_of_parts):
+			delimiter_start = row[j - 1].position if j != 0 else 0
+			positions = [line.find(delimiter, delimiter_start + 1) for delimiter in "|+" if delimiter in line[delimiter_start + 1:]]
+			position = min(positions) if positions else -1
+			if position > delimiter_positions[j]:  # Colspan to be increased
+				row[i].colspan += 1
+				if position == delimiter_positions[len(delimiter_positions) - 1]:  # last cell in row, adjust colspan to get max number columns
+					colspan_allocated = row[i].colspan
+					#for cell_index in range(number_of_parts):
+					#	colspan_allocated += row[cell_index].colspan
+					row[column_index].colspan += number_of_columns - colspan_allocated - column_index
+			elif position < delimiter_positions[j]:
+				raise ValueError("Wrong cell formatting")
+			else:
+				break
+		return row[column_index]
+
+	separator_indices = [i for i, line in enumerate(lines) if is_separator(line)]
+
+	print(separator_indices)
+	if not separator_indices:
+		raise ValueError("No valid separators found in the provided Pandoc table.")
+
+	# Calculate max number of columns
+	delimiter_positions = []
+	number_of_columns = 0
+	for separator_index in separator_indices:
+		if lines[separator_index].count("+") - 1 > number_of_columns:
+			number_of_columns = lines[separator_index].count("+") - 1
+			delimiter_positions = []
+			for j in range(number_of_columns):
+				delimiter_positions_start = delimiter_positions[j - 1] if j != 0 else 0
+				del_positions = [lines[separator_index].find(delimiter, delimiter_positions_start + 1) for delimiter in "+" if delimiter in lines[separator_index][delimiter_positions_start + 1:]]
+				delimiter_positions.append(min(del_positions) if del_positions else -1)
+	has_header = False
+	header_delimiter_positions = []
+	for index in separator_indices:
+		if _matchGridTableHeaderSeparator.match(lines[index]):
+			has_header = True
+			header_separator_index = index
+			header_rows = []
+			parts = re.split(r"\+", lines[index].strip("+"))
+			default_alignments = []
+			#Calculate default alignments and positions of delimiters
+			for part_index in range(len(parts)):
+				if parts[part_index].startswith(":") and not parts[part_index].endswith(":"):
+					default_alignments.append("align=\"left\"")
+				elif not parts[part_index].startswith(":") and parts[part_index].endswith(":"):
+					default_alignments.append("align=\"right\"")
+				else:
+					default_alignments.append("align=\"center\"")
+				# Delimiter position
+				delimiter_positions_start = delimiter_positions[part_index - 1] if part_index != 0 else 0
+				del_positions = [lines[index].find(delimiter, delimiter_positions_start + 1) for delimiter in "+" if delimiter in lines[index][delimiter_positions_start + 1:]]
+				header_delimiter_positions.append(min(del_positions) if del_positions else -1)
+
+	data_rows = []
+	for row in range(len(separator_indices) - 1):
+		table_row = []
+		auxiliar_rows = []
+		has_merged_cells = False
+		in_data_row = False
+		start, end = separator_indices[row], separator_indices[row + 1]
+		row_lines = lines[start:end]  # Lines between separators including separator line start as it gives information about the number of columns of the row
+		if row_lines:
+			# Combine multiline content into single strings for each cell
+			for line in row_lines:
+				if is_separator(line) and not in_data_row:
+					number_of_columns_row = line.count("+") - 1
+					in_data_row = True
+					parts = re.split(r"\s*\+\s*", line.strip("+"))
+					# Add as many cells as columns with span attributes
+					delimiter_index = 0
+					# Determine the alignment of the cell - In order to replicate Pandoc's behaviour (do not support of alignment colons on separator lines (just header separator)
+					# we need to assign the default alignment as defined in the header separator line
+					# We may not need the code below, as that supports alignment per cell and row
+					#alignments = []
+					#for part_index in range(len(parts)):
+					#	if parts[part_index].startswith(":") and not parts[part_index].endswith(":"):
+					#		alignments.append("align=\"left\"")
+					#	elif not parts[part_index].startswith(":") and parts[part_index].endswith(":"):
+					#		alignments.append("align=\"right\"")
+					#	else:
+					#		alignments.append("align=\"center\"")
+					header_delimiter_index = 0
+					table_row = Row(number_of_columns_row)
+					for i in range(number_of_columns_row):
+						delimiter_index += len(parts[i]) + 1
+						table_row[i].alignment = default_alignments[i] if i == 0 else "align=\"center\""
+						table_row[i].position = delimiter_index # Position of cell delimiter +
+
+						#Set alignment as defined by header separator line
+						table_row[i].set_alignment()
+
+				elif in_data_row:
+					# Regular data row or partial separator
+					if _matchGridTableBodySeparator.match(line): # Partial separator
+						has_merged_cells = True
+						cells = re.split(r"[\|\+]", line.strip("|").strip("+"))  # (?<!\\)[\|\+]
+						#Add auxiliar line, set delimiters for each cell
+						auxiliar_rows.append(Row(number_of_columns))
+						aux_delimiter_index = 0
+						for auxiliar_cell_index in range(number_of_columns):
+							aux_delimiter_index += len(cells[auxiliar_cell_index]) + 1
+							auxiliar_rows[-1][auxiliar_cell_index].position = aux_delimiter_index  # Position of cell delimiter +
+						auxiliar_rows[-1][i].set_alignment()
+
+						if len(cells) <= number_of_columns: # Colspan: Positions of | with respect to + need to be determined
+							for i in range(len(cells)):
+								if _matchGridTableBodySeparatorLine.match(cells[i]):  # A new row is to be added
+									#auxiliar_rows[-1]['use_auxiliar_row'][i] = True
+									auxiliar_rows[-1][i].list_flag = False
+									table_row[i].auxiliar_index = len(auxiliar_rows)-1
+									#if cells[i].startswith(":") and not cells[i].endswith(":"):
+									#	auxiliar_rows[-1]['auxiliar_row'][i]['alignment'] = "align=\"left\""
+									#elif not cells[i].startswith(":") and  cells[i].endswith(":"):
+									#	auxiliar_rows[-1]['auxiliar_row'][i]['alignment'] = "align=\"right\""
+									#else:
+									#	auxiliar_rows[-1]['auxiliar_row'][i]['alignment'] = "align=\"center\""
+								else:
+									# Handle content of the cell
+									if table_row[i].auxiliar_index is not None: # and auxiliar_rows[table_row[i]['auxiliar_index']]['use_auxiliar_row'][i]:
+										auxiliar_rows[table_row[i].auxiliar_index][i] = handling_content(auxiliar_rows[table_row[i].auxiliar_index][i], cells[i])
+										if not auxiliar_rows[table_row[i].auxiliar_index][i].colspan_adjusted:
+											auxiliar_rows[table_row[i].auxiliar_index][i].colspan_adjusted = True
+											# TO BE CHECKED Most probably the code below is never executed, colspan should be already adjusted when dealing with a partial separator
+											auxiliar_rows[table_row[i].auxiliar_index][i] = adjust_colspan(auxiliar_rows[table_row[i].auxiliar_index], i, len(cells), line, number_of_columns, delimiter_positions)
+									else:
+										table_row[i] = handling_content(table_row[i], cells[i])
+										# Cell which is not separator
+										table_row[i].rowspan += 1
+										if not table_row.cells[i].colspan_adjusted:
+											table_row[i].colspan_adjusted = True
+											#TO BE CHECKED Most probably the code below is never executed, colspan should be already adjusted when dealing with a partial separator
+											table_row[i] = adjust_colspan(table_row, i, len(cells), line, number_of_columns, delimiter_positions)
+						else:
+							raise ValueError("More cells than columns found")
+					else: # Data row
+						cells = re.split(r"\s*\|\s*", line.strip("|"))
+						if len(cells) < number_of_columns: # Colspan: Positions of | with respect to + need to be determined
+							for i in range(len(cells)):
+								# Handle content of the cell
+								if table_row[i].auxiliar_index is not None:# and auxiliar_rows[table_row[i]['auxiliar_index']]['use_auxiliar_row'][i]:
+									auxiliar_rows[table_row.cells[i].auxiliar_index][i] = handling_content(auxiliar_rows[table_row[i].auxiliar_index][i], cells[i])
+									if not auxiliar_rows[table_row.cells[i].auxiliar_index].cells[i].colspan_adjusted:
+										auxiliar_rows[table_row.cells[i].auxiliar_index].cells[i].colspan_adjusted = True
+										#TO BE CHECKED Most probably the code below is never executed, colspan should be already adjusted when dealing with a partial separator
+										auxiliar_rows[table_row[i].auxiliar_index][i] = adjust_colspan(auxiliar_rows[table_row[i].auxiliar_index].cells, i, len(cells), line, number_of_columns, delimiter_positions)
+								else:
+									table_row[i] = handling_content(table_row[i], cells[i])
+									if not table_row.cells[i].colspan_adjusted:
+										table_row[i].colspan_adjusted = True
+										table_row[i] = adjust_colspan(table_row.cells, i, len(cells), line, number_of_columns, delimiter_positions)
+						elif len(cells) == number_of_columns: # Simple row
+							for i in range(len(cells)):
+								if table_row[i].auxiliar_index is not None:# and auxiliar_rows[table_row[i]['auxiliar_index']]['use_auxiliar_row'][i]:
+									auxiliar_rows[table_row[i].auxiliar_index][i] = handling_content(auxiliar_rows[table_row[i].auxiliar_index][i], cells[i])
+								else:
+									# Handle content of the cell
+									table_row[i] = handling_content(table_row[i], cells[i])
+						else:
+							raise ValueError("More cells than columns found")
+				else:
+					raise ValueError("No separator line found for row starting")
+
+			if has_header and start >= header_separator_index: # table_row and auxiliar_row are part of data_rows
+				data_rows.append(table_row.cells)
+				if has_merged_cells:
+					for row in auxiliar_rows:
+						#for i in range(len(row.cells)):
+						#	print(row.cells[i].content)
+						data_rows.append(row.cells)
+			elif has_header and start < header_separator_index: # table_row and auxiliar_row are part of header_rows
+				header_rows.append(table_row.cells)
+				if has_merged_cells:
+					for row in auxiliar_rows:
+						header_rows.append(row.cells)
+
+	#print(header_rows)
+	#print(data_rows)
+	# Check if there are any data rows
+	if not data_rows and not header_rows:
+		raise ValueError("No valid rows found in the provided Pandoc table.")
+
+	# Format text
+	for rows in [header_rows, data_rows]:
+		bold = "<strong>"
+		italic = "<i>"
+		for row in rows:
+			for cell in row:
+				if cell.content is not None:
+					# Replacing "<" by &lt;
+					#cell.content = cell.content.replace("<", "&lt;")
+
+					#Bold
+					for bold_characters in ["**", "__"]:
+						while cell.content.find(bold_characters) != -1:
+							cell.content = cell.content.replace(bold_characters, bold, 1)
+							if bold == "<strong>":
+								bold = "</strong>"
+							else:
+								bold = "<strong>"
+					#Italic
+					while cell.content.find("_") != -1 and cell.content.find("\_") == -1:
+						cell.content = cell.content.rstrip() .replace("_", italic, 1)
+						if italic == "<i>":
+							italic = "</i>"
+						else:
+							italic = "<i>"
+					while cell.content.find("\_") != -1:
+						cell.content = cell.content.rstrip().replace("\_", "_", 1)
+
+	# Correct newlines characters
+	for row in header_rows:
+		for cell in row:
+			cell.content = cell.content.replace("\n", "<br />") if cell.content is not None else None
+	for row in data_rows:
+		for cell in row:
+			cell.content = cell.content.replace("\n", "<br />") if cell.content is not None else None
+
+	# Checking that the grid is correct Not too much tested - need to take into account rowspan of previous rows
+	forward_rowspan = []
+	for row_index in range(len(header_rows)):
+		if len(forward_rowspan) == 0:
+			forward_rowspan = [0 for _ in range(len(header_rows[row_index]))]
+		sum = 0
+		for cell_index in range(len(header_rows[row_index])):
+			sum += header_rows[row_index][cell_index].colspan
+			if row_index > 0 and header_rows[row_index][cell_index].colspan == 0:
+				if forward_rowspan[cell_index] > 0:
+					sum += 1
+				forward_rowspan[cell_index] -= 1
+			if forward_rowspan[cell_index] == 0 and header_rows[row_index][cell_index].rowspan > 1:
+				forward_rowspan[cell_index] = header_rows[row_index][cell_index].rowspan -1
+		if not sum == number_of_columns:
+			raise ValueError("Grid table not converted properly")
+	forward_rowspan = []
+	for row_index in range(len(data_rows)):
+		if len(forward_rowspan) == 0:
+			forward_rowspan = [0 for _ in range(len(data_rows[row_index]))]
+		sum = 0
+		for cell_index in range(len(data_rows[row_index])):
+			sum += data_rows[row_index][cell_index].colspan
+			if row_index > 0 and data_rows[row_index][cell_index].colspan == 0:
+				if forward_rowspan[cell_index] > 0:
+					sum += 1
+				forward_rowspan[cell_index] -= 1
+			if forward_rowspan[cell_index] == 0 and data_rows[row_index][cell_index].rowspan > 1:
+				forward_rowspan[cell_index] = data_rows[row_index][cell_index].rowspan - 1
+		if not sum == number_of_columns:
+			raise ValueError("Grid table not converted properly")
+
+	return header_rows, data_rows
+
+def generate_html_table_with_spans(pandoc_table):
+	"""
+	Generate an HTML table from a Pandoc-style grid table with row and column spans.
+
+	:param pandoc_table: String of the Pandoc-style grid table.
+	:return: HTML string.
+	"""
+	try:
+		grid_header, grid_body = parse_pandoc_table_with_spans(pandoc_table)
+	except:
+		logging.ERROR("Grid table could not be generated")
+		return "HTML TABLE COULD NOT BE GENERATED FROM MARKDOWN GRID TABLE. CHECK LOGS"
+	else:
+		html = "<table>\n"
+		has_header = False
+
+		for row in grid_header:
+			for cell in row:
+				if cell.rowspan != 0 and cell.colspan != 0:
+					has_header = True
+		if has_header:
+			html += "    <thead>\n"
+			for row in grid_header:
+				html += "        <tr>\n"
+				for cell in row:
+					if cell.rowspan == 0 or cell.colspan == 0:
+						continue
+					else:
+						# Prepare content, in case there's a list
+						#print(cell.content)
+						if matches := re.findall(r"\s*([-*+]|\s*\d+\.)\s+([^<]+)<br \/>",
+												 cell.content):  # Update cell in new row
+							#print("MATCHING")
+							list = "<ul>"
+							# Build list the matches
+							for match in matches:
+								list += "<li>" + match[1] + "</li>"
+							list += "</ul>"
+							cell.content = re.sub(r"(\s*([-*+]|\s*\d+\.)\s+[^<]+<br \/>)+", list, cell.content)
+							# Enforce left alignment if cell contains a list
+							cell.alignment = "align=\"left\""
+						#else:
+						#	print("NOT MATCHING")
+
+						rowspan = f" rowspan=\"{cell.rowspan}\"" if cell.rowspan > 1 else ""
+						colspan = f" colspan=\"{cell.colspan}\"" if cell.colspan > 1 else ""
+						html += f"            <th{rowspan}{colspan} {cell.alignment}>{cell.content}</th>\n"
+				html += "        </tr>\n"
+			html += "    </thead>\n"
+
+		html += "    <tbody>\n"
+		for row in grid_body:
+			html += "        <tr>\n"
+			for cell in row:
+				if cell.rowspan == 0 or cell.colspan == 0:
+					continue
+				else:
+					#Prepare content, in case there's a list
+					#print(cell.content)
+					if matches := re.findall(r"\s*([-*+]|\s*\d+\.)\s+([^<]+)<br \/>", cell.content):  # Update cell in new row
+						#print("MATCHING")
+						#print(cell.content)
+						list = "<ul>"
+						# Build list the matches
+						for match in matches:
+							list += "<li>" + match[1] + "</li>"
+						list += "</ul>"
+						cell.content = re.sub(r"(\s*([-*+]|\s*\d+\.)\s+[^<]+<br \/>)+",list, cell.content)
+						# Enforce left alignment if cell contains a list
+						cell.alignment = "align=\"left\""
+					#else:
+						#print("NOT MATCHING")
+					rowspan = f" rowspan=\"{cell.rowspan}\"" if cell.rowspan > 1 else ""
+					colspan = f" colspan=\"{cell.colspan}\"" if cell.colspan > 1 else ""
+					html += f"            <td{rowspan}{colspan} {cell.alignment}>{cell.content}</td>\n"
+			html += "        </tr>\n"
+
+		html += "    </tbody>\n"
+		html += "</table>"
+		return html
 
 def analyseMarkdown(filename:str) -> Document:
 	"""	Analyse the markdown file and split it into clauses.
@@ -473,6 +912,9 @@ def analyseMarkdown(filename:str) -> Document:
 	inCodefence = False
 	inTable = False
 	tableHasSeparator = False
+	inGridTable = False
+	gridTableHasSeparator = False
+	gridTable = ""
 	for line in inLines:
 
 		# Detect and handle codefences
@@ -493,7 +935,7 @@ def analyseMarkdown(filename:str) -> Document:
 			continue
 
 		# Detect and handle tables
-		if _matchTable.match(line) and not inTable:
+		if _matchTable.match(line) and not inTable and not inGridTable:
 			inTable = True
 			outClauses[-1].append(Line(line, LineType.TABLEHEADER))
 			continue
@@ -512,8 +954,36 @@ def analyseMarkdown(filename:str) -> Document:
 				outClauses[-1].lines[-1].lineType = LineType.TABLELASTROW
 				# continue with other matches
 
+		#Detect grid tables and convert them to html table
+		if _matchGridTable.match(line) and not inGridTable:
+			inGridTable = True
+			#outClauses[-1].append(Line(line, LineType.TABLEHEADER))
+			gridTable += line
+			continue
+		if inGridTable:
+			if _matchGridTableHeaderSeparator.match(line) or _matchGridTableBodySeparator.match(line):
+				#outClauses[-1].append(Line(line, LineType.TABLESEPARATOR))
+				gridTable += line
+				continue
+			elif _matchTable.match(line):
+				#outClauses[-1].append(Line(line, LineType.TABLEROW))
+				gridTable += line
+				continue
+			else:
+				inGridTable = False
+				# Mark the previous line as the last row in the table
+				#outClauses[-1].lines[-1].lineType = LineType.TABLELASTROW
+				print(gridTable)
+				htmltable = ""
+				htmltable = generate_html_table_with_spans(gridTable)
+				print(htmltable)
+				for row in htmltable:
+					outClauses[-1].append(Line(row, LineType.TABLEROW))
+				gridTable = ""
+		# continue with other matches
+
 		# Detect notes
-  		# Notes are lines that start with a '>'.
+		# Notes are lines that start with a '>'.
 		if _matchNote.match(line):
 			outClauses[-1].append(Line(line, LineType.NOTE))
 			continue
@@ -537,7 +1007,7 @@ def analyseMarkdown(filename:str) -> Document:
 			clauseTitle = re.sub(_htmlTag, '', clauseTitle)
 			headerNumber = _matchHeaderNumber.search(clauseTitle)
 			outClauses.append(Clause(len(m.groups()[0]), # level
-						  		   headerNumber.group() if headerNumber else shortHash(clauseTitle, 6),
+								   headerNumber.group() if headerNumber else shortHash(clauseTitle, 6),
 								   clauseTitle, 
 								   []))
 			_lineType = LineType.HEADING
@@ -591,7 +1061,7 @@ def processDocument(args:argparse.Namespace) -> None:
 
 if __name__ == '__main__':
 	parser = argparse.ArgumentParser(description = 'Convert oneM2M markdown specificatios to MkDocs format',
-								     formatter_class = argparse.ArgumentDefaultsHelpFormatter)
+									 formatter_class = argparse.ArgumentDefaultsHelpFormatter)
 
 	parser.add_argument('--verbose', '-v', action = 'store_true', help = 'verbose output during processing')
 	parser.add_argument('--very-verbose', '-vv', action = 'store_true', help = 'very verbose output during processing')