restrutured removing the go source

This commit is contained in:
jorenchik
2024-10-14 21:13:44 +03:00
parent ff4beecb5b
commit 2cef7007a2
138 changed files with 9911 additions and 1209 deletions

3
src/transpiler/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
Debug
Release
.cache

16
src/transpiler/.vscode/launch.json vendored Normal file
View File

@@ -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}"
}
]
}

5
src/transpiler/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"cmake.configureOnOpen": true,
"cmake.generator": "Unix Makefiles", // might use Ninja too
"cmake.buildDirectory": "${workspaceFolder}/build"
}

12
src/transpiler/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,12 @@
{
"tasks": [
{
"label": "Build transpiler",
"command": "cmake",
"args": [
"--build Debug",
],
}
],
"version": "2.0.0"
}

View File

@@ -0,0 +1,22 @@
# Set sources
set(
SOURCES
main.cpp
)
add_library(
api
lexer.cpp
parser.cpp
time.cpp
api.cpp
stringUtils.cpp
)
add_executable(transpiler ${SOURCES})
target_link_libraries(transpiler api)
target_compile_options(transpiler PRIVATE -Wall -Wextra -Wpedantic)
target_include_directories(transpiler PRIVATE ${CMAKE_SOURCE_DIR}/include)
target_include_directories(api PUBLIC ${CMAKE_SOURCE_DIR}/include)

127
src/transpiler/api.cpp Normal file
View File

@@ -0,0 +1,127 @@
#include <sstream>
#include <vector>
#include <chrono>
#include "api.h"
#include "result.h"
#include "lexer.h"
#include "parser.h"
#include "time.h"
#include "config.h"
#define TABWIDTH 4
bool debug;
std::chrono::high_resolution_clock::time_point start;
std::chrono::high_resolution_clock::time_point end;
std::string wrapText(std::string text, size_t width) {
std::string result;
size_t currentLineLength = 0;
size_t wordStart = 0;
size_t preservedSpaceCount = 0;
for (size_t i = 0; i < text.length(); ++i) {
if (text[i] == '\t') {
preservedSpaceCount += TABWIDTH;
} else if (!std::isalnum(text[i])) {
preservedSpaceCount++;
} else {
wordStart = i;
break;
}
}
result += text.substr(0, wordStart);
currentLineLength = preservedSpaceCount;
for (size_t i = wordStart; i < text.length(); ++i) {
if (text[i] == ' ' || i == text.length() - 1) {
size_t wordEnd = (i == text.length() - 1) ? i + 1 : i; // Handle the last word
size_t wordLength = wordEnd - wordStart;
if (currentLineLength + wordLength > width) {
result += '\n';
result.append(preservedSpaceCount / TABWIDTH, '\t');
result.append(preservedSpaceCount % TABWIDTH, ' ');
currentLineLength = preservedSpaceCount;
}
result += text.substr(wordStart, wordLength) + ' ';
currentLineLength += wordLength + 1;
wordStart = i + 1;
}
}
return result;
}
std::string escapeText(std::string text) {
std::stringstream ss;
for (auto c: text) {
switch(c) {
case '\\':
ss << "\\\\";
break;
case '[':
ss << "\\[";
break;
case ']':
ss << "\\]";
break;
case '-':
ss << "\\-";
break;
case '^':
ss << "\\^";
break;
case ':':
ss << "\\:";
break;
case '>':
ss << "\\>";
break;
case '+':
ss << "\\+";
break;
default:
ss << c;
break;
}
}
return ss.str();
}
Result<ParseInfo> transpile(std::string fileContent, bool isDebug) {
start = std::chrono::high_resolution_clock::now();
end = std::chrono::high_resolution_clock::now();
debug = isDebug;
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};
}

View File

@@ -0,0 +1,32 @@
[
{
"directory": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/transpiler",
"command": "/usr/bin/g++ -I/home/jorenchik/Code/mdemory/src/cpp/include -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": "transpiler/CMakeFiles/transpiler.dir/main.cpp.o"
},
{
"directory": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/transpiler",
"command": "/usr/bin/g++ -I/home/jorenchik/Code/mdemory/src/cpp/include -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": "transpiler/CMakeFiles/transpiler.dir/lexer.cpp.o"
},
{
"directory": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/transpiler",
"command": "/usr/bin/g++ -I/home/jorenchik/Code/mdemory/src/cpp/include -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": "transpiler/CMakeFiles/transpiler.dir/parser.cpp.o"
},
{
"directory": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/transpiler",
"command": "/usr/bin/g++ -I/home/jorenchik/Code/mdemory/src/cpp/include -std=gnu++20 -Wall -Wextra -Wpedantic -o CMakeFiles/transpiler.dir/time.cpp.o -c /home/jorenchik/Code/mdemory/src/cpp/transpiler/time.cpp",
"file": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/time.cpp",
"output": "transpiler/CMakeFiles/transpiler.dir/time.cpp.o"
},
{
"directory": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/transpiler",
"command": "/usr/bin/g++ -I/home/jorenchik/Code/mdemory/src/cpp/include -std=gnu++20 -Wall -Wextra -Wpedantic -o CMakeFiles/transpiler.dir/api.cpp.o -c /home/jorenchik/Code/mdemory/src/cpp/transpiler/api.cpp",
"file": "/home/jorenchik/Code/mdemory/src/cpp/transpiler/api.cpp",
"output": "transpiler/CMakeFiles/transpiler.dir/api.cpp.o"
}
]

