Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing end of input while parsing stack not empty #39

Merged
merged 13 commits into from
Dec 25, 2023
4 changes: 1 addition & 3 deletions include/Parser/FirstAndFollowGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ class FirstAndFollowGenerator {

void compute();

void printFirstSets();

void printFollowSets();
void generateMarkdownFirstAndFollowSets(const std::string &filename);

private:
std::vector<Production> productionVector;
Expand Down
2 changes: 2 additions & 0 deletions include/Parser/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class Parser {
* @brief Build the predictive top down parser
*/
void buildPredictiveTopDownParser();

static void printGrammar(std::unordered_map<std::string, std::vector<std::vector<std::string>>> &grammar);
};


Expand Down
6 changes: 4 additions & 2 deletions include/Parser/PredictiveTopDownParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +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 handleSyncEntry(const StackItem& top);
void handleValidProduction(const StackItem& top, const CellValue* cellValue);
void handleEndOfInput(const StackItem &top);
void handleEndOfStack(Token *&curr_token);
void pushProductionToStack(const std::vector<std::string>& production);
void setNextDerivation(const StackItem& top, std::vector<std::string> &curr_production);
};
Expand Down
10 changes: 5 additions & 5 deletions program.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
int x;
x = 5;
if (x > 2)
{
x = 0;
int x;
x = 5;
if (x > 2)
{
x = 0;
}
else
{
Expand Down
46 changes: 32 additions & 14 deletions src/Parser/FirstAndFollowGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
Expand Down Expand Up @@ -252,30 +266,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<std::pair<std::string, Production>, CompareFirst> &first_set = entry.second;

std::cout << non_terminal << ": { ";
out << "| " << non_terminal << " | ";
for (const std::pair<std::string, Production> &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<std::string> &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();
}
98 changes: 50 additions & 48 deletions src/Parser/FirstAndFollowGeneratorUtility.cpp
Original file line number Diff line number Diff line change
@@ -1,69 +1,71 @@

#include "Parser/FirstAndFollowGeneratorUtility.h"
#include <algorithm>
#include <fstream>

std::vector<SubstringInfo> findAllLongestSubstringIndices(const std::string& input, const std::set<std::string>& substrings) {
std::vector<SubstringInfo> substringInfoVec;
std::vector<SubstringInfo>
findAllLongestSubstringIndices(const std::string &input, const std::set<std::string> &substrings) {
std::vector<SubstringInfo> substringInfoVec;

for (const std::string& substring : substrings) {
size_t pos = input.find(substring);
while (pos != std::string::npos) {
int endIndex = static_cast<int>(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<int>(pos + substring.length());
bool found = false;

for (auto& info : substringInfoVec) {
if (info.start == static_cast<int>(pos) && endIndex > info.end) {
info.end = endIndex;
found = true;
break;
}
}
for (auto &info: substringInfoVec) {
if (info.start == static_cast<int>(pos) && endIndex > info.end) {
info.end = endIndex;
found = true;
break;
}
}

if (!found) {
substringInfoVec.push_back({static_cast<int>(pos), endIndex});
}
if (!found) {
substringInfoVec.push_back({static_cast<int>(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<std::string>& nonTerminals) {
return nonTerminals.find(s) != nonTerminals.end();
bool isNT(const std::string &s, std::set<std::string> &nonTerminals) {
return nonTerminals.find(s) != nonTerminals.end();
}

std::set<std::string> collectNonTerminals(const std::vector<Production>& grammar) {
std::set<std::string> nonTerminals;
for (const Production& rule : grammar) {
nonTerminals.insert(rule.nonTerminal);
}
return nonTerminals;
std::set<std::string> collectNonTerminals(const std::vector<Production> &grammar) {
std::set<std::string> 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;
}
24 changes: 19 additions & 5 deletions src/Parser/Parser.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "Parser/Parser.h"
#include "Utilities.h"
#include "Parser/CFGReader.h"
#include "LeftRecursionRemover.h"
#include "LeftFactorer.h"
Expand Down Expand Up @@ -31,23 +30,21 @@ std::unordered_map<std::string, std::vector<std::vector<std::string>>> 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<std::string, std::vector<std::vector<std::string>>> &grammar) {
firstAndFollowGenerator = new FirstAndFollowGenerator(grammar);
firstAndFollowGenerator->compute();
firstAndFollowGenerator->printFirstSets();
firstAndFollowGenerator->printFollowSets();
firstAndFollowGenerator->generateMarkdownFirstAndFollowSets("../FirstAndFollowSets.md");
}

void Parser::buildPredictiveTable() {
predictiveTable = new PredictiveTable(firstAndFollowGenerator->getFirstSets(),
firstAndFollowGenerator->getFollowSets(),
firstAndFollowGenerator->getNonTerminals());
predictiveTable->buildPredictiveTable();
std::cout << "\nPredictive Table:\n";
predictiveTable->printPredictiveTable();
predictiveTable->generateMarkdownTable("../PredictiveTable.md");
}

Expand All @@ -57,3 +54,20 @@ void Parser::buildPredictiveTopDownParser() {
firstAndFollowGenerator->getNonTerminals(),
"../LL1ParsingOutput.md");
}

void Parser::printGrammar(std::unordered_map<std::string, std::vector<std::vector<std::string>>> &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";
}
}
22 changes: 18 additions & 4 deletions src/Parser/PredictiveTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::vector<std::string>> table;
for (const auto &non_terminal: non_terminals) {
outputFile << "| **" << non_terminal << "** |";
std::vector<std::string> 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";
}

Expand Down
Loading