diff --git a/src/transpiler/lexer.cpp b/src/transpiler/lexer.cpp index f1f19db..7866989 100644 --- a/src/transpiler/lexer.cpp +++ b/src/transpiler/lexer.cpp @@ -17,11 +17,12 @@ int32_t column; int32_t previousRow; int32_t previousColumn; bool textStarted = false; -bool identifierStarted = false; +bool cooldownStarted = false; bool sof; /* - * TODO + * Noņem norādītos simbolus no simbolu virknes kreisās un labās pusēs. + * Simboli tiek noņemti līdz tiek sastapts simbols, kas nav norādīts. */ void trimString(std::string *str, std::string trimChars) { @@ -123,12 +124,14 @@ Result> tokenizeMdem(const std::string& content) { for (size_t i = 0; i < content.size(); ++i) { char c = content[i]; - // Apstrādā īpašos simbolus un tekstu. + // Pavirza faila norādi un papildina buferi. if (c == '\n') { row += 1; column = 0; } if (c == '\\') { + // Simbolus, kas abilst citām tekstvienībām, var ievadīt, + // ja pirms tiem ieliek '\' simbolu. i += 1; if (i < content.size()) { buffer.push_back(content[i]); @@ -137,6 +140,7 @@ Result> tokenizeMdem(const std::string& content) { } else { buffer.push_back(c); } + // Iepriekšējā tekstvienības pozīcijas uzturēšana. if (!textStarted) { if (c == '\n') { previousRow += 1; @@ -150,7 +154,7 @@ Result> tokenizeMdem(const std::string& content) { } } - // Emitē tekstvienības. + // Izveido viena simbola tekstvienības, ja tāda ir sastapta. switch (c) { case '[': { tokenWithBuffer( @@ -161,13 +165,16 @@ Result> tokenizeMdem(const std::string& content) { previousRow = row; previousColumn = column; textStarted = false; - identifierStarted = true; + + // Karodziņš, lai zinātu, kad ir jānosaka pārtraukuma + // tekstvienību. + cooldownStarted = true; } break; case ']': { - if (!identifierStarted) { + if (!cooldownStarted) { return { tokens, - "Nevar beigt identifikatoru, ja tas nav iesākts", + "Nevar beigt pārtraukuma norādīšanu, ja tas nav iesākts", tokens[i].row, tokens[i].column }; @@ -180,7 +187,7 @@ Result> tokenizeMdem(const std::string& content) { previousRow = row; previousColumn = column; textStarted = false; - identifierStarted = false; + cooldownStarted = false; } break; case '-': { tokenWithBuffer( @@ -255,9 +262,13 @@ Result> tokenizeMdem(const std::string& content) { std::cout << "SECTION END: LEXER\n"; } + // Leksiskā analīze ir veiksmīga - neatgriež kļūdu. return {tokens, ""}; } +/* + * Tekstvienības nosaukums latviešu valodā. + */ std::string Token::toString(const TokenType* ttype) { switch (*ttype) { case TokenType::TextFragment: return "teksta fragments"; @@ -275,6 +286,9 @@ std::string Token::toString(const TokenType* ttype) { } } +/* + * Tekstvienību reprezentējoša simbolu virkne atkļūdošanai. + */ std::string Token::toString() const { std::string contentStr = content; static const std::regex nextLineExp("\n", std::regex_constants::ECMAScript); diff --git a/src/transpiler/parser.cpp b/src/transpiler/parser.cpp index 8be8f92..57d8adc 100644 --- a/src/transpiler/parser.cpp +++ b/src/transpiler/parser.cpp @@ -10,80 +10,81 @@ #include #include - #include "config.h" #include "lexer.h" #include "result.h" #include "parser.h" #include "stringUtils.h" -typedef std::map> TokenAutomata; +typedef std::map> TokenTransitions; -TokenAutomata *automata = nullptr; +TokenTransitions *transitions = nullptr; /* * Tekstvienību secības pārejas, kas nosaka, kādā secībā tekstvienības var būt. + * Pāreja no tekstvienības A uz tekstvienību B ir atļauta, tikai ja sarakstā ar + * atslēgu tekstvienībā A ir tekstvienība B. * */ -void initParserAutomata() { - automata = new TokenAutomata; - (*automata)[TokenType::TextFragment] = { +void initTransitions() { + transitions = new TokenTransitions; + (*transitions)[TokenType::TextFragment] = { TokenType::QuestionEnd, TokenType::ElementDashStart, TokenType::ElementPlusStart, TokenType::MatchGroupEnd, TokenType::EndOfFile, }; - (*automata)[TokenType::MatchGroupEnd] = { + (*transitions)[TokenType::MatchGroupEnd] = { TokenType::ElementDashStart }; - (*automata)[TokenType::QuestionEnd] = { + (*transitions)[TokenType::QuestionEnd] = { TokenType::ElementDashStart, TokenType::ElementPlusStart }; - (*automata)[TokenType::ElementDashStart] = { + (*transitions)[TokenType::ElementDashStart] = { TokenType::CooldownStart, TokenType::TextFragment, TokenType::ElementOrderModifier }; - (*automata)[TokenType::ElementOrderModifier] = { + (*transitions)[TokenType::ElementOrderModifier] = { TokenType::TextFragment }; - (*automata)[TokenType::ElementPlusStart] = { + (*transitions)[TokenType::ElementPlusStart] = { TokenType::TextFragment }; - (*automata)[TokenType::Cooldown] = { + (*transitions)[TokenType::Cooldown] = { TokenType::CooldownEnd, }; - (*automata)[TokenType::CooldownStart] = { + (*transitions)[TokenType::CooldownStart] = { TokenType::Cooldown }; - (*automata)[TokenType::CooldownEnd] = { + (*transitions)[TokenType::CooldownEnd] = { TokenType::TextFragment }; - (*automata)[TokenType::StartOfFile] = { + (*transitions)[TokenType::StartOfFile] = { TokenType::TextFragment, TokenType::ElementDashStart, TokenType::EndOfFile }; - (*automata)[TokenType::EndOfFile] = {}; + (*transitions)[TokenType::EndOfFile] = {}; } /* - * Pārbauda, vai vai tekstvienību sarakstu akceptē atbilst atbilst valodas - * automāts. + * Pārbauda, vai tekstvienību saraksts atbilst valodas + * definētām pieļaujamām pārejām. * */ Result ValidateGrammar(const std::vector& tokens) { - if (!automata) { - initParserAutomata(); + if (!transitions) { + initTransitions(); } for (size_t i = 0; i < tokens.size() - 1; ++i) { Token token = tokens[i]; Token nextToken = tokens[i + 1]; if ( std::find( - (*automata)[token.tokenType].begin(), - (*automata)[token.tokenType].end(), + (*transitions)[token.tokenType].begin(), + (*transitions)[token.tokenType].end(), nextToken.tokenType - ) == (*automata)[token.tokenType].end()) { + ) == (*transitions)[token.tokenType].end()) { auto capitalize = [](const std::string& str) { if (str.empty()) return str; @@ -105,13 +106,24 @@ Result ValidateGrammar(const std::vector& tokens) { return {}; } -// @Fix: Prevent duplicate group names and questions in ordered question (to -// simplify checking in practice). +// @Fix: before EOF is acceptable +// @Fix: remove section from questions + +/* + * Apstrādā tekstvienības, iegūstot datumu un laiku un vienu vai vairākus + * dažāda veida jautājumus. Veiksmes gadījumā atgriež jautājumu norādes un + * datumu un laiku, ja tāds bija norādīts. Kļūdas gadījumā atgriež jautājumu + * norādes un kļūdu ar to atrašanos vietu failā. Atrašanās vieta ir nosakāma no + * atrašanās informācijas tekstvienību objektos. + * */ Result parseQuestions(const std::vector& tokens) { auto questions = std::vector(); time_t time = 0; - auto makeResult = [&questions, &time](std::string error, Token token) -> Result { + // Palīgfunkcija - atgriež jautājumus un laiku ar norādītu tekstvienības + // kļūdas informāciju. + auto makeResult = [&questions, &time](std::string error, Token token) + -> Result { return { { questions, time }, error, @@ -120,10 +132,10 @@ Result parseQuestions(const std::vector& tokens) { }; }; + // Sākotnējā validācija. if (tokens.size() == 0) { return makeResult("", Token()); } - auto result = ValidateGrammar(tokens); if (result.error.length() > 0) { return makeResult( @@ -139,10 +151,13 @@ Result parseQuestions(const std::vector& tokens) { std::cout << "SECTION: PARSER:\n"; } + // Palīgfunkcija - pārbauda, vai tekstvienības saraksta indeksā ir + // elements, kas nav faila beigas. auto isInBounds = [tokens](size_t i) { return i < tokens.size() && tokens[i].tokenType != TokenType::EndOfFile; }; + // Sākuma datumu un laiku mēģina nolasīt, ja tāds ir norādīts. if (isInBounds(i) && tokens[i].tokenType == TokenType::TextFragment) { const std::string format = "%d.%m.%Y %H:%M"; const std::string datetime = tokens[i].content.c_str(); @@ -159,6 +174,7 @@ Result parseQuestions(const std::vector& tokens) { i++; } + // Pamata parsēšana. while (i < tokens.size()) { if (tokens[i].tokenType == TokenType::ElementDashStart) { std::string questionText; @@ -170,14 +186,18 @@ Result parseQuestions(const std::vector& tokens) { bool hasGroupEncountered = false; Token questionStartToken; - // Start element parsing & add to the offset. + // Šajā momentā ir sagaidāms jautājuma sākums - tam nevar būt secības modifikators. if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) { return makeResult( "Nevar izmantot secības modifikatoru ('^') jautājuma sākumā", tokens[i + 1]); } + // Piefiksē sākumu, lai varētu sniegt labāku kļūdas + // atrašanos vietu kļūdas gadījumā. questionStartToken = tokens[i]; + + // Apstrādā pārtraukumu, ja tāds ir. if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::CooldownStart) { try { cooldown = std::stod(tokens[i + 2].content); @@ -195,12 +215,13 @@ Result parseQuestions(const std::vector& tokens) { i += 3; } - // Parse elements of a question. + // Jautājumu elementu parsēšana. while (isInBounds(i)) { - // Check question end. + // Pārbauda, vai nav sastapts cits jautājuma sākums, un noslēdz, ja tas tā ir. if (isInBounds(i + 3) && tokens[i].tokenType == TokenType::ElementDashStart) { - // Distance to the possible question end. + + // Jautājumam var būt un var nebūt pārtraukums - nosaka vai tas būtu. size_t offset; if (tokens[i + 1].tokenType == TokenType::ElementOrderModifier) { offset = tokens[i + 2].tokenType == TokenType::CooldownStart ? 6 : 3; @@ -210,19 +231,21 @@ Result parseQuestions(const std::vector& tokens) { 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( - "Nepareiza idenfikatora izvietošana", + "Jautājuma elementam nevar būt pārtraukums", tokens[i] ); } } - // Determine element type. + // Jautājuma elementa noteikšana un ar to saistītās kļūdas. bool isDash; bool isGroup = false; bool isOrder = false; + + // Elementa sākums. if (tokens[i].tokenType == TokenType::ElementDashStart) { isDash = true; } else { @@ -241,6 +264,8 @@ Result parseQuestions(const std::vector& tokens) { ); } } + + // Elementa secības modifikators. if (isInBounds(i+1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) { isOrder = true; isOrderQuestion = true; @@ -269,6 +294,8 @@ Result parseQuestions(const std::vector& tokens) { ); } } + + // Elementa grupas modifikators. if (isInBounds(i + 2) && tokens[i + 2].tokenType == TokenType::MatchGroupEnd) { isGroup = true; isGroupQuestion = true; @@ -289,6 +316,7 @@ Result parseQuestions(const std::vector& tokens) { hasGroupEncountered = true; } + // Izveido atbilstoša veida jautājuma elementu. QuestionElement questionElement; questionElement.isDash = isDash; questionElement.isGroup = isGroup; @@ -299,23 +327,28 @@ Result parseQuestions(const std::vector& tokens) { } questionElements.push_back(questionElement); - size_t offset = 2; + // Nākamā elementa atrašanās vieta ir atkarīga no elementu + // veida, kas ir sastapts. + size_t offset = 2; if (isOrder) { offset += 1; } if (isGroup) { offset += 1; } - i += offset; } + // Izveido jautājuma objektu. + // Fix: else block - jautājums bez elementiem. if (questionElements.size() > 0) { if (isGroupQuestion) { auto *question = new GroupQuestion(); question->cooldown = cooldown; question->questionText = questionText; question->section = section; + + // Izveido grupas; i - elementu iterators; k - grupu iterators. int32_t k = -1; for (size_t i = 0; i < questionElements.size(); ++i) { auto questionElement = questionElements[i]; @@ -344,12 +377,14 @@ Result parseQuestions(const std::vector& tokens) { question->questionText = cleanContent(questionText); question->section = section; + // Izveido vairāku elementu jautājumu. auto existingElements = std::set(); for (const auto& elem : questionElements) { Choice choice; choice.answer = cleanContent(elem.content); choice.isCorrect = !elem.isDash; + // Secības elementiem nedrīkst būt vienādi elementi. if (isOrderQuestion) { if (existingElements.contains(choice.answer)) { return makeResult( @@ -366,6 +401,7 @@ Result parseQuestions(const std::vector& tokens) { } questions.push_back(question); + // Uzstāda vairāku elementu jautājuma specializēto veidu. if (isPlusQuestion) { question->type = MultiElementType::MultiChoice; } else if (isOrderQuestion) { @@ -400,6 +436,9 @@ Result parseQuestions(const std::vector& tokens) { ); } +/* + * Simbolu virkne, kas attēlo jautājumu atkļūdošanai. + */ std::string MultiElementQuestion::toString() const { std::stringstream ss; for (const auto& choice : choices) { @@ -422,6 +461,9 @@ std::string MultiElementQuestion::toString() const { ); } +/* + * Simbolu virkne, kas attēlo jautājumu atkļūdošanai. + */ std::string GroupQuestion::toString() const { std::stringstream ss; for (auto group: groups) {