diff --git a/src/cpp/CMakeLists.txt b/src/cpp/CMakeLists.txt
new file mode 100644
index 0000000..bf375b5
--- /dev/null
+++ b/src/cpp/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.16)
+project(mdemory)
+
+set(CMAKE_CXX_STANDARD 20)
+
+add_subdirectory(transpiler)
+add_subdirectory(qtapp)
+
+# Add the main source files
+# add_executable(MdemoryApp qtapp/main.cpp)
diff --git a/src/cpp/qtapp/.cache/clangd/index/main.cpp.6DE93E662B25E657.idx b/src/cpp/qtapp/.cache/clangd/index/main.cpp.6DE93E662B25E657.idx
new file mode 100644
index 0000000..363fabf
Binary files /dev/null and b/src/cpp/qtapp/.cache/clangd/index/main.cpp.6DE93E662B25E657.idx differ
diff --git a/src/cpp/qtapp/.cache/clangd/index/mocs_compilation.cpp.24E22B09DF7BB0D0.idx b/src/cpp/qtapp/.cache/clangd/index/mocs_compilation.cpp.24E22B09DF7BB0D0.idx
new file mode 100644
index 0000000..2d86651
Binary files /dev/null and b/src/cpp/qtapp/.cache/clangd/index/mocs_compilation.cpp.24E22B09DF7BB0D0.idx differ
diff --git a/src/cpp/qtapp/.clang-format b/src/cpp/qtapp/.clang-format
new file mode 100644
index 0000000..651f916
--- /dev/null
+++ b/src/cpp/qtapp/.clang-format
@@ -0,0 +1,401 @@
+# clang-format
+# Made by: Ingmar Delsink
+# idelsink.com
+# See http://clang.llvm.org/docs/ClangFormatStyleOptions.html
+# Tested with: clang-format version 3.7.1
+
+# General
+#########
+
+# The style used for all options not specifically set in the configuration.
+# This option is supported only in the clang-format configuration (both within -style='{...}' and the .clang-format file).
+# Possible values:
+# LLVM A style complying with the LLVM coding standards
+# Google A style complying with Google’s C++ style guide
+# Chromium A style complying with Chromium’s style guide
+# Mozilla A style complying with Mozilla’s style guide
+# WebKit A style complying with WebKit’s style guide
+#BasedOnStyle:
+
+# TabWidth (unsigned)
+# The number of columns used for tab stops.
+TabWidth: 4
+
+# IndentWidth (unsigned)
+# The number of columns to use for indentation.
+IndentWidth: 4
+
+# UseTab (UseTabStyle)
+# The way to use tab characters in the resulting file.
+# Possible values:
+# UT_Never (in configuration: Never) Never use tab.
+# UT_ForIndentation (in configuration: ForIndentation) Use tabs only for indentation.
+# UT_Always (in configuration: Always) Use tabs whenever we need to fill whitespace that spans at least from one tab stop to the next one.
+UseTab: Never
+
+# C++
+#####
+
+# Language (LanguageKind)
+# Language, this format style is targeted at.
+# Possible values:
+# LK_None (in configuration: None) Do not use.
+# LK_Cpp (in configuration: Cpp) Should be used for C, C++, ObjectiveC, ObjectiveC++.
+# LK_Java (in configuration: Java) Should be used for Java.
+# LK_JavaScript (in configuration: JavaScript) Should be used for JavaScript.
+# LK_Proto (in configuration: Proto) Should be used for Protocol Buffers (https://developers.google.com/protocol-buffers/).
+# LK_TableGen (in configuration: TableGen) Should be used for TableGen code.
+Language: Cpp
+
+# Standard (LanguageStandard)
+# Format compatible with this standard, e.g. use A > instead of A> for LS_Cpp03.
+# Possible values:
+# LS_Cpp03 (in configuration: Cpp03) Use C++03-compatible syntax.
+# LS_Cpp11 (in configuration: Cpp11) Use features of C++11 (e.g. A> instead of A >).
+# LS_Auto (in configuration: Auto) Automatic detection based on the input.
+Standard: Cpp11
+
+# Pointer and reference alignment style. Possible values: Left, Right, Middle.
+PointerAlignment: Left
+
+# AccessModifierOffset (int)
+# The extra indent or outdent of access modifiers, e.g. public:.
+AccessModifierOffset: 0
+
+# AlignAfterOpenBracket (BracketAlignmentStyle)
+# If true, horizontally aligns arguments after an open bracket.
+# This applies to round brackets (parentheses), angle brackets and square brackets.
+# Possible values:
+# BAS_Align (in configuration: Align) Align parameters on the open bracket, e.g.:
+# someLongFunction(argument1,
+# argument2);
+# BAS_DontAlign (in configuration: DontAlign) Don’t align, instead use ContinuationIndentWidth, e.g.:
+# someLongFunction(argument1,
+# argument2);
+# BAS_AlwaysBreak (in configuration: AlwaysBreak) Always break after an open bracket, if the parameters don’t fit on a single line, e.g.:
+# someLongFunction(
+# argument1, argument2);
+AlignAfterOpenBracket: false
+
+# AlignConsecutiveAssignments (bool)
+# If true, aligns consecutive assignments.
+# This will align the assignment operators of consecutive lines. This will result in formattings like
+# int aaaa = 12;
+# int b = 23;
+# int ccc = 23;
+AlignConsecutiveAssignments: true
+
+# AlignEscapedNewlinesLeft (bool)
+# If true, aligns escaped newlines as far left as possible. Otherwise puts them into the right-most column.
+AlignEscapedNewlinesLeft: true
+
+# AlignOperands (bool)
+# If true, horizontally align operands of binary and ternary expressions.
+# Specifically, this aligns operands of a single expression that needs to be split over multiple lines, e.g.:
+# int aaa = bbbbbbbbbbbbbbb +
+# ccccccccccccccc;
+AlignOperands: false
+
+# AlignTrailingComments (bool)
+# If true, aligns trailing comments.
+AlignTrailingComments: true
+
+# AllowAllParametersOfDeclarationOnNextLine (bool)
+# Allow putting all parameters of a function declaration onto the next line even if BinPackParameters is false.
+AllowAllParametersOfDeclarationOnNextLine: false
+
+# AllowShortBlocksOnASingleLine (bool)
+# Allows contracting simple braced statements to a single line.
+AllowShortBlocksOnASingleLine: false
+
+# AllowShortCaseLabelsOnASingleLine (bool)
+# If true, short case labels will be contracted to a single line.
+AllowShortCaseLabelsOnASingleLine: true
+
+# AllowShortFunctionsOnASingleLine (ShortFunctionStyle)
+# Dependent on the value, int f() { return 0; } can be put on a single line.
+# Possible values:
+# SFS_None (in configuration: None) Never merge functions into a single line.
+# SFS_Empty (in configuration: Empty) Only merge empty functions.
+# SFS_Inline (in configuration: Inline) Only merge functions defined inside a class. Implies “empty”.
+# SFS_All (in configuration: All) Merge all functions fitting on a single line.
+AllowShortFunctionsOnASingleLine: false
+
+# AllowShortIfStatementsOnASingleLine (bool)
+# If true, if (a) return; can be put on a single line.
+AllowShortIfStatementsOnASingleLine: false
+
+# AllowShortLoopsOnASingleLine (bool)
+# If true, while (true) continue; can be put on a single line.
+AllowShortLoopsOnASingleLine: false
+
+# AlwaysBreakBeforeMultilineStrings (bool)
+# If true, always break before multiline string literals.
+# This flag is mean to make cases where there are multiple multiline strings in a file look more consistent. Thus, it will only take effect if wrapping the string at that point leads to it being indented ContinuationIndentWidth spaces from the start of the line.
+AlwaysBreakBeforeMultilineStrings: false
+
+# AlwaysBreakTemplateDeclarations (bool)
+# If true, always break after the template<...> of a template declaration.
+AlwaysBreakTemplateDeclarations: false
+
+# BinPackArguments (bool)
+# If false, a function call’s arguments will either be all on the same line or will have one line each.
+#BinPackArguments: false
+
+# BinPackParameters (bool)
+# If false, a function declaration’s or function definition’s parameters will either all be on the same line or will have one line each.
+BinPackParameters: false
+
+# BraceWrapping (BraceWrappingFlags)
+# Control of individual brace wrapping cases.
+# If BreakBeforeBraces is set to BS_Custom, use this to specify how each individual brace case should be handled. Otherwise, this is ignored.
+# Nested configuration flags:
+# bool AfterClass Wrap class definitions.
+# bool AfterControlStatement Wrap control statements (if/for/while/switch/..).
+# bool AfterEnum Wrap enum definitions.
+# bool AfterFunction Wrap function definitions.
+# bool AfterNamespace Wrap namespace definitions.
+# bool AfterObjCDeclaration Wrap ObjC definitions (@autoreleasepool, interfaces, ..).
+# bool AfterStruct Wrap struct definitions.
+# bool AfterUnion Wrap union definitions.
+# bool BeforeCatch Wrap before catch.
+# bool BeforeElse Wrap before else.
+# bool IndentBraces Indent the wrapped braces themselves.
+#BraceWrapping:
+
+# BreakAfterJavaFieldAnnotations (bool)
+# Break after each annotation on a field in Java files.
+#BreakAfterJavaFieldAnnotations:
+
+# BreakBeforeBinaryOperators (BinaryOperatorStyle)
+# The way to wrap binary operators.
+# Possible values:
+# BOS_None (in configuration: None) Break after operators.
+# BOS_NonAssignment (in configuration: NonAssignment) Break before operators that aren’t assignments.
+# BOS_All (in configuration: All) Break before operators.
+BreakBeforeBinaryOperators: false
+
+# BreakBeforeBraces (BraceBreakingStyle)
+# The brace breaking style to use.
+# Possible values:
+# BS_Attach (in configuration: Attach) Always attach braces to surrounding context.
+# BS_Linux (in configuration: Linux) Like Attach, but break before braces on function, namespace and class definitions.
+# BS_Mozilla (in configuration: Mozilla) Like Attach, but break before braces on enum, function, and record definitions.
+# BS_Stroustrup (in configuration: Stroustrup) Like Attach, but break before function definitions, catch, and else.
+# BS_Allman (in configuration: Allman) Always break before braces.
+# BS_GNU (in configuration: GNU) Always break before braces and add an extra level of indentation to braces of control statements, not to those of class, function or other definitions.
+# BS_WebKit (in configuration: WebKit) Like Attach, but break before functions.
+# BS_Custom (in configuration: Custom) Configure each individual brace in BraceWrapping.
+BreakBeforeBraces: Attach
+
+# BreakBeforeTernaryOperators (bool)
+# If true, ternary operators will be placed after line breaks.
+BreakBeforeTernaryOperators: false
+
+# BreakConstructorInitializersBeforeComma (bool)
+# Always break constructor initializers before commas and align the commas with the colon.
+BreakConstructorInitializersBeforeComma: false
+
+# BreakStringLiterals (bool)
+# Allow breaking string literals when formatting.
+#BreakStringLiterals:
+
+# ColumnLimit (unsigned)
+# The column limit.
+# A column limit of 0 means that there is no column limit. In this case, clang-format will respect the input’s line breaking decisions within statements unless they contradict other rules.
+ColumnLimit: 80
+
+# CommentPragmas (std::string)
+# A regular expression that describes comments with special meaning, which should not be split into lines or otherwise changed.
+CommentPragmas: ''
+
+# ConstructorInitializerAllOnOneLineOrOnePerLine (bool)
+# If the constructor initializers don’t fit on a line, put each initializer on its own line.
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+
+# ConstructorInitializerIndentWidth (unsigned)
+# The number of characters to use for indentation of constructor initializer lists.
+ConstructorInitializerIndentWidth: 0
+
+# ContinuationIndentWidth (unsigned)
+# Indent width for line continuations.
+ContinuationIndentWidth: 0
+
+# Cpp11BracedListStyle (bool)
+# If true, format braced lists as best suited for C++11 braced lists.
+# Important differences: - No spaces inside the braced list. - No line break before the closing brace. - Indentation with the continuation indent, not with the block indent.
+# Fundamentally, C++11 braced lists are formatted exactly like function calls would be formatted in their place. If the braced list follows a name (e.g. a type or variable name), clang-format formats as if the {} were the parentheses of a function call with that name. If there is no name, a zero-length name is assumed.
+Cpp11BracedListStyle: false
+
+# DerivePointerAlignment (bool)
+# If true, analyze the formatted file for the most common alignment of & and \*. PointerAlignment is then used only as fallback.
+DerivePointerBinding: false
+
+# DisableFormat (bool)
+# Disables formatting completely.
+#DisableFormat:
+
+# ExperimentalAutoDetectBinPacking (bool)
+# If true, clang-format detects whether function calls and definitions are formatted with one parameter per line.
+# Each call can be bin-packed, one-per-line or inconclusive. If it is inconclusive, e.g. completely on one line, but a decision needs to be made, clang-format analyzes whether there are other bin-packed cases in the input file and act accordingly.
+# NOTE: This is an experimental flag, that might go away or be renamed. Do not use this in config files, etc. Use at your own risk.
+#ExperimentalAutoDetectBinPacking:
+
+# ForEachMacros (std::vector)
+# A vector of macros that should be interpreted as foreach loops instead of as function calls.
+# These are expected to be macros of the form:
+# FOREACH(, ...)
+#
+# In the .clang-format configuration file, this can be configured like:
+# ForEachMacros: ['RANGES_FOR', 'FOREACH']
+# For example: BOOST_FOREACH.
+#ForEachMacros:
+
+# IncludeCategories (std::vector)
+# Regular expressions denoting the different #include categories used for ordering #includes.
+# These regular expressions are matched against the filename of an include (including the <> or “”) in order. The value belonging to the first matching regular expression is assigned and #includes are sorted first according to increasing category number and then alphabetically within each category.
+# If none of the regular expressions match, INT_MAX is assigned as category. The main header for a source file automatically gets category 0. so that it is generally kept at the beginning of the #includes (http://llvm.org/docs/CodingStandards.html#include-style). However, you can also assign negative priorities if you have certain headers that always need to be first.
+# To configure this in the .clang-format file, use:
+# IncludeCategories:
+# - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+# Priority: 2
+# - Regex: '^(<|"(gtest|isl|json)/)'
+# Priority: 3
+# - Regex: '.\*'
+# Priority: 1
+#IncludeCategories:
+
+# IndentCaseLabels (bool)
+# Indent case labels one level from the switch statement.
+# When false, use the same indentation level as for the switch statement. Switch statement body is always indented one level more than case labels.
+IndentCaseLabels: false
+
+# IndentFunctionDeclarationAfterType (bool)
+# If true, indent when breaking function declarations which are not also definitions after the type.
+IndentFunctionDeclarationAfterType: false
+
+# IndentWrappedFunctionNames (bool)
+# Indent if a function definition or declaration is wrapped after the type.
+#IndentWrappedFunctionNames:
+
+# KeepEmptyLinesAtTheStartOfBlocks (bool)
+# If true, empty lines at the start of blocks are kept.
+#KeepEmptyLinesAtTheStartOfBlocks:
+
+# MacroBlockBegin (std::string)
+# A regular expression matching macros that start a block.
+#MacroBlockBegin:
+
+# MacroBlockEnd (std::string)
+# A regular expression matching macros that end a block.
+#MacroBlockEnd:
+
+# MaxEmptyLinesToKeep (unsigned)
+# The maximum number of consecutive empty lines to keep.
+MaxEmptyLinesToKeep: 2
+
+# NamespaceIndentation (NamespaceIndentationKind)
+# The indentation used for namespaces.
+# Possible values:
+# NI_None (in configuration: None) Don’t indent in namespaces.
+# NI_Inner (in configuration: Inner) Indent only in inner namespaces (nested in other namespaces).
+# NI_All (in configuration: All) Indent in all namespaces.
+NamespaceIndentation: None
+
+# ObjCBlockIndentWidth (unsigned)
+# The number of characters to use for indentation of ObjC blocks.
+#ObjCBlockIndentWidth:
+
+# ObjCSpaceAfterProperty (bool)
+# Add a space after @property in Objective-C, i.e. use @property (readonly) instead of @property(readonly).
+ObjCSpaceAfterProperty: true
+
+# ObjCSpaceBeforeProtocolList (bool)
+# Add a space in front of an Objective-C protocol list, i.e. use Foo instead of Foo.
+ObjCSpaceBeforeProtocolList: true
+
+# PenaltyBreakBeforeFirstCallParameter (unsigned)
+# The penalty for breaking a function call after call(.
+PenaltyBreakBeforeFirstCallParameter: 100
+
+# PenaltyBreakComment (unsigned)
+# The penalty for each line break introduced inside a comment.
+PenaltyBreakComment: 100
+
+# PenaltyBreakFirstLessLess (unsigned)
+# The penalty for breaking before the first <<.
+PenaltyBreakFirstLessLess: 0
+
+# PenaltyBreakString (unsigned)
+# The penalty for each line break introduced inside a string literal.
+PenaltyBreakString: 100
+
+# PenaltyExcessCharacter (unsigned)
+# The penalty for each character outside of the column limit.
+PenaltyExcessCharacter: 1
+
+# PenaltyReturnTypeOnItsOwnLine (unsigned)
+# Penalty for putting the return type of a function onto its own line.
+PenaltyReturnTypeOnItsOwnLine: 20
+
+# PointerAlignment (PointerAlignmentStyle)
+# Pointer and reference alignment style.
+# Possible values:
+# PAS_Left (in configuration: Left) Align pointer to the left.
+# PAS_Right (in configuration: Right) Align pointer to the right.
+# PAS_Middle (in configuration: Middle) Align pointer in the middle.
+#PointerAlignment:
+
+# ReflowComments (bool)
+# If true, clang-format will attempt to re-flow comments.
+#ReflowComments: true (from v3.9)
+
+# SortIncludes (bool)
+# If true, clang-format will sort #includes.
+#SortIncludes: false (from v3.9)
+
+# SpaceAfterCStyleCast (bool)
+# If true, a space may be inserted after C style casts.
+SpaceAfterCStyleCast: false
+
+# SpaceBeforeAssignmentOperators (bool)
+# If false, spaces will be removed before assignment operators.
+SpaceBeforeAssignmentOperators: true
+
+# SpaceBeforeParens (SpaceBeforeParensOptions)
+# Defines in which cases to put a space before opening parentheses.
+# Possible values:
+# SBPO_Never (in configuration: Never) Never put a space before opening parentheses.
+# SBPO_ControlStatements (in configuration: ControlStatements) Put a space before opening parentheses only after control statement keywords (for/if/while...).
+# SBPO_Always (in configuration: Always) Always put a space before opening parentheses, except when it’s prohibited by the syntax rules (in function-like macro definitions) or when determined by other style rules (after unary operators, opening parentheses, etc.)
+SpaceBeforeParens: Always
+
+# SpaceInEmptyParentheses (bool)
+# If true, spaces may be inserted into ().
+SpaceInEmptyParentheses: false
+
+# SpacesBeforeTrailingComments (unsigned)
+# The number of spaces before trailing line comments (// - comments).
+# This does not affect trailing block comments (/* - comments) as those commonly have different usage patterns and a number of special cases.
+SpacesBeforeTrailingComments: 1
+
+# SpacesInAngles (bool)
+# If true, spaces will be inserted after < and before > in template argument lists.
+SpacesInAngles: false
+
+# SpacesInCStyleCastParentheses (bool)
+# If true, spaces may be inserted into C style casts.
+SpacesInCStyleCastParentheses: false
+
+# SpacesInContainerLiterals (bool)
+# If true, spaces are inserted inside container literals (e.g. ObjC and Javascript array and dict literals).
+SpacesInContainerLiterals: false
+
+# SpacesInParentheses (bool)
+# If true, spaces will be inserted after ( and before ).
+SpacesInParentheses: false
+
+# SpacesInSquareBrackets (bool)
+# If true, spaces will be inserted after [ and before ].
+SpacesInSquareBrackets: false
+
diff --git a/src/cpp/qtapp/.gitignore b/src/cpp/qtapp/.gitignore
new file mode 100644
index 0000000..0f3a6b1
--- /dev/null
+++ b/src/cpp/qtapp/.gitignore
@@ -0,0 +1,2 @@
+Debug
+Release
diff --git a/src/cpp/qtapp/CMakeLists.txt b/src/cpp/qtapp/CMakeLists.txt
new file mode 100644
index 0000000..66c996f
--- /dev/null
+++ b/src/cpp/qtapp/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.10)
+if(CMAKE_VERSION VERSION_LESS "3.7.0")
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+endif()
+
+project(MdemoryApp VERSION 0.1.0 LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+find_package(Qt5 COMPONENTS Widgets REQUIRED)
+
+add_executable(
+ MdemoryApp
+ main.cpp
+)
+target_link_libraries(MdemoryApp Qt5::Widgets)
diff --git a/src/cpp/qtapp/compile_commands.json b/src/cpp/qtapp/compile_commands.json
new file mode 100644
index 0000000..61e3c8b
--- /dev/null
+++ b/src/cpp/qtapp/compile_commands.json
@@ -0,0 +1,14 @@
+[
+{
+ "directory": "/home/jorenchik/Code/mdemory/src/cpp/qtapp",
+ "command": "/usr/bin/g++ -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_WIDGETS_LIB -I/home/jorenchik/Code/mdemory/src/cpp/qtapp/MdemoryApp_autogen/include -isystem /usr/include/qt -isystem /usr/include/qt/QtWidgets -isystem /usr/include/qt/QtGui -isystem /usr/include/qt/QtCore -isystem /usr/lib/qt/mkspecs/linux-g++ -std=gnu++11 -fPIC -o CMakeFiles/MdemoryApp.dir/MdemoryApp_autogen/mocs_compilation.cpp.o -c /home/jorenchik/Code/mdemory/src/cpp/qtapp/MdemoryApp_autogen/mocs_compilation.cpp",
+ "file": "/home/jorenchik/Code/mdemory/src/cpp/qtapp/MdemoryApp_autogen/mocs_compilation.cpp",
+ "output": "CMakeFiles/MdemoryApp.dir/MdemoryApp_autogen/mocs_compilation.cpp.o"
+},
+{
+ "directory": "/home/jorenchik/Code/mdemory/src/cpp/qtapp",
+ "command": "/usr/bin/g++ -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_WIDGETS_LIB -I/home/jorenchik/Code/mdemory/src/cpp/qtapp/MdemoryApp_autogen/include -isystem /usr/include/qt -isystem /usr/include/qt/QtWidgets -isystem /usr/include/qt/QtGui -isystem /usr/include/qt/QtCore -isystem /usr/lib/qt/mkspecs/linux-g++ -std=gnu++11 -fPIC -o CMakeFiles/MdemoryApp.dir/main.cpp.o -c /home/jorenchik/Code/mdemory/src/cpp/qtapp/main.cpp",
+ "file": "/home/jorenchik/Code/mdemory/src/cpp/qtapp/main.cpp",
+ "output": "CMakeFiles/MdemoryApp.dir/main.cpp.o"
+}
+]
\ No newline at end of file
diff --git a/src/cpp/qtapp/main.cpp b/src/cpp/qtapp/main.cpp
new file mode 100644
index 0000000..f7fbd90
--- /dev/null
+++ b/src/cpp/qtapp/main.cpp
@@ -0,0 +1,222 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct Page {
+ int start;
+ int end;
+};
+
+class Mdem {
+public:
+ QWidget *wMdem;
+ QLabel *wFrontText;
+ QWidget *wBack;
+ QVector backLabels;
+ QToolButton *showButton;
+ int labelCount;
+
+ // Method to show or hide back labels
+ void showBacklabels() {
+ for (int i = 0; i < backLabels.size(); ++i) {
+ if (i < labelCount) {
+ if (!backLabels[i]->isVisible()) {
+ backLabels[i]->show();
+ }
+ } else {
+ if (backLabels[i]->isVisible()) {
+ backLabels[i]->hide();
+ }
+ }
+ }
+ }
+
+ // Constructor to create an Mdem object
+ Mdem() {
+ wMdem = new QWidget();
+ QVBoxLayout *vMdem = new QVBoxLayout();
+ wMdem->setLayout(vMdem);
+
+ QString id = QString("mdem_%1").arg(1);
+ wMdem->setObjectName(id);
+
+ // Front
+ QWidget *wFront = new QWidget();
+ QHBoxLayout *hFront = new QHBoxLayout();
+ wFront->setMinimumHeight(60);
+ wFront->setLayout(hFront);
+ wMdem->setStyleSheet(QString(
+ "QWidget#%1 > QWidget {"
+ "border-right: 1px solid gray;"
+ "border-bottom: 1px solid gray;"
+ "border-left: 1px solid gray;"
+ "} "
+ "QWidget#%1 > QWidget[first=\"true\"] {"
+ "border-top: 1px solid gray;"
+ "}"
+ ).arg(id));
+
+ // Add Front Content
+ wFrontText = new QLabel();
+ hFront->addWidget(wFrontText);
+ hFront->addStretch(1);
+
+ showButton = new QToolButton();
+ showButton->setText("Show");
+ hFront->addWidget(showButton);
+
+ // Back
+ wBack = new QWidget();
+ QVBoxLayout *hBack = new QVBoxLayout();
+ wBack->setLayout(hBack);
+ vMdem->addWidget(wBack);
+
+ // Add Back Content
+ for (int i = 0; i < 20; ++i) {
+ QLabel *elBackText = new QLabel();
+ hBack->addWidget(elBackText);
+ backLabels.append(elBackText);
+ }
+
+ vMdem->addWidget(wFront);
+ vMdem->addWidget(wBack);
+ vMdem->setContentsMargins(0, 0, 0, 0);
+ vMdem->setSpacing(0);
+
+ wBack->hide();
+ wMdem->hide();
+
+ // Connect button to toggle view
+ QObject::connect(showButton, &QToolButton::clicked, [this]() {
+ if (wBack->isVisible()) {
+ wBack->hide();
+ showButton->setText("Show");
+ } else {
+ wBack->show();
+ showButton->setText("Hide");
+ }
+ showBacklabels();
+ });
+ }
+};
+
+QLabel *deckListLabel;
+QVBoxLayout *hMdemScroll;
+QSpacerItem *mdemSpacer;
+QList mdems;
+QString workingPath = "/home/jorenchik/Code/mdemory/memorybase";
+
+void CreateMdems(QList& questions) {
+ if (mdemSpacer) {
+ hMdemScroll->removeItem(mdemSpacer);
+ }
+
+ for (Mdem *mdem : mdems) {
+ if (mdem->wMdem->isVisible()) {
+ mdem->wMdem->hide();
+ }
+ }
+
+ // TODO
+}
+
+void SwitchPage(int pageIdx, QList& pages, QList& mdems) {
+ for (Mdem *mdem : mdems) {
+ if (mdem->wBack->isVisible()) {
+ mdem->wBack->hide();
+ mdem->showButton->setText("Show");
+ }
+ }
+
+ // TODO
+}
+
+int main(int argc, char *argv[]) {
+ QApplication app(argc, argv);
+ QMainWindow window;
+
+ QSplitter *hSplitter = new QSplitter();
+
+ // LeftSide
+ QWidget *leftWidget = new QWidget();
+ QVBoxLayout *leftLayout = new QVBoxLayout();
+ QLabel *mdemLabel = new QLabel("Mdems");
+ QFileSystemModel *model = new QFileSystemModel();
+ QTreeView *mdemList = new QTreeView();
+
+ leftWidget->setLayout(leftLayout);
+ leftLayout->addWidget(mdemLabel);
+ model->setRootPath(workingPath);
+ mdemList->setModel(model);
+
+ QModelIndex rootIndex = model->index("/home/jorenchik/Code/mdemory/memorybase");
+ mdemList->setRootIndex(rootIndex);
+ leftLayout->addWidget(mdemList);
+
+ // DeckList
+ QLabel *deckLabel = new QLabel("Decks");
+ QListView *deckList = new QListView();
+ leftLayout->addWidget(deckLabel);
+ leftLayout->addWidget(deckList);
+
+ // RightSide
+ QWidget *rightWidget = new QWidget();
+ QVBoxLayout *rightLayout = new QVBoxLayout();
+ rightWidget->setLayout(rightLayout);
+
+ QWidget *top = new QWidget();
+ QHBoxLayout *hTop = new QHBoxLayout();
+ deckListLabel = new QLabel("Mdem: todo.mdem");
+ top->setLayout(hTop);
+ rightLayout->addWidget(top);
+
+ hTop->addWidget(deckListLabel);
+ hTop->addStretch(1);
+
+ QToolButton *refresh = new QToolButton();
+ QToolButton *practice = new QToolButton();
+ QToolButton *shuffle = new QToolButton();
+
+ hTop->addWidget(refresh);
+ hTop->addWidget(shuffle);
+ hTop->addWidget(practice);
+
+ // Buttons
+ refresh->setText("Refresh");
+ shuffle->setText("Shuffle");
+ practice->setText("Practice");
+
+ // Mdems
+ QScrollArea *mdemScroll = new QScrollArea();
+ QWidget *mdemContainer = new QWidget();
+ hMdemScroll = new QVBoxLayout();
+ mdemScroll->setWidget(mdemContainer);
+ mdemScroll->setWidgetResizable(true);
+ mdemContainer->setLayout(hMdemScroll);
+ rightLayout->addWidget(mdemScroll);
+
+ // Pagination
+ hSplitter->addWidget(leftWidget);
+ hSplitter->addWidget(rightWidget);
+ hSplitter->setStretchFactor(0, 1);
+ hSplitter->setStretchFactor(1, 3);
+
+ window.setCentralWidget(hSplitter);
+ window.show();
+ return app.exec();
+}
diff --git a/src/cpp/transpiler/.cache/clangd/index/api.h.09188030E1E1AD2B.idx b/src/cpp/transpiler/.cache/clangd/index/api.h.09188030E1E1AD2B.idx
new file mode 100644
index 0000000..3babb38
Binary files /dev/null and b/src/cpp/transpiler/.cache/clangd/index/api.h.09188030E1E1AD2B.idx differ
diff --git a/src/cpp/transpiler/.cache/clangd/index/config.h.37161B9BC74F84AB.idx b/src/cpp/transpiler/.cache/clangd/index/config.h.37161B9BC74F84AB.idx
new file mode 100644
index 0000000..cbe0f87
Binary files /dev/null and b/src/cpp/transpiler/.cache/clangd/index/config.h.37161B9BC74F84AB.idx differ
diff --git a/src/cpp/transpiler/.cache/clangd/index/lexer.cpp.83041CDDE7BB82EA.idx b/src/cpp/transpiler/.cache/clangd/index/lexer.cpp.83041CDDE7BB82EA.idx
new file mode 100644
index 0000000..a4c1a2a
Binary files /dev/null and b/src/cpp/transpiler/.cache/clangd/index/lexer.cpp.83041CDDE7BB82EA.idx differ
diff --git a/src/cpp/transpiler/.cache/clangd/index/lexer.h.56AED8998E88A18A.idx b/src/cpp/transpiler/.cache/clangd/index/lexer.h.56AED8998E88A18A.idx
new file mode 100644
index 0000000..75fe5a4
Binary files /dev/null and b/src/cpp/transpiler/.cache/clangd/index/lexer.h.56AED8998E88A18A.idx differ
diff --git a/src/cpp/transpiler/.cache/clangd/index/main.cpp.3110054129CACA6D.idx b/src/cpp/transpiler/.cache/clangd/index/main.cpp.3110054129CACA6D.idx
new file mode 100644
index 0000000..38c0024
Binary files /dev/null and b/src/cpp/transpiler/.cache/clangd/index/main.cpp.3110054129CACA6D.idx differ
diff --git a/src/cpp/transpiler/.cache/clangd/index/parser.cpp.1DA6C31FD012A889.idx b/src/cpp/transpiler/.cache/clangd/index/parser.cpp.1DA6C31FD012A889.idx
new file mode 100644
index 0000000..6231dc1
Binary files /dev/null and b/src/cpp/transpiler/.cache/clangd/index/parser.cpp.1DA6C31FD012A889.idx differ
diff --git a/src/cpp/transpiler/.cache/clangd/index/parser.h.A6B071E84CF21EB1.idx b/src/cpp/transpiler/.cache/clangd/index/parser.h.A6B071E84CF21EB1.idx
new file mode 100644
index 0000000..903df12
Binary files /dev/null and b/src/cpp/transpiler/.cache/clangd/index/parser.h.A6B071E84CF21EB1.idx differ
diff --git a/src/cpp/transpiler/.cache/clangd/index/result.h.9FDF8FE2A27152FF.idx b/src/cpp/transpiler/.cache/clangd/index/result.h.9FDF8FE2A27152FF.idx
new file mode 100644
index 0000000..ff249d2
Binary files /dev/null and b/src/cpp/transpiler/.cache/clangd/index/result.h.9FDF8FE2A27152FF.idx differ
diff --git a/src/cpp/transpiler/.cache/clangd/index/time.h.A5DECF25CDA82FFC.idx b/src/cpp/transpiler/.cache/clangd/index/time.h.A5DECF25CDA82FFC.idx
new file mode 100644
index 0000000..96863a0
Binary files /dev/null and b/src/cpp/transpiler/.cache/clangd/index/time.h.A5DECF25CDA82FFC.idx differ
diff --git a/src/cpp/transpiler/.gitignore b/src/cpp/transpiler/.gitignore
new file mode 100644
index 0000000..0f3a6b1
--- /dev/null
+++ b/src/cpp/transpiler/.gitignore
@@ -0,0 +1,2 @@
+Debug
+Release
diff --git a/src/cpp/transpiler/.vscode/launch.json b/src/cpp/transpiler/.vscode/launch.json
new file mode 100644
index 0000000..54d9930
--- /dev/null
+++ b/src/cpp/transpiler/.vscode/launch.json
@@ -0,0 +1,16 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "lldb",
+ "name": "C/C++: gcc.exe build and debug active file",
+ "request": "launch",
+ "program": "./Debug/transpiler",
+ "args": ["input.mdem"],
+ "cwd": "${fileDirname}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/cpp/transpiler/.vscode/settings.json b/src/cpp/transpiler/.vscode/settings.json
new file mode 100644
index 0000000..d12d5bd
--- /dev/null
+++ b/src/cpp/transpiler/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "cmake.configureOnOpen": true,
+ "cmake.generator": "Unix Makefiles", // might use Ninja too
+ "cmake.buildDirectory": "${workspaceFolder}/build"
+}
diff --git a/src/cpp/transpiler/.vscode/tasks.json b/src/cpp/transpiler/.vscode/tasks.json
new file mode 100644
index 0000000..182561b
--- /dev/null
+++ b/src/cpp/transpiler/.vscode/tasks.json
@@ -0,0 +1,12 @@
+{
+ "tasks": [
+ {
+ "label": "Build transpiler",
+ "command": "cmake",
+ "args": [
+ "--build Debug",
+ ],
+ }
+ ],
+ "version": "2.0.0"
+}
\ No newline at end of file
diff --git a/src/cpp/transpiler/CMakeLists.txt b/src/cpp/transpiler/CMakeLists.txt
new file mode 100644
index 0000000..ed250ef
--- /dev/null
+++ b/src/cpp/transpiler/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.10)
+project(MemoryTranspiler LANGUAGES CXX)
+
+# C++ standard spec
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+# Give info for intellisense
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+# Set sources
+set(SOURCES
+ main.cpp
+ lexer.cpp
+ parser.cpp
+ time.cpp
+ api.cpp
+)
+include_directories(${CMAKE_SOURCE_DIR}/include)
+
+# Add the executable (CLI)
+add_executable(transpiler ${SOURCES})
+target_compile_options(transpiler PRIVATE -Wall -Wextra -Wpedantic)
diff --git a/src/cpp/transpiler/api.cpp b/src/cpp/transpiler/api.cpp
new file mode 100644
index 0000000..bbcc7c1
--- /dev/null
+++ b/src/cpp/transpiler/api.cpp
@@ -0,0 +1,43 @@
+#include
+#include
+
+#include "api.h"
+#include "result.h"
+#include "lexer.h"
+#include "parser.h"
+#include "time.h"
+
+Result> Transpile(std::string fileContent) {
+ start = std::chrono::high_resolution_clock::now();
+ auto lexRes = TokenizeMdem(fileContent);
+ auto tokens = lexRes.value;
+ if (lexRes.error.length() > 0) {
+ return {
+ {},
+ std::format(
+ "Lexical analysis error: {}",
+ lexRes.error
+ ),
+ lexRes.row,
+ lexRes.column
+ };
+ }
+
+ auto parseRes = ParseQuestions(tokens);
+ auto questions = parseRes.value;
+ if (parseRes.error.length() > 0) {
+ return {
+ {},
+ std::format(
+ "Parsing error: {}",
+ parseRes.error
+ ),
+ parseRes.row,
+ parseRes.column
+ };
+ }
+
+ end = std::chrono::high_resolution_clock::now();
+ ShowTime("Transpilation time");
+ return {questions};
+}
diff --git a/src/cpp/transpiler/api.h b/src/cpp/transpiler/api.h
new file mode 100644
index 0000000..d5c75c1
--- /dev/null
+++ b/src/cpp/transpiler/api.h
@@ -0,0 +1,4 @@
+#include "result.h"
+#include "parser.h"
+
+Result> Transpile(std::string fileContent);
diff --git a/src/cpp/transpiler/compile_commands.json b/src/cpp/transpiler/compile_commands.json
new file mode 100644
index 0000000..8e57e25
--- /dev/null
+++ b/src/cpp/transpiler/compile_commands.json
@@ -0,0 +1,20 @@
+[
+{
+ "directory": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/Debug",
+ "command": "/usr/bin/g++ -I/home/jorenchik/Code/mdemory/src/cpp/transpiler/include -g -std=gnu++20 -Wall -Wextra -Wpedantic -o CMakeFiles/transpiler.dir/main.cpp.o -c /home/jorenchik/Code/mdemory/src/cpp/transpiler/main.cpp",
+ "file": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/main.cpp",
+ "output": "CMakeFiles/transpiler.dir/main.cpp.o"
+},
+{
+ "directory": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/Debug",
+ "command": "/usr/bin/g++ -I/home/jorenchik/Code/mdemory/src/cpp/transpiler/include -g -std=gnu++20 -Wall -Wextra -Wpedantic -o CMakeFiles/transpiler.dir/lexer.cpp.o -c /home/jorenchik/Code/mdemory/src/cpp/transpiler/lexer.cpp",
+ "file": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/lexer.cpp",
+ "output": "CMakeFiles/transpiler.dir/lexer.cpp.o"
+},
+{
+ "directory": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/Debug",
+ "command": "/usr/bin/g++ -I/home/jorenchik/Code/mdemory/src/cpp/transpiler/include -g -std=gnu++20 -Wall -Wextra -Wpedantic -o CMakeFiles/transpiler.dir/parser.cpp.o -c /home/jorenchik/Code/mdemory/src/cpp/transpiler/parser.cpp",
+ "file": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/parser.cpp",
+ "output": "CMakeFiles/transpiler.dir/parser.cpp.o"
+}
+]
\ No newline at end of file
diff --git a/src/cpp/transpiler/config.h b/src/cpp/transpiler/config.h
new file mode 100644
index 0000000..58f8154
--- /dev/null
+++ b/src/cpp/transpiler/config.h
@@ -0,0 +1,4 @@
+#pragma once
+
+extern bool debug;
+
diff --git a/src/cpp/transpiler/lexer.cpp b/src/cpp/transpiler/lexer.cpp
new file mode 100644
index 0000000..81446fd
--- /dev/null
+++ b/src/cpp/transpiler/lexer.cpp
@@ -0,0 +1,284 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "lexer.h"
+#include "config.h"
+#include "result.h"
+
+std::vector tokens;
+std::vector buffer;
+int32_t row;
+int32_t column;
+int32_t previousRow;
+int32_t previousColumn;
+bool textStarted = false;
+bool identifierStarted = false;
+
+void trimString(std::string &str, std::string trimChars) {
+ int padSize = 0;
+ bool pad = false;
+ for (size_t i = 0; i < str.size(); ++i) {
+ for (size_t k = 0; k < trimChars.size(); ++k) {
+ if (str[i] == trimChars[k]) {
+ padSize++;
+ pad = true;
+ break;
+ }
+ }
+ if (!pad) {
+ break;
+ }
+ pad = false;
+ }
+ if (padSize > 0) {
+ str.erase(0, padSize);
+ }
+ padSize = 0;
+ pad = false;
+ for (size_t i = str.size(); i-- > 0;) {
+ for (size_t k = 0; k < trimChars.size(); ++k) {
+ if (str[i] == trimChars[k]) {
+ padSize++;
+ pad = true;
+ break;
+ }
+ }
+ if (!pad) {
+ break;
+ }
+ pad = false;
+ }
+ if (padSize > 0) {
+ str.erase(str.end() - padSize, str.end());
+ }
+}
+
+void makeTokenWithTokenBuffer(
+ TokenType ttype,
+ size_t tokenLen,
+ TokenType textType
+) {
+ std::string token(buffer.end() - tokenLen, buffer.end());
+ if (buffer.size() > tokenLen) {
+ std::string prevFragment(buffer.begin(), buffer.end() - tokenLen);
+ trimString(prevFragment, " \n\t");
+ if (prevFragment.length() > 0) {
+ tokens.push_back(Token{
+ textType,
+ prevFragment,
+ previousRow,
+ previousColumn
+ });
+ }
+ }
+ buffer.clear();
+
+ tokens.push_back(Token{
+ ttype,
+ token,
+ row,
+ column
+ });
+
+ previousRow = row;
+ previousColumn = column;
+ buffer.clear();
+}
+
+Result> TokenizeMdem(const std::string& fileRunes) {
+ row = 1;
+ column = 1;
+ previousRow = 1;
+ previousColumn = 1;
+ textStarted = false;
+ tokens.clear();
+ buffer.clear();
+
+ if (fileRunes.find_first_not_of(" \n\t") == std::string::npos) {
+ return {tokens, ""};
+ }
+
+ for (size_t i = 0; i < fileRunes.size(); ++i) {
+ char c = fileRunes[i];
+
+ // AdvancePointer
+ if (c == '\n') {
+ row += 1;
+ column = 0;
+ }
+ buffer.push_back(c);
+
+ // SkipWhitetext
+ if (!textStarted) {
+ if (c == '\n') {
+ previousRow += 1;
+ previousColumn = 1;
+ } else if (c == ' ') {
+ previousColumn += 1;
+ } else if (c == '\t') {
+ previousColumn += 4;
+ } else {
+ textStarted = true;
+ }
+ }
+
+ // EmitTokens
+ switch (c) {
+ case '[':
+ makeTokenWithTokenBuffer(
+ TokenType::IdentifierStart,
+ 1,
+ TokenType::TextFragment
+ );
+ previousRow = row;
+ previousColumn = column;
+ textStarted = false;
+ identifierStarted = true;
+ break;
+ case ']':
+ if (!identifierStarted) {
+ return {
+ tokens,
+ "Cannot end identifier if it is not started",
+ tokens[i].row,
+ tokens[i].column
+ };
+ }
+ makeTokenWithTokenBuffer(
+ TokenType::IdentifierEnd,
+ 1,
+ TokenType::Identifier
+ );
+ previousRow = row;
+ previousColumn = column;
+ textStarted = false;
+ identifierStarted = false;
+ break;
+ case '#':
+ makeTokenWithTokenBuffer(
+ TokenType::SectionIdentifierStart,
+ 1,
+ TokenType::TextFragment
+ );
+ previousRow = row;
+ previousColumn = column;
+ textStarted = false;
+ break;
+ case '{':
+ makeTokenWithTokenBuffer(
+ TokenType::SectionStart,
+ 1,
+ TokenType::Identifier
+ );
+ previousRow = row;
+ previousColumn = column;
+ textStarted = false;
+ break;
+ case '}':
+ makeTokenWithTokenBuffer(
+ TokenType::SectionEnd,
+ 1,
+ TokenType::TextFragment
+ );
+ previousRow = row;
+ previousColumn = column;
+ textStarted = false;
+ break;
+ case '-':
+ makeTokenWithTokenBuffer(
+ TokenType::ElementDashStart,
+ 1,
+ TokenType::TextFragment
+ );
+ previousRow = row;
+ previousColumn = column;
+ textStarted = false;
+ break;
+ case '>':
+ makeTokenWithTokenBuffer(
+ TokenType::QuestionEnd,
+ 1,
+ TokenType::TextFragment
+ );
+ previousRow = row;
+ previousColumn = column;
+ break;
+ case '+':
+ makeTokenWithTokenBuffer(
+ TokenType::ElementPlusStart,
+ 1,
+ TokenType::TextFragment
+ );
+ previousRow = row;
+ previousColumn = column;
+ textStarted = false;
+ break;
+ }
+
+ column += 1;
+ }
+
+ makeTokenWithTokenBuffer(
+ TokenType::EndOfFile,
+ 0,
+ TokenType::TextFragment
+ );
+
+ if (debug) {
+ std::cout << "SECTION: Lexer output:\n";
+ std::cout << std::format("Token count: {}", tokens.size()) << std::endl;
+ for (const Token& token : tokens) {
+ std::cout << token.ToString();
+ }
+ std::cout << "SECTION END: Lexer output\n";
+ }
+
+ return {tokens, ""};
+}
+
+std::regex nextLineExp(
+ "\n",
+ std::regex_constants::ECMAScript
+);
+
+std::regex doubleSpaceExp(
+ "\\s\\s+",
+ std::regex_constants::ECMAScript
+);
+
+std::string Token::ToString(const TokenType* ttype) {
+ switch (*ttype) {
+ case TokenType::TextFragment: return "text fragment";
+ case TokenType::QuestionEnd: return "question end symbol";
+ case TokenType::ElementDashStart: return "dash element start";
+ case TokenType::ElementPlusStart: return "plus element start";
+ case TokenType::Identifier: return "identifier";
+ case TokenType::IdentifierStart: return "start of identifier";
+ case TokenType::IdentifierEnd: return "end of identifier";
+ case TokenType::SectionIdentifierStart: return "section identifier start";
+ case TokenType::SectionStart: return "start of section";
+ case TokenType::SectionEnd: return "end of section";
+ case TokenType::EndOfFile: return "end of file";
+ default: return "unrecognized token";
+ }
+}
+
+std::string Token::ToString() const {
+ std::string contentStr = content;
+ if (tokenType == TokenType::TextFragment) {
+ contentStr = std::regex_replace(contentStr, nextLineExp, "");
+ contentStr = std::regex_replace(contentStr, doubleSpaceExp, " ");
+ }
+ return std::format(
+ "{}: \"{}\" ({}:{})\n",
+ ToString(&tokenType),
+ contentStr,
+ row,
+ column
+ );
+}
diff --git a/src/cpp/transpiler/lexer.h b/src/cpp/transpiler/lexer.h
new file mode 100644
index 0000000..10cebb1
--- /dev/null
+++ b/src/cpp/transpiler/lexer.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+#include
+
+#include "result.h"
+
+enum class TokenType {
+ TextFragment,
+ QuestionEnd,
+ ElementDashStart,
+ ElementPlusStart,
+ Identifier,
+ IdentifierStart,
+ IdentifierEnd,
+ SectionIdentifierStart,
+ SectionStart,
+ SectionEnd,
+ SOF,
+ EndOfFile
+};
+
+struct Token {
+ TokenType tokenType;
+ std::string content;
+ int32_t row;
+ int32_t column;
+
+ std::string ToString() const;
+ static std::string ToString(const TokenType* ttype);
+};
+
+Result> TokenizeMdem(const std::string& fileRunes);
diff --git a/src/cpp/transpiler/main.cpp b/src/cpp/transpiler/main.cpp
new file mode 100644
index 0000000..424cd6b
--- /dev/null
+++ b/src/cpp/transpiler/main.cpp
@@ -0,0 +1,82 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "api.h"
+#include "parser.h"
+#include "time.h"
+#include "config.h"
+
+std::string readFile(const std::string& filePath) {
+ std::ifstream file(filePath);
+ if (!file.is_open()) {
+ throw std::runtime_error("Cannot open file: " + filePath);
+ }
+
+ std::string content;
+ std::string line;
+ while (std::getline(file, line)) {
+ content += line + '\n';
+ }
+
+ file.close();
+ return content;
+}
+
+bool debug = false;
+
+std::chrono::high_resolution_clock::time_point start;
+std::chrono::high_resolution_clock::time_point end;
+
+int main(int argc, char* argv[]) {
+ std::string filePath;
+
+ if (argc == 3) {
+ auto option = std::string(argv[1]);
+ if (option == "--debug") {
+ debug = true;
+ } else {
+ std::cout << std::format("Unrecognized option: {}", option) << std::endl;
+ return 1;
+ }
+ filePath = argv[2];
+ } else if (argc == 2) {
+ filePath = argv[1];
+ } else {
+ std::cerr << "Usage: " << argv[0] << " \n";
+ return 1;
+ }
+
+ try {
+ start = std::chrono::high_resolution_clock::now();
+ std::string fileContent = readFile(filePath);
+ end = std::chrono::high_resolution_clock::now();
+ ShowTime("I/O time");
+
+ auto res = Transpile(fileContent);
+ auto questions = res.value;
+ if (res.error.length() > 0) {
+ std::cout << std::format(
+ "{} ({}:{})\n",
+ res.error,
+ res.row,
+ res.column
+ );
+ return 1;
+ }
+
+ for (Question* question: questions) {
+ delete question;
+ }
+
+ } catch (std::exception &e) {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/cpp/transpiler/parser.cpp b/src/cpp/transpiler/parser.cpp
new file mode 100644
index 0000000..0ab7607
--- /dev/null
+++ b/src/cpp/transpiler/parser.cpp
@@ -0,0 +1,278 @@
+#include
+#include
+#include
+#include
+#include