From 82c40c001b3b79c409c3c11bb00a0d5e304de3a3 Mon Sep 17 00:00:00 2001 From: bazina Date: Sun, 24 Dec 2023 21:48:04 +0200 Subject: [PATCH 01/12] ANYCC 29 - Fix 'dash' print. --- src/Parser/PredictiveTopDownParser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Parser/PredictiveTopDownParser.cpp b/src/Parser/PredictiveTopDownParser.cpp index 828d2f8..e7d180f 100644 --- a/src/Parser/PredictiveTopDownParser.cpp +++ b/src/Parser/PredictiveTopDownParser.cpp @@ -106,11 +106,11 @@ void PredictiveTopDownParser::handleMissingTerminal(const StackItem &top) { void PredictiveTopDownParser::handleEmptyEntry(const StackItem &top, Token *&curr_token) { parsingFile << "Error:(illegal " << top.token << ") at line(" << curr_token->getPosition()->line_number << ") column(" - << curr_token->getPosition()->column_number << ") – discard " << curr_token << " |"; + << curr_token->getPosition()->column_number << ") - discard " << *(curr_token->getKey()) << " |"; std::cerr << "Error:(illegal " << top.token << ") at line(" << curr_token->getPosition()->line_number << ") column(" - << curr_token->getPosition()->column_number << ") – discard " << curr_token << std::endl; + << curr_token->getPosition()->column_number << ") - discard " << *(curr_token->getKey()) << std::endl; curr_token = lex.getNextToken(); } From 585229d9c3d4ca1d21555d3615775e2e7d85ab83 Mon Sep 17 00:00:00 2001 From: saeed Date: Sun, 24 Dec 2023 23:29:52 +0200 Subject: [PATCH 02/12] handle end of input while stack not empty --- include/Parser/PredictiveTopDownParser.h | 4 +-- program.txt | 42 +++++++++++++++++++----- src/Parser/PredictiveTopDownParser.cpp | 39 +++++++++++++--------- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/include/Parser/PredictiveTopDownParser.h b/include/Parser/PredictiveTopDownParser.h index 5e3d900..4cdeb53 100644 --- a/include/Parser/PredictiveTopDownParser.h +++ b/include/Parser/PredictiveTopDownParser.h @@ -53,10 +53,10 @@ class PredictiveTopDownParser { bool handleMatchOrError(const StackItem& top, Token*& curr_token); void handleMatch(const StackItem& top, Token*& curr_token); void handleNonTerminal(const StackItem& top, Token*& curr_token); - void handleMissingTerminal(const StackItem& top); + void handleMissingTerminalOrSyncEntry(const StackItem& top); void handleEmptyEntry(const StackItem& top, Token*& curr_token); - void handleSyncEntry(const StackItem& top); void handleValidProduction(const StackItem& top, const CellValue* cellValue); + void handleEndOfInput(); void pushProductionToStack(const std::vector& production); void setNextDerivation(const StackItem& top, std::vector &curr_production); }; diff --git a/program.txt b/program.txt index f5799f8..ed36490 100644 --- a/program.txt +++ b/program.txt @@ -1,10 +1,34 @@ -int x; -x = 5; -if (x > 2) -{ - x = 0; -} -else +!!!!! +@@@@@ +1.5E-6 +int sum , count , pass , mnt; whi!= +le (pass !1.5E ! +10 ) { - x = 1; -} \ No newline at end of file +pass = pass + 1; +} +boolean float int intx! +! +whi! +@int sum , count , pass , mnt; whi! 1.5E-6 +do! +1.5E-6 +@int sum , count , pass , mnt; whi! +le (pass ! ! +10 ) +} +boolean float int intx! +! +whi! + +do! +dou! +whi!le +do! +1.5E while +1.5E 123 +1.5E +1.5E@ +do! +@ +1.5E \ No newline at end of file diff --git a/src/Parser/PredictiveTopDownParser.cpp b/src/Parser/PredictiveTopDownParser.cpp index e7d180f..0d1290a 100644 --- a/src/Parser/PredictiveTopDownParser.cpp +++ b/src/Parser/PredictiveTopDownParser.cpp @@ -22,8 +22,7 @@ PredictiveTopDownParser::PredictiveTopDownParser( } } -PredictiveTopDownParser::~PredictiveTopDownParser() { -} +PredictiveTopDownParser::~PredictiveTopDownParser() {} void PredictiveTopDownParser::parseInputTokens() { std::cout << "Parsing input tokens..." << std::endl; @@ -49,8 +48,6 @@ void PredictiveTopDownParser::parseInputTokens() { handleNonTerminal(top, curr_token); parsingFile << "\n"; } - // Accept the grammar if the stack is empty - std::cout << "Accept -_-" << std::endl; parsingFile.close(); } @@ -60,10 +57,14 @@ bool PredictiveTopDownParser::handleMatchOrError(const StackItem &top, Token *&c handleMatch(top, curr_token); return true; } else { - handleMissingTerminal(top); + handleMissingTerminalOrSyncEntry(top); return true; } } + if (*(curr_token->getKey()) == "$") { + handleEndOfInput(); + return true; + } return false; } @@ -72,9 +73,19 @@ void PredictiveTopDownParser::handleMatch(const StackItem &top, Token *&curr_tok std::cout << "Match " << *(curr_token->getKey()) << std::endl; stk.pop(); + if (*(curr_token->getKey()) == "$") { + handleEndOfInput(); + return; + } curr_token = lex.getNextToken(); // Advance to the next token } +void PredictiveTopDownParser::handleEndOfInput() { + while (!stk.empty()) { + handleMissingTerminalOrSyncEntry(stk.top()); + stk.pop(); + } +} void PredictiveTopDownParser::handleNonTerminal(const StackItem &top, Token *&curr_token) { const CellValue *cellValue = predictive_table.lookUp(top.token, *(curr_token->getKey())); @@ -85,7 +96,7 @@ void PredictiveTopDownParser::handleNonTerminal(const StackItem &top, Token *&cu handleEmptyEntry(top, curr_token); break; case ParsingTableEntryType::SYNC: - handleSyncEntry(top); + handleMissingTerminalOrSyncEntry(top); break; case ParsingTableEntryType::VALID_PRODUCTION: handleValidProduction(top, cellValue); @@ -96,13 +107,16 @@ void PredictiveTopDownParser::handleNonTerminal(const StackItem &top, Token *&cu } // Helper functions for error handling and stack operations -void PredictiveTopDownParser::handleMissingTerminal(const StackItem &top) { - parsingFile << "Error: missing " << top.token << ", discarded" << " |"; +void PredictiveTopDownParser::handleMissingTerminalOrSyncEntry(const StackItem &top) { + parsingFile << "Error: missing " << top.token << " discarded" << " |"; - std::cerr << "Error: missing " << top.token << ", discarded" << std::endl; + std::cerr << "Error: missing " << top.token << " discarded" << std::endl; stk.pop(); } +/** + * @brief discard the current token (input symbol) and advance to the next token + * */ void PredictiveTopDownParser::handleEmptyEntry(const StackItem &top, Token *&curr_token) { parsingFile << "Error:(illegal " << top.token << ") at line(" << curr_token->getPosition()->line_number << ") column(" @@ -114,13 +128,6 @@ void PredictiveTopDownParser::handleEmptyEntry(const StackItem &top, Token *&cur curr_token = lex.getNextToken(); } -void PredictiveTopDownParser::handleSyncEntry(const StackItem &top) { - parsingFile << "Error: missing " << top.token << ", discarded" << " |"; - - std::cerr << "Error: missing " << top.token << ", discarded" << std::endl; - stk.pop(); -} - void PredictiveTopDownParser::handleValidProduction(const StackItem &top, const CellValue *cellValue) { stk.pop(); auto production = cellValue->getProduction().productions[0]; From d6b3bcd7f528ec598a8c763538eb323ba6030bd1 Mon Sep 17 00:00:00 2001 From: bazina Date: Mon, 25 Dec 2023 08:54:06 +0200 Subject: [PATCH 03/12] ANYCC 29 - Generate First & Follow Markdown files --- include/Parser/FirstAndFollowGenerator.h | 4 +- src/Parser/FirstAndFollowGenerator.cpp | 28 +++--- src/Parser/FirstAndFollowGeneratorUtility.cpp | 98 ++++++++++--------- 3 files changed, 67 insertions(+), 63 deletions(-) diff --git a/include/Parser/FirstAndFollowGenerator.h b/include/Parser/FirstAndFollowGenerator.h index 9113229..eb45dd1 100644 --- a/include/Parser/FirstAndFollowGenerator.h +++ b/include/Parser/FirstAndFollowGenerator.h @@ -36,9 +36,7 @@ class FirstAndFollowGenerator { void compute(); - void printFirstSets(); - - void printFollowSets(); + void generateMarkdownFirstAndFollowSets(const std::string &filename); private: std::vector productionVector; diff --git a/src/Parser/FirstAndFollowGenerator.cpp b/src/Parser/FirstAndFollowGenerator.cpp index bf8e9ce..7ca4eed 100644 --- a/src/Parser/FirstAndFollowGenerator.cpp +++ b/src/Parser/FirstAndFollowGenerator.cpp @@ -252,30 +252,34 @@ void FirstAndFollowGenerator::compute() { computeFollowSets(computedFollowSets); } -void FirstAndFollowGenerator::printFirstSets() { - std::cout << "First Sets:\n"; +void FirstAndFollowGenerator::generateMarkdownFirstAndFollowSets(const std::string &filename) { + std::ofstream out(filename); + out << "# First and Follow Sets\n\n"; + out << "## First Sets\n\n"; + out << "| Non-Terminal | First Set |\n"; + out << "| ------------ | --------- |\n"; for (const auto &entry: computedFirstSets) { const std::string &non_terminal = entry.first; const std::set, CompareFirst> &first_set = entry.second; - std::cout << non_terminal << ": { "; + out << "| " << non_terminal << " | "; for (const std::pair &symbol: first_set) { - std::cout << symbol.first << ' '; + out << '`' << symbol.first << "` "; } - std::cout << "}\n"; + out << " |\n"; } -} - -void FirstAndFollowGenerator::printFollowSets() { - std::cout << "\nFollow Sets:\n"; + out << "\n## Follow Sets\n\n"; + out << "| Non-Terminal | Follow Set |\n"; + out << "| ------------ | ---------- |\n"; for (const auto &entry: computedFollowSets) { const std::string &non_terminal = entry.first; const std::set &follow_set = entry.second; - std::cout << non_terminal << ": { "; + out << "| " << non_terminal << " | "; for (const std::string &symbol: follow_set) { - std::cout << symbol << ' '; + out << '`' << symbol << "` "; } - std::cout << "}\n"; + out << " |\n"; } + out.close(); } diff --git a/src/Parser/FirstAndFollowGeneratorUtility.cpp b/src/Parser/FirstAndFollowGeneratorUtility.cpp index d9492fb..873e023 100644 --- a/src/Parser/FirstAndFollowGeneratorUtility.cpp +++ b/src/Parser/FirstAndFollowGeneratorUtility.cpp @@ -1,69 +1,71 @@ #include "Parser/FirstAndFollowGeneratorUtility.h" #include +#include -std::vector findAllLongestSubstringIndices(const std::string& input, const std::set& substrings) { - std::vector substringInfoVec; +std::vector +findAllLongestSubstringIndices(const std::string &input, const std::set &substrings) { + std::vector substringInfoVec; - for (const std::string& substring : substrings) { - size_t pos = input.find(substring); - while (pos != std::string::npos) { - int endIndex = static_cast(pos + substring.length()); - bool found = false; + for (const std::string &substring: substrings) { + size_t pos = input.find(substring); + while (pos != std::string::npos) { + int endIndex = static_cast(pos + substring.length()); + bool found = false; - for (auto& info : substringInfoVec) { - if (info.start == static_cast(pos) && endIndex > info.end) { - info.end = endIndex; - found = true; - break; - } - } + for (auto &info: substringInfoVec) { + if (info.start == static_cast(pos) && endIndex > info.end) { + info.end = endIndex; + found = true; + break; + } + } - if (!found) { - substringInfoVec.push_back({static_cast(pos), endIndex}); - } + if (!found) { + substringInfoVec.push_back({static_cast(pos), endIndex}); + } - pos = input.find(substring, pos + 1); // Move to the next occurrence + pos = input.find(substring, pos + 1); // Move to the next occurrence + } } - } - std::sort(substringInfoVec.begin(), substringInfoVec.end(), compareSubstringInfo); + std::sort(substringInfoVec.begin(), substringInfoVec.end(), compareSubstringInfo); - return substringInfoVec; + return substringInfoVec; } -bool isNT(const std::string& s, std::set& nonTerminals) { - return nonTerminals.find(s) != nonTerminals.end(); +bool isNT(const std::string &s, std::set &nonTerminals) { + return nonTerminals.find(s) != nonTerminals.end(); } -std::set collectNonTerminals(const std::vector& grammar) { - std::set nonTerminals; - for (const Production& rule : grammar) { - nonTerminals.insert(rule.nonTerminal); - } - return nonTerminals; +std::set collectNonTerminals(const std::vector &grammar) { + std::set nonTerminals; + for (const Production &rule: grammar) { + nonTerminals.insert(rule.nonTerminal); + } + return nonTerminals; } -std::string getLongestUpperCaseSequence(const std::string& str) { - std::string currentSequence; - std::string longestSequence; +std::string getLongestUpperCaseSequence(const std::string &str) { + std::string currentSequence; + std::string longestSequence; - for (char ch : str) { - if (isupper(ch)) { - currentSequence += ch; - } else { - // Check if the current sequence is longer than the longest - if (currentSequence.length() > longestSequence.length()) { - longestSequence = currentSequence; - } - // Reset the current sequence - currentSequence.clear(); + for (char ch: str) { + if (isupper(ch)) { + currentSequence += ch; + } else { + // Check if the current sequence is longer than the longest + if (currentSequence.length() > longestSequence.length()) { + longestSequence = currentSequence; + } + // Reset the current sequence + currentSequence.clear(); + } } - } - // Check if the last sequence is longer than the longest - if (currentSequence.length() > longestSequence.length()) { - longestSequence = currentSequence; - } + // Check if the last sequence is longer than the longest + if (currentSequence.length() > longestSequence.length()) { + longestSequence = currentSequence; + } - return longestSequence; + return longestSequence; } From 93a47f9c3822732e8cb9f3b67581b28ef1188dec Mon Sep 17 00:00:00 2001 From: bazina Date: Mon, 25 Dec 2023 08:54:22 +0200 Subject: [PATCH 04/12] ANYCC 29 - Printing Grammar --- include/Parser/Parser.h | 2 ++ src/Parser/Parser.cpp | 24 +++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/Parser/Parser.h b/include/Parser/Parser.h index 728d9d7..4ee7ae6 100644 --- a/include/Parser/Parser.h +++ b/include/Parser/Parser.h @@ -51,6 +51,8 @@ class Parser { * @brief Build the predictive top down parser */ void buildPredictiveTopDownParser(); + + static void printGrammar(std::unordered_map>> &grammar); }; diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 91944a1..07c8395 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -1,5 +1,4 @@ #include "Parser/Parser.h" -#include "Utilities.h" #include "Parser/CFGReader.h" #include "LeftRecursionRemover.h" #include "LeftFactorer.h" @@ -31,14 +30,14 @@ std::unordered_map>> Parser::b auto grammar = CFGReader::parseCFGInput("../CFG.txt"); auto lr_free_grammar = LeftRecursionRemover::removeLR(grammar); auto left_factored_grammar = LeftFactorer::leftFactor(lr_free_grammar); + printGrammar(left_factored_grammar); return left_factored_grammar; } void Parser::buildFirstAndFollowSets(std::unordered_map>> &grammar) { firstAndFollowGenerator = new FirstAndFollowGenerator(grammar); firstAndFollowGenerator->compute(); - firstAndFollowGenerator->printFirstSets(); - firstAndFollowGenerator->printFollowSets(); + firstAndFollowGenerator->generateMarkdownFirstAndFollowSets("../FirstAndFollowSets.md"); } void Parser::buildPredictiveTable() { @@ -46,8 +45,6 @@ void Parser::buildPredictiveTable() { firstAndFollowGenerator->getFollowSets(), firstAndFollowGenerator->getNonTerminals()); predictiveTable->buildPredictiveTable(); - std::cout << "\nPredictive Table:\n"; - predictiveTable->printPredictiveTable(); predictiveTable->generateMarkdownTable("../PredictiveTable.md"); } @@ -57,3 +54,20 @@ void Parser::buildPredictiveTopDownParser() { firstAndFollowGenerator->getNonTerminals(), "../LL1ParsingOutput.md"); } + +void Parser::printGrammar(std::unordered_map>> &grammar) { + std::cout << "Grammar:\n"; + for (auto &non_terminal: grammar) { + std::cout << non_terminal.first << " --> "; + int i = 0; + for (auto &production: non_terminal.second) { + i++; + for (auto &symbol: production) { + std::cout << symbol << " "; + } + if (i < non_terminal.second.size()) + std::cout << "| "; + } + std::cout << "\n"; + } +} From c49cc7c6cf64286afc2c72ab1081d4b085e5cb4c Mon Sep 17 00:00:00 2001 From: saeed Date: Mon, 25 Dec 2023 14:26:10 +0200 Subject: [PATCH 05/12] handle end of input and adjust readme output --- include/Parser/PredictiveTopDownParser.h | 3 +- src/Parser/PredictiveTopDownParser.cpp | 50 ++++++++++++++---------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/include/Parser/PredictiveTopDownParser.h b/include/Parser/PredictiveTopDownParser.h index 4cdeb53..ba1683d 100644 --- a/include/Parser/PredictiveTopDownParser.h +++ b/include/Parser/PredictiveTopDownParser.h @@ -53,7 +53,8 @@ class PredictiveTopDownParser { bool handleMatchOrError(const StackItem& top, Token*& curr_token); void handleMatch(const StackItem& top, Token*& curr_token); void handleNonTerminal(const StackItem& top, Token*& curr_token); - void handleMissingTerminalOrSyncEntry(const StackItem& top); + void handleMissingTerminal(const StackItem& top); + void handleSyncEntry(const StackItem &top); void handleEmptyEntry(const StackItem& top, Token*& curr_token); void handleValidProduction(const StackItem& top, const CellValue* cellValue); void handleEndOfInput(); diff --git a/src/Parser/PredictiveTopDownParser.cpp b/src/Parser/PredictiveTopDownParser.cpp index 0d1290a..6a7508c 100644 --- a/src/Parser/PredictiveTopDownParser.cpp +++ b/src/Parser/PredictiveTopDownParser.cpp @@ -16,9 +16,8 @@ PredictiveTopDownParser::PredictiveTopDownParser( left_most_derivation.push_back({CFGReader::start_symbol}); parsingFile.open(filename); - if (!parsingFile.is_open()) { - std::cerr << "Error opening file: output.md" << std::endl; + std::cerr << "Error opening file: LL1ParsingOutput.md" << std::endl; } } @@ -27,7 +26,7 @@ PredictiveTopDownParser::~PredictiveTopDownParser() {} void PredictiveTopDownParser::parseInputTokens() { std::cout << "Parsing input tokens..." << std::endl; - parsingFile << "Parsing input tokens...\n\n"; + parsingFile << "*Parsing input tokens...*\n\n"; parsingFile << "| Stack | Current Token | Output |\n"; parsingFile << "|--------|---------------|------------------------|\n"; @@ -57,32 +56,24 @@ bool PredictiveTopDownParser::handleMatchOrError(const StackItem &top, Token *&c handleMatch(top, curr_token); return true; } else { - handleMissingTerminalOrSyncEntry(top); + handleMissingTerminal(top); return true; } } - if (*(curr_token->getKey()) == "$") { - handleEndOfInput(); - return true; - } return false; } void PredictiveTopDownParser::handleMatch(const StackItem &top, Token *&curr_token) { - parsingFile << "match " << *(curr_token->getKey()) << " |"; + parsingFile << "match ``" << *(curr_token->getKey()) << "`` |"; std::cout << "Match " << *(curr_token->getKey()) << std::endl; stk.pop(); - if (*(curr_token->getKey()) == "$") { - handleEndOfInput(); - return; - } curr_token = lex.getNextToken(); // Advance to the next token } void PredictiveTopDownParser::handleEndOfInput() { while (!stk.empty()) { - handleMissingTerminalOrSyncEntry(stk.top()); + handleMissingTerminal(stk.top()); stk.pop(); } } @@ -96,7 +87,7 @@ void PredictiveTopDownParser::handleNonTerminal(const StackItem &top, Token *&cu handleEmptyEntry(top, curr_token); break; case ParsingTableEntryType::SYNC: - handleMissingTerminalOrSyncEntry(top); + handleSyncEntry(top); break; case ParsingTableEntryType::VALID_PRODUCTION: handleValidProduction(top, cellValue); @@ -107,10 +98,10 @@ void PredictiveTopDownParser::handleNonTerminal(const StackItem &top, Token *&cu } // Helper functions for error handling and stack operations -void PredictiveTopDownParser::handleMissingTerminalOrSyncEntry(const StackItem &top) { - parsingFile << "Error: missing " << top.token << " discarded" << " |"; +void PredictiveTopDownParser::handleMissingTerminal(const StackItem &top) { + parsingFile << "Error: missing ``" << top.token << "`` inserted" << " |"; - std::cerr << "Error: missing " << top.token << " discarded" << std::endl; + std::cerr << "Error: missing '" << top.token << "' inserted" << std::endl; stk.pop(); } @@ -118,19 +109,36 @@ void PredictiveTopDownParser::handleMissingTerminalOrSyncEntry(const StackItem & * @brief discard the current token (input symbol) and advance to the next token * */ void PredictiveTopDownParser::handleEmptyEntry(const StackItem &top, Token *&curr_token) { - parsingFile << "Error:(illegal " << top.token << ") at line(" + parsingFile << "Error:(illegal ``" << top.token << "``) at line(" << curr_token->getPosition()->line_number << ") column(" - << curr_token->getPosition()->column_number << ") - discard " << *(curr_token->getKey()) << " |"; + << curr_token->getPosition()->column_number << ") - discard ``" << *(curr_token->getKey()) << "`` |"; std::cerr << "Error:(illegal " << top.token << ") at line(" << curr_token->getPosition()->line_number << ") column(" << curr_token->getPosition()->column_number << ") - discard " << *(curr_token->getKey()) << std::endl; - curr_token = lex.getNextToken(); + if (*(curr_token->getKey()) != "$") { + curr_token = lex.getNextToken(); + } + else { + // report error and pop stack + stk.pop(); + } +} + +void PredictiveTopDownParser::handleSyncEntry(const StackItem &top) { + parsingFile << "Error: ``Sync`` " << ",discard " << top.token << "|"; + + std::cerr << "Error: Sync " << "discard " << top.token << std::endl; + stk.pop(); } void PredictiveTopDownParser::handleValidProduction(const StackItem &top, const CellValue *cellValue) { + parsingFile << top.token << " → "; stk.pop(); auto production = cellValue->getProduction().productions[0]; + for (auto &symbol: production) { + parsingFile << symbol << " "; + } setNextDerivation(top, production); pushProductionToStack(production); } From 336e06c3041bcf0082ae57f029a375d4ca1d3c38 Mon Sep 17 00:00:00 2001 From: bazina Date: Mon, 25 Dec 2023 15:54:21 +0200 Subject: [PATCH 06/12] ANYCC 47 - Fix prioritize direct production for each first in first set --- src/Parser/FirstAndFollowGenerator.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Parser/FirstAndFollowGenerator.cpp b/src/Parser/FirstAndFollowGenerator.cpp index 7ca4eed..bc890a3 100644 --- a/src/Parser/FirstAndFollowGenerator.cpp +++ b/src/Parser/FirstAndFollowGenerator.cpp @@ -31,7 +31,16 @@ FirstAndFollowGenerator::computeFirst(const std::string &nonTerminal) { symbolStr); // insert all the first from nonTerminalFirstSet but with the production in the for loop not the one coming with the variable for (const auto &pair: nonTerminalFirstSet) { - firstSet.insert({pair.first, {nonTerminal, {production}}}); + bool foundBefore = false; + for (const auto &it: firstSet) { + if (it.first == pair.first) { + foundBefore = true; + break; + } + } + if (!foundBefore) { + firstSet.insert({pair.first, {nonTerminal, {production}}}); + } } // Check if the non-terminal has an epsilon production @@ -41,8 +50,13 @@ FirstAndFollowGenerator::computeFirst(const std::string &nonTerminal) { } } else { // Handle terminal symbols + for (auto it = firstSet.begin(); it != firstSet.end(); ++it) { + if (it->first == symbol) { + firstSet.erase(it); + break; + } + } firstSet.insert({symbol, {nonTerminal, {production}}}); - //firstSet.insert(symbol); // Break the loop for terminal symbols break; } From e5dc10a28ac0c8c55d44ac0285947ed67ede926d Mon Sep 17 00:00:00 2001 From: bazina Date: Mon, 25 Dec 2023 15:54:35 +0200 Subject: [PATCH 07/12] ANYCC 47 - Fix Predictive Table MD --- src/Parser/PredictiveTable.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Parser/PredictiveTable.cpp b/src/Parser/PredictiveTable.cpp index 3def57b..ce203eb 100644 --- a/src/Parser/PredictiveTable.cpp +++ b/src/Parser/PredictiveTable.cpp @@ -172,25 +172,39 @@ void PredictiveTable::generateMarkdownTable(const std::string &outputFilePath) { } outputFile << "\n"; - // Iterate through non-terminals and terminals to fill in the table + // create table with empty cells then replace them with the correct values like replace strings + std::vector> table; for (const auto &non_terminal: non_terminals) { - outputFile << "| **" << non_terminal << "** |"; + std::vector row; for (const auto &terminal: terminals) { const CellValue *cellValue = lookUp(non_terminal, terminal); if (hasProduction(non_terminal, terminal)) { const auto &production = cellValue->getProduction(); std::string productionStr; if (!production.productions.empty()) { + productionStr.push_back('`'); for (const auto &symbol: production.productions[0]) { productionStr += symbol + " "; } productionStr.pop_back(); // Remove the extra space + productionStr.push_back('`'); } - outputFile << " `" << productionStr << "` |"; + row.push_back(productionStr); } else if (isSynchronizing(non_terminal, terminal)) { - outputFile << " `Synch` |"; + row.push_back("`Synch`"); + } else { + row.push_back(""); } } + table.push_back(row); + } + + // Write table rows + for (int i = 0; i < non_terminals.size(); ++i) { + outputFile << "| **" << *std::next(non_terminals.begin(), i) << "** |"; + for (int j = 0; j < terminals.size(); ++j) { + outputFile << " " << table[i][j] << " |"; + } outputFile << "\n"; } From 425e1f57e21fa1bca9f7a31b853b1a7026277ffa Mon Sep 17 00:00:00 2001 From: bazina Date: Mon, 25 Dec 2023 15:55:09 +0200 Subject: [PATCH 08/12] ANYCC 47 - Put project program --- program.txt | 42 +++++++++--------------------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/program.txt b/program.txt index ed36490..f5799f8 100644 --- a/program.txt +++ b/program.txt @@ -1,34 +1,10 @@ -!!!!! -@@@@@ -1.5E-6 -int sum , count , pass , mnt; whi!= -le (pass !1.5E ! -10 ) -{ -pass = pass + 1; -} -boolean float int intx! -! -whi! -@int sum , count , pass , mnt; whi! 1.5E-6 -do! -1.5E-6 -@int sum , count , pass , mnt; whi! -le (pass ! ! -10 ) +int x; +x = 5; +if (x > 2) +{ + x = 0; } -boolean float int intx! -! -whi! - -do! -dou! -whi!le -do! -1.5E while -1.5E 123 -1.5E -1.5E@ -do! -@ -1.5E \ No newline at end of file +else +{ + x = 1; +} \ No newline at end of file From fb1d6bf750b2d61aa890e2c7f061fe708bdefdd6 Mon Sep 17 00:00:00 2001 From: bazina Date: Mon, 25 Dec 2023 16:11:18 +0200 Subject: [PATCH 09/12] ANYCC 47 - Put test program --- CFG.txt | 22 +++++----------------- program.txt | 11 +---------- rules.txt | 16 ++++------------ 3 files changed, 10 insertions(+), 39 deletions(-) diff --git a/CFG.txt b/CFG.txt index 0062517..3fa75f3 100644 --- a/CFG.txt +++ b/CFG.txt @@ -1,17 +1,5 @@ -# METHOD_BODY = STATEMENT_LIST -# STATEMENT_LIST = STATEMENT | STATEMENT_LIST STATEMENT -# STATEMENT = DECLARATION -| IF -| WHILE -| ASSIGNMENT -# DECLARATION = PRIMITIVE_TYPE 'id' ';' -# PRIMITIVE_TYPE = 'int' | 'float' -# IF = 'if' '(' EXPRESSION ')' '{' STATEMENT '}' 'else' '{' STATEMENT '}' -# WHILE = 'while' '(' EXPRESSION ')' '{' STATEMENT '}' -# ASSIGNMENT = 'id' 'assign' EXPRESSION ';' -# EXPRESSION = SIMPLE_EXPRESSION -| SIMPLE_EXPRESSION 'relop' SIMPLE_EXPRESSION -# SIMPLE_EXPRESSION = TERM | SIGN TERM | SIMPLE_EXPRESSION 'addop' TERM -# TERM = FACTOR | TERM 'mulop' FACTOR -# FACTOR = 'id' | 'num' | '(' EXPRESSION ')' -# SIGN = '+' | '-' \ No newline at end of file +# E = T E1 +# E1 = 'add' T E1 | Epsilon +# T = F T1 +# T1 = 'mul' F T1 | Epsilon +# F = '(' E ')' | id \ No newline at end of file diff --git a/program.txt b/program.txt index f5799f8..b310541 100644 --- a/program.txt +++ b/program.txt @@ -1,10 +1 @@ -int x; -x = 5; -if (x > 2) -{ - x = 0; -} -else -{ - x = 1; -} \ No newline at end of file +* + id ) + ( id * \ No newline at end of file diff --git a/rules.txt b/rules.txt index 0e0310b..da43f0d 100644 --- a/rules.txt +++ b/rules.txt @@ -1,12 +1,4 @@ -letter = a- z | A-Z -digit = 0 - 9 -id: letter (letter | digit)* -digits = digit+ -{boolean int float} -num: digit+ | digit+ . digits (\L | E digits) -relop: \=\= | !\= | > | >\= | < | <\= -assign: \= -{while if else} -[; , \( \) { }] -addop: \+ | \- -mulop: \* | / \ No newline at end of file +id: id +mul: \* +add: \+ +[\( \)] \ No newline at end of file From 3b88930df6e3498a47e30573f92f5680c9d48d24 Mon Sep 17 00:00:00 2001 From: saeed Date: Mon, 25 Dec 2023 16:45:05 +0200 Subject: [PATCH 10/12] fix end of input or end of stack --- include/Parser/PredictiveTopDownParser.h | 5 ++- program.txt | 42 ++++++++++++++---- src/Parser/PredictiveTopDownParser.cpp | 54 +++++++++++++++--------- 3 files changed, 70 insertions(+), 31 deletions(-) diff --git a/include/Parser/PredictiveTopDownParser.h b/include/Parser/PredictiveTopDownParser.h index ba1683d..9e0e899 100644 --- a/include/Parser/PredictiveTopDownParser.h +++ b/include/Parser/PredictiveTopDownParser.h @@ -53,11 +53,12 @@ class PredictiveTopDownParser { bool handleMatchOrError(const StackItem& top, Token*& curr_token); void handleMatch(const StackItem& top, Token*& curr_token); void handleNonTerminal(const StackItem& top, Token*& curr_token); - void handleMissingTerminal(const StackItem& top); + void handleMissingTerminal(const StackItem& top, Token *&curr_token); void handleSyncEntry(const StackItem &top); void handleEmptyEntry(const StackItem& top, Token*& curr_token); void handleValidProduction(const StackItem& top, const CellValue* cellValue); - void handleEndOfInput(); + void handleEndOfInput(const StackItem &top); + void handleEndOfStack(Token *&curr_token); void pushProductionToStack(const std::vector& production); void setNextDerivation(const StackItem& top, std::vector &curr_production); }; diff --git a/program.txt b/program.txt index f5799f8..ed36490 100644 --- a/program.txt +++ b/program.txt @@ -1,10 +1,34 @@ -int x; -x = 5; -if (x > 2) -{ - x = 0; -} -else +!!!!! +@@@@@ +1.5E-6 +int sum , count , pass , mnt; whi!= +le (pass !1.5E ! +10 ) { - x = 1; -} \ No newline at end of file +pass = pass + 1; +} +boolean float int intx! +! +whi! +@int sum , count , pass , mnt; whi! 1.5E-6 +do! +1.5E-6 +@int sum , count , pass , mnt; whi! +le (pass ! ! +10 ) +} +boolean float int intx! +! +whi! + +do! +dou! +whi!le +do! +1.5E while +1.5E 123 +1.5E +1.5E@ +do! +@ +1.5E \ No newline at end of file diff --git a/src/Parser/PredictiveTopDownParser.cpp b/src/Parser/PredictiveTopDownParser.cpp index 6a7508c..eaf6633 100644 --- a/src/Parser/PredictiveTopDownParser.cpp +++ b/src/Parser/PredictiveTopDownParser.cpp @@ -27,8 +27,8 @@ void PredictiveTopDownParser::parseInputTokens() { std::cout << "Parsing input tokens..." << std::endl; parsingFile << "*Parsing input tokens...*\n\n"; - parsingFile << "| Stack | Current Token | Output |\n"; - parsingFile << "|--------|---------------|------------------------|\n"; + parsingFile << "| Stack Top | Current Token | Output |\n"; + parsingFile << "|-----------|---------------|------------------------|\n"; Token *curr_token = lex.getNextToken(); @@ -54,11 +54,14 @@ bool PredictiveTopDownParser::handleMatchOrError(const StackItem &top, Token *&c if (top.isTerminal) { if (top.token == *(curr_token->getKey())) { handleMatch(top, curr_token); - return true; - } else { - handleMissingTerminal(top); - return true; } + else if (top.token == EPSILON) { + handleEndOfStack(curr_token); + } + else { + handleMissingTerminal(top, curr_token); + } + return true; } return false; } @@ -71,10 +74,12 @@ void PredictiveTopDownParser::handleMatch(const StackItem &top, Token *&curr_tok curr_token = lex.getNextToken(); // Advance to the next token } -void PredictiveTopDownParser::handleEndOfInput() { - while (!stk.empty()) { - handleMissingTerminal(stk.top()); - stk.pop(); +void PredictiveTopDownParser::handleEndOfStack(Token *&curr_token) { + while (*(curr_token->getKey()) != "$") { + parsingFile << "Error: ``" << *(curr_token->getKey()) << "`` discarded |"; + + std::cout << "Error: " << *(curr_token->getKey()) << " discarded" << std::endl; + curr_token = lex.getNextToken(); } } @@ -98,7 +103,11 @@ void PredictiveTopDownParser::handleNonTerminal(const StackItem &top, Token *&cu } // Helper functions for error handling and stack operations -void PredictiveTopDownParser::handleMissingTerminal(const StackItem &top) { +void PredictiveTopDownParser::handleMissingTerminal(const StackItem &top, Token *&curr_token) { + if (*(curr_token->getKey()) == "$") { + handleEndOfInput(top); // report error and pop stack + return; + } parsingFile << "Error: missing ``" << top.token << "`` inserted" << " |"; std::cerr << "Error: missing '" << top.token << "' inserted" << std::endl; @@ -109,20 +118,25 @@ void PredictiveTopDownParser::handleMissingTerminal(const StackItem &top) { * @brief discard the current token (input symbol) and advance to the next token * */ void PredictiveTopDownParser::handleEmptyEntry(const StackItem &top, Token *&curr_token) { - parsingFile << "Error:(illegal ``" << top.token << "``) at line(" + if (*(curr_token->getKey()) == "$") { + handleEndOfInput(top); // report error and pop stack + return; + } + parsingFile << "Error: (illegal ``" << top.token << "``) at line(" << curr_token->getPosition()->line_number << ") column(" << curr_token->getPosition()->column_number << ") - discard ``" << *(curr_token->getKey()) << "`` |"; - std::cerr << "Error:(illegal " << top.token << ") at line(" + std::cerr << "Error: (illegal " << top.token << ") at line(" << curr_token->getPosition()->line_number << ") column(" << curr_token->getPosition()->column_number << ") - discard " << *(curr_token->getKey()) << std::endl; - if (*(curr_token->getKey()) != "$") { - curr_token = lex.getNextToken(); - } - else { - // report error and pop stack - stk.pop(); - } + curr_token = lex.getNextToken(); +} + +void PredictiveTopDownParser::handleEndOfInput(const StackItem &top) { + parsingFile << "Error: ``No more input`` " << ", discard " << top.token << "|"; + + std::cerr << "Error: No more input " << "discard " << top.token << std::endl; + stk.pop(); } void PredictiveTopDownParser::handleSyncEntry(const StackItem &top) { From 1f60051d86cf88688afd891c470cc252dea3b51d Mon Sep 17 00:00:00 2001 From: bazina Date: Mon, 25 Dec 2023 18:25:23 +0200 Subject: [PATCH 11/12] ANYCC 47 - Modify print --- src/Parser/PredictiveTopDownParser.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Parser/PredictiveTopDownParser.cpp b/src/Parser/PredictiveTopDownParser.cpp index affb271..0289d1e 100644 --- a/src/Parser/PredictiveTopDownParser.cpp +++ b/src/Parser/PredictiveTopDownParser.cpp @@ -54,11 +54,9 @@ bool PredictiveTopDownParser::handleMatchOrError(const StackItem &top, Token *&c if (top.isTerminal) { if (top.token == *(curr_token->getKey())) { handleMatch(top, curr_token); - } - else if (top.token == "$") { + } else if (top.token == "$") { handleEndOfStack(curr_token); - } - else { + } else { handleMissingTerminal(top, curr_token); } return true; @@ -79,7 +77,7 @@ void PredictiveTopDownParser::handleEndOfStack(Token *&curr_token) { curr_token = lex.getNextToken(); while (*(curr_token->getKey()) != "$") { parsingFile << "| $ | " << *(curr_token->getKey()) - << " | Error: ``" << *(curr_token->getKey()) << "`` discarded |"; + << " | Error: ``" << *(curr_token->getKey()) << "`` discarded |"; std::cerr << "Error: " << *(curr_token->getKey()) << " discarded" << std::endl; curr_token = lex.getNextToken(); @@ -110,10 +108,6 @@ void PredictiveTopDownParser::handleNonTerminal(const StackItem &top, Token *&cu // Helper functions for error handling and stack operations void PredictiveTopDownParser::handleMissingTerminal(const StackItem &top, Token *&curr_token) { - if (*(curr_token->getKey()) == "$") { - handleEndOfInput(top); // report error and pop stack - return; - } parsingFile << "Error: missing ``" << top.token << "`` inserted" << " |"; std::cerr << "Error: missing '" << top.token << "' inserted" << std::endl; From 3e0a694782c61bcb2a16a588ad2c14328d580c0d Mon Sep 17 00:00:00 2001 From: bazina Date: Mon, 25 Dec 2023 18:25:37 +0200 Subject: [PATCH 12/12] ANYCC 47 - Add Default test --- CFG.txt | 22 +++++++++++++++++----- program.txt | 11 ++++++++++- rules.txt | 16 ++++++++++++---- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/CFG.txt b/CFG.txt index 3fa75f3..0062517 100644 --- a/CFG.txt +++ b/CFG.txt @@ -1,5 +1,17 @@ -# E = T E1 -# E1 = 'add' T E1 | Epsilon -# T = F T1 -# T1 = 'mul' F T1 | Epsilon -# F = '(' E ')' | id \ No newline at end of file +# METHOD_BODY = STATEMENT_LIST +# STATEMENT_LIST = STATEMENT | STATEMENT_LIST STATEMENT +# STATEMENT = DECLARATION +| IF +| WHILE +| ASSIGNMENT +# DECLARATION = PRIMITIVE_TYPE 'id' ';' +# PRIMITIVE_TYPE = 'int' | 'float' +# IF = 'if' '(' EXPRESSION ')' '{' STATEMENT '}' 'else' '{' STATEMENT '}' +# WHILE = 'while' '(' EXPRESSION ')' '{' STATEMENT '}' +# ASSIGNMENT = 'id' 'assign' EXPRESSION ';' +# EXPRESSION = SIMPLE_EXPRESSION +| SIMPLE_EXPRESSION 'relop' SIMPLE_EXPRESSION +# SIMPLE_EXPRESSION = TERM | SIGN TERM | SIMPLE_EXPRESSION 'addop' TERM +# TERM = FACTOR | TERM 'mulop' FACTOR +# FACTOR = 'id' | 'num' | '(' EXPRESSION ')' +# SIGN = '+' | '-' \ No newline at end of file diff --git a/program.txt b/program.txt index b310541..d54f9b0 100644 --- a/program.txt +++ b/program.txt @@ -1 +1,10 @@ -* + id ) + ( id * \ No newline at end of file +int x; +x = 5; +if (x > 2) +{ + x = 0; +} +else +{ + x = 1; +} \ No newline at end of file diff --git a/rules.txt b/rules.txt index da43f0d..0e0310b 100644 --- a/rules.txt +++ b/rules.txt @@ -1,4 +1,12 @@ -id: id -mul: \* -add: \+ -[\( \)] \ No newline at end of file +letter = a- z | A-Z +digit = 0 - 9 +id: letter (letter | digit)* +digits = digit+ +{boolean int float} +num: digit+ | digit+ . digits (\L | E digits) +relop: \=\= | !\= | > | >\= | < | <\= +assign: \= +{while if else} +[; , \( \) { }] +addop: \+ | \- +mulop: \* | / \ No newline at end of file