284
src/transpiler/lexer.cpp Normal file
View File

@@ -0,0 +1,284 @@
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <format>
#include <regex>
#include "lexer.h"
#include "config.h"
#include "result.h"
std::vector<Token> tokens;
std::vector<char> buffer;
int32_t row;
int32_t column;
int32_t previousRow;
int32_t previousColumn;
bool textStarted = false;
bool identifierStarted = false;
bool sof;
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<std::vector<Token>> 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;
}
if (c == '\\') {
i += 1;
if (i < fileRunes.size()) {
buffer.push_back(fileRunes[i]);
}
continue;
} else {
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::CooldownStart,
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::CooldownEnd,
1,
TokenType::Cooldown
);
previousRow = row;
previousColumn = column;
textStarted = false;
identifierStarted = false;
break;
case '-':
makeTokenWithTokenBuffer(
TokenType::ElementDashStart,
1,
TokenType::TextFragment
);
previousRow = row;
previousColumn = column;
textStarted = false;
break;
case '^':
makeTokenWithTokenBuffer(
TokenType::ElementOrderModifier,
1,
TokenType::TextFragment
);
previousRow = row;
previousColumn = column;
textStarted = false;
break;
case ':':
makeTokenWithTokenBuffer(
TokenType::MatchGroupEnd,
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::MatchGroupEnd: return "match group end";
case TokenType::ElementDashStart: return "dash element start";
case TokenType::ElementOrderModifier: return "order element modifier";
case TokenType::ElementPlusStart: return "plus element start";
case TokenType::Cooldown: return "cooldown";
case TokenType::CooldownStart: return "start of cooldown";
case TokenType::CooldownEnd: return "end of cooldown";
case TokenType::StartOfFile: return "start of the file";
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
);
}

74
src/transpiler/main.cpp Normal file
View File

@@ -0,0 +1,74 @@
#include <exception>
#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include "time.h"
#include "api.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;
}
int main(int argc, char* argv[]) {
std::string filePath;
bool debug = false;
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] << " <file-path>\n";
return 1;
}
try {
std::string fileContent = readFile(filePath);
end = std::chrono::high_resolution_clock::now();
showTime("I/O time");
auto res = transpile(fileContent, debug);
auto questions = res.value.questions;
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;
}

387
src/transpiler/parser.cpp Normal file
View File

