Skip to content

Commit

Permalink
Fixing end of input while parsing stack not empty (#39)
Browse files Browse the repository at this point in the history
* ANYCC 29
- Fix 'dash' print.

* handle end of input while stack not empty

* ANYCC 29
- Generate First & Follow Markdown files

* ANYCC 29
- Printing Grammar

* handle end of input and adjust readme output

* ANYCC 47
- Fix prioritize direct production for each first in first set

* ANYCC 47
- Fix Predictive Table MD

* ANYCC 47
- Put project program

* ANYCC 47
- Put test program

* fix end of input or end of stack

* ANYCC 47
- Modify print

* ANYCC 47
- Add Default test

---------

Co-authored-by: bazina <youssefbazina7@gmail.com>
  • Loading branch information
Ahmedelsa3eed and Bazina authored Dec 25, 2023
1 parent 6a424aa commit 14ce0f4
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 103 deletions.
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

0 comments on commit 14ce0f4

Please sign in to comment.