@@ -0,0 +1,387 @@
#include <cstdio>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <sstream>
#include <format>
#include "config.h"
#include "lexer.h"
#include "result.h"
#include "parser.h"
#include "stringUtils.h"
struct QuestionElement {
bool isDash;
bool isGroup;
std::string content;
};
std::string MultiElementQuestion::ToString() const {
std::stringstream ss;
for (const auto& choice : Choices) {
char opener;
if (type == MultiElementType::Order) {
opener = '^';
} else if (choice.IsCorrect) {
opener = '+';
} else {
opener = '-';
}
ss << opener << " " << choice.Answer << "; ";
}
return std::format(
"<Multiple element>\nsection:{}\nid:{}\n{}\n{}",
Section,
Cooldown,
QuestionText,
ss.str()
);
}
std::string GroupQuestion::ToString() const {
std::stringstream ss;
for (auto group: Groups) {
ss << group.name << ": ";
for (auto el: group.elements) {
ss << el << ", ";
}
ss << "; ";
}
return std::format(
"<GroupQuestion>\nsection:{}\nid:{}\n{}\n{}",
Section,
Cooldown,
QuestionText,
ss.str()
);
}
// Automaton for validating token transitions
std::map<TokenType, std::vector<TokenType>> automata;
bool contains(const std::vector<TokenType>& vec, TokenType element) {
return std::find(vec.begin(), vec.end(), element) != vec.end();
}
// Automata for validating the parser state
std::map<TokenType, std::vector<TokenType>> parserAutomata() {
std::map<TokenType, std::vector<TokenType>> automata;
automata[TokenType::TextFragment] = {
TokenType::QuestionEnd,
TokenType::ElementDashStart,
TokenType::ElementPlusStart,
TokenType::MatchGroupEnd,
TokenType::EndOfFile,
};
automata[TokenType::MatchGroupEnd] = {
TokenType::ElementDashStart
};
automata[TokenType::QuestionEnd] = {
TokenType::ElementDashStart,
TokenType::ElementPlusStart
};
automata[TokenType::ElementDashStart] = {
TokenType::CooldownStart,
TokenType::TextFragment,
TokenType::ElementOrderModifier
};
automata[TokenType::ElementOrderModifier] = {
TokenType::TextFragment
};
automata[TokenType::ElementPlusStart] = {
TokenType::TextFragment
};
automata[TokenType::Cooldown] = {
TokenType::CooldownEnd,
};
automata[TokenType::CooldownStart] = {
TokenType::Cooldown
};
automata[TokenType::CooldownEnd] = {
TokenType::TextFragment
};
automata[TokenType::StartOfFile] = {
TokenType::TextFragment,
TokenType::ElementDashStart,
TokenType::EndOfFile
};
automata[TokenType::EndOfFile] = {};
return automata;
}
std::string capitalize(const std::string& str) {
if (str.empty()) return str;
std::string result = str;
result[0] = std::towupper(result[0]);
return result;
}
Result<NoneType> ValidateGrammar(const std::vector<Token>& tokens) {
automata = parserAutomata();
for (size_t i = 0; i < tokens.size() - 1; ++i) {
Token token = tokens[i];
Token nextToken = tokens[i + 1];
if (!contains(automata[token.tokenType], nextToken.tokenType)) {
return {
.error=std::format(
"Invalid token sequence: {} cannot precede {}",
std::string(capitalize(Token::ToString(&token.tokenType))),
std::string(capitalize(Token::ToString(&nextToken.tokenType)))
),
.row=token.row,
.column=token.column
};
}
}
return {};
}
Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
auto questions = std::vector<Question*>();
time_t time = 0;
auto makeResult = [&questions, &time](std::string error, Token token) -> Result<ParseInfo> {
return {
{ questions, time },
error,
token.row,
token.column
};
};
if (tokens.size() == 0) {
return makeResult("", Token());
}
auto result = ValidateGrammar(tokens);
if (result.error.length() > 0) {
return makeResult(
result.error,
Token{.row=result.row, .column=result.column}
);
}
std::string section;
size_t i = 0;
if (debug) {
std::cout << "SECTION: Parser output:\n";
}
auto isInBounds = [tokens](size_t i) {
return i < tokens.size() && tokens[i].tokenType != TokenType::EndOfFile;
};
if (isInBounds(i) && tokens[i].tokenType == TokenType::TextFragment) {
std::tm tm = {};
try {
strptime(tokens[i].content.c_str(), "%d.%m.%Y %H:%M", &tm);
} catch (std::exception e) {
return makeResult(
std::format("cannot parse the time - {}", e.what()),
tokens[i]
);
}
time = mktime(&tm);
i++;
}
while (i < tokens.size()) {
if (tokens[i].tokenType == TokenType::ElementDashStart) {
std::string questionText;
std::vector<QuestionElement> questionElements;
double cooldown;
bool isOrderQuestion = false;
bool isGroupQuestion = false;
bool isPlusQuestion = false;
// Start element parsing & add to the offset.
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
return makeResult(
"cannot have order modifier ('^') in the question definition",
tokens[i + 1]
);
}
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::CooldownStart) {
try {
cooldown = std::stod(tokens[i + 2].content);
} catch (std::exception e) {
return makeResult(
"error parsing cooldown",
tokens[i + 1]
);
}
questionText = tokens[i + 4].content;
i += 6;
} else {
cooldown = 0;
questionText = tokens[i + 1].content;
i += 3;
}
// Parse elements of a question.
while (isInBounds(i)) {
// Check question end.
if (isInBounds(i + 3) && tokens[i].tokenType == TokenType::ElementDashStart) {
// Distance to the possible question end.
size_t offset;
if (tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
offset = tokens[i + 2].tokenType == TokenType::CooldownStart ? 6 : 3;
} else {
offset = tokens[i + 1].tokenType == TokenType::CooldownStart ? 5 : 2;
}
if (isInBounds(i + offset) && tokens[i + offset].tokenType == TokenType::QuestionEnd) {
break;
}
if (offset == 5 && tokens[i + 5].tokenType != TokenType::QuestionEnd) {
// Cannot place the identifier on the ordinary element.
return makeResult(
"Invalid identifier placement",
tokens[i]
);
}
}
// Determine element type.
bool isDash;
bool isGroup = false;
bool isOrder = false;
if (tokens[i].tokenType == TokenType::ElementDashStart) {
isDash = true;
} else {
isDash = false;
isPlusQuestion = true;
}
if (isInBounds(i+1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
isOrder = true;
isOrderQuestion = true;
if (!isDash) {
return makeResult(
"order questions can only be used with dashes ('-')",
tokens[i]
);
}
if (isGroupQuestion) {
return makeResult(
"question with groups cannot be ordered ('-^' and ':')",
tokens[i]
);
}
if (isInBounds(i + 3) && tokens[i + 3].tokenType == TokenType::MatchGroupEnd) {
return makeResult(
"cannot have groups in order question('-^' and ':')",
tokens[i]
);
}
}
if (isInBounds(i + 2) && tokens[i + 2].tokenType == TokenType::MatchGroupEnd) {
isGroup = true;
isGroupQuestion = true;
if (!isDash) {
return makeResult(
"group questions can only be used with dashes ('-')",
tokens[i]
);
}
}
QuestionElement questionElement;
questionElement.isDash = isDash;
questionElement.isGroup = isGroup;
if (isOrder) {
questionElement.content = tokens[i + 2].content;
} else {
questionElement.content = tokens[i + 1].content;
}
questionElements.push_back(questionElement);
size_t offset = 2;
if (isOrder) {
offset += 1;
}
if (isGroup) {
offset += 1;
}
i += offset;
}
if (questionElements.size() > 0) {
if (isGroupQuestion) {
auto *question = new GroupQuestion();
question->Cooldown = cooldown;
question->QuestionText = questionText;
question->Section = section;
int32_t k = -1;
for (size_t i = 0; i < questionElements.size(); ++i) {
auto questionElement = questionElements[i];
if (questionElement.isGroup) {
++k;
auto group = Group();
group.name = cleanContent(questionElement.content);
question->Groups.push_back(group);
} else {
if (k >= 0) {
question->Groups[k].elements.push_back(
cleanContent(
questionElement.content
)
);
}
}
}
questions.push_back(question);
if (debug) {
std::cout << question->ToString() << "\n";
}
} else {
auto *question = new MultiElementQuestion();
question->Cooldown = cooldown;
question->QuestionText = cleanContent(questionText);
question->Section = section;
for (const auto& elem : questionElements) {
Choice choice;
choice.Answer = cleanContent(elem.content);
choice.IsCorrect = !elem.isDash;
question->Choices.push_back(choice);
}
questions.push_back(question);
if (isPlusQuestion) {
question->type = MultiElementType::MultiChoice;
} else if (isOrderQuestion) {
question->type = MultiElementType::Order;
} else {
question->type = MultiElementType::Regular;
}
if (debug) {
std::cout << question->ToString() << "\n";
}
}
}
} else if (tokens[i].tokenType == TokenType::EndOfFile) {
if (debug) {
std::cout << "File terminated: EndOfFile\n";
}
break;
} else {
return makeResult(
"Unexpected token encountered",
tokens[i]
);
}
}
if (debug) {
std::cout << "SECTION END: Parser output:\n";
}
return makeResult(
"",
Token()
);
}

View File

@@ -0,0 +1,25 @@
#include <regex>
#include "stringUtils.h"
const std::regex doubleOrMoreSpaceExp(
"\\s\\s+",
std::regex_constants::ECMAScript | std::regex_constants::icase
);
const std::regex tabExp(
"\\t+",
std::regex_constants::ECMAScript | std::regex_constants::icase
);
const std::regex newLineExp(
"\\n+",
std::regex_constants::ECMAScript | std::regex_constants::icase
);
std::string cleanContent(std::string answer) {
answer = std::regex_replace(answer, newLineExp, "");
answer = std::regex_replace(answer, tabExp, " ");
answer = std::regex_replace(answer, doubleOrMoreSpaceExp, " ");
return answer;
}

10
src/transpiler/time.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include <cmath>
#include <iostream>
#include "time.h"
void showTime(std::string label) {
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
double_t msDuration = (double_t) duration.count() / 1000;
std::cout << std::format("{}: {:.3f} ms", label, msDuration) << std::endl;
}

8
src/transpiler/time.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include<chrono>
extern std::chrono::high_resolution_clock::time_point start;
extern std::chrono::high_resolution_clock::time_point end;
void showTime(std::string label);