Advertisement
fooker

lab 5

Feb 18th, 2025
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.97 KB | None | 0 0
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. int main() {
  5.     ifstream file("text.txt");
  6.     if (!file) {
  7.         cout << "Input file not found!\n";
  8.         exit(1);  // Return error code 1
  9.     }
  10.  
  11.     int number = 0, index = 1;
  12.  
  13.     map<char, int> mp;
  14.     map<int, char> reverse_mp;
  15.     map<int, vector<vector<char>>> production_list;
  16.  
  17.     string line;
  18.     while (getline(file, line)) {
  19.         number++;
  20.  
  21.         bool start = false;
  22.         char nonTerminal = ' ';
  23.  
  24.         vector<char> production_;
  25.  
  26.         for (char inputchar : line) {
  27.             if (!start) {
  28.                 nonTerminal = inputchar;
  29.                 start = true;
  30.  
  31.                 if (mp[nonTerminal] == 0) {
  32.                     mp[nonTerminal] = index++;
  33.                     reverse_mp[mp[nonTerminal]] = nonTerminal;
  34.                 }
  35.             } else {
  36.                 if (inputchar == '-' || inputchar == '>' || inputchar == ' ' || inputchar == '\n') {
  37.                     // Ignore these characters
  38.                 } else if (inputchar == '|') {
  39.                     production_list[mp[nonTerminal]].push_back(production_);
  40.                     production_.clear();
  41.                 } else {
  42.                     production_.push_back(inputchar);
  43.                 }
  44.             }
  45.         }
  46.  
  47.         // Add last production for the current non-terminal
  48.         if (!production_.empty()) {
  49.             production_list[mp[nonTerminal]].push_back(production_);
  50.         }
  51.     }
  52.  
  53.     // Compute the FIRST sets
  54.     map<char, set<char>> first;
  55.  
  56.     // Function to calculate FIRST set for a given non-terminal
  57.     function<void(char)> computeFirst = [&](char nonTerminal) {
  58.         if (first.count(nonTerminal)) return;  // Already computed
  59.  
  60.         for (const auto& production : production_list[mp[nonTerminal]]) {
  61.             for (char symbol : production) {
  62.                 if (mp[symbol] == 0) {  // Terminal
  63.                     first[nonTerminal].insert(symbol);
  64.                     break;
  65.                 } else {  // Non-terminal
  66.                     computeFirst(symbol);
  67.                     first[nonTerminal].insert(first[symbol].begin(), first[symbol].end());
  68.                     if (first[symbol].count('^') == 0) break;  // Stop if no epsilon
  69.                 }
  70.             }
  71.         }
  72.     };
  73.  
  74.     for (int i = 1; i < index; i++) {
  75.         char nonTerminal = reverse_mp[i];
  76.         computeFirst(nonTerminal);
  77.     }
  78.  
  79.     // Print the FIRST sets (optional for debugging)
  80.     // for (auto [u, v] : first) {
  81.     //     cout << "FIRST(" << u << ") = { ";
  82.     //     for (auto w : v) {
  83.     //         cout << w << ", ";
  84.     //     }
  85.     //     cout << "}\n";
  86.     // }
  87.  
  88.     // Compute the FOLLOW sets
  89.     map<char, set<char>> follow;
  90.  
  91.     // Function to calculate FOLLOW set for a given non-terminal
  92.     function<void(char)> computeFollow = [&](char nonTerminal) {
  93.         if (follow.count(nonTerminal)) return;  // Already computed
  94.  
  95.         if (nonTerminal == reverse_mp[1]) {  // Start symbol
  96.             follow[nonTerminal].insert('$');
  97.         }
  98.  
  99.         for (int i = 1; i < index; i++) {
  100.             for (const auto& production : production_list[i]) {
  101.                 for (int j = 0; j < production.size(); j++) {
  102.                     if (production[j] == nonTerminal) {
  103.                         if (j + 1 < production.size()) {
  104.                             char nextSymbol = production[j + 1];
  105.                             if (mp[nextSymbol] == 0) {
  106.                                 follow[nonTerminal].insert(nextSymbol);  // Terminal
  107.                             } else {
  108.                                 follow[nonTerminal].insert(first[nextSymbol].begin(), first[nextSymbol].end());
  109.                                 if (first[nextSymbol].count('^')) {
  110.                                     follow[nonTerminal].insert(follow[reverse_mp[i]].begin(), follow[reverse_mp[i]].end());
  111.                                 }
  112.                             }
  113.                         } else {
  114.                             follow[nonTerminal].insert(follow[reverse_mp[i]].begin(), follow[reverse_mp[i]].end());
  115.                         }
  116.                     }
  117.                 }
  118.             }
  119.         }
  120.     };
  121.  
  122.     // Compute FOLLOW sets for all non-terminals
  123.     for (int i = 1; i < index; i++) {
  124.         computeFollow(reverse_mp[i]);
  125.     }
  126.  
  127.     // Print the FOLLOW sets (optional for debugging)
  128.     // for (auto [u, v] : follow) {
  129.     //     cout << "FOLLOW(" << u << ") = { ";
  130.     //     for (auto w : v) {
  131.     //         cout << w << ", ";
  132.     //     }
  133.     //     cout << "}\n";
  134.     // }
  135.  
  136.     // Construct the LL(1) parse table
  137.     map<pair<char, char>, vector<char>> parse_table;
  138.     bool cannot = false;
  139.  
  140.     for (auto [u, v] : production_list) {
  141.         for (const auto& production : v) {
  142.             char alpha = production[0];
  143.             char A = reverse_mp[u];
  144.  
  145.             if (mp[alpha] == 0) {  // Terminal
  146.                 if (alpha == '^') {  // Epsilon
  147.                     for (auto t : follow[A]) {
  148.                         if (parse_table[{A, t}].empty()) {
  149.                             parse_table[{A, t}] = production;
  150.                         } else {
  151.                             cannot = true;
  152.                         }
  153.                     }
  154.                 } else {  // Non-epsilon terminal
  155.                     if (parse_table[{A, alpha}].empty()) {
  156.                         parse_table[{A, alpha}] = production;
  157.                     } else {
  158.                         cannot = true;
  159.                     }
  160.                 }
  161.             } else {  // Non-terminal
  162.                 for (auto w : first[alpha]) {
  163.                     if (w == '^') {
  164.                         for (auto t : follow[A]) {
  165.                             if (parse_table[{A, t}].empty()) {
  166.                                 parse_table[{A, t}] = production;
  167.                             } else {
  168.                                 cannot = true;
  169.                             }
  170.                         }
  171.                     } else {
  172.                         if (parse_table[{A, w}].empty()) {
  173.                             parse_table[{A, w}] = production;
  174.                         } else {
  175.                             cannot = true;
  176.                         }
  177.                     }
  178.                 }
  179.             }
  180.         }
  181.     }
  182.  
  183.     // Output a message if a conflict occurs in the parse table
  184.     if (cannot) {
  185.         cout << "Error: The grammar is not LL(1).\n";
  186.     } else {
  187.         cout << "The grammar is LL(1) and the parse table is constructed.\n";
  188.     }
  189.  
  190.     // Optionally, print the parse table for debugging
  191.     // for (auto [key, value] : parse_table) {
  192.     //     cout << "Parse Table[" << key.first << ", " << key.second << "] = ";
  193.     //     for (auto ch : value) {
  194.     //         cout << ch << " ";
  195.     //     }
  196.     //     cout << endl;
  197.     // }
  198.  
  199.     string input;
  200.     cout << "Enter the input string: ";
  201.     cin >> input;
  202.     input += '$';  // Add end-of-input marker
  203.  
  204.     stack<char> parse_stack;
  205.     parse_stack.push('$');
  206.     parse_stack.push(reverse_mp[1]);  // Push the start symbol onto the stack
  207.  
  208.     cout << "Start Parsing:\n";
  209.     while (!parse_stack.empty()) {
  210.         char top = parse_stack.top();
  211.         char current_input = input[0];
  212.  
  213.         if (top == current_input) {
  214.             // If top of the stack matches the current input symbol, pop it and move input forward
  215.            
  216.             cout << top << " matches " << current_input << endl;
  217.             parse_stack.pop();
  218.             input = input.substr(1);  // Move the input pointer forward
  219.         } else if (mp[top] > 0) {
  220.             // If top is a non-terminal, use the parse table to expand it
  221.             auto it = parse_table.find({top, current_input});
  222.             if (it != parse_table.end()) {
  223.                 cout << top << " expands to ";
  224.                 const vector<char>& production = it->second;
  225.  
  226.                 // Push the right-hand side of the production onto the stack in reverse order
  227.                 parse_stack.pop();  // Pop the non-terminal
  228.                 for (auto rit = production.rbegin(); rit != production.rend(); ++rit) {
  229.                     if (*rit != '^') {  // Skip epsilon productions
  230.                         parse_stack.push(*rit);
  231.                     }
  232.                 }
  233.  
  234.                 for (auto sym : production) {
  235.                     cout << sym << " ";
  236.                 }
  237.                 cout << endl;
  238.             } else {
  239.                 cout << "Parse error: No rule for " << top << " with input " << current_input << endl;
  240.                 return 0;
  241.             }
  242.         } else {
  243.             // If top is not a terminal and no production is found, it's a parsing error
  244.             cout << "Parse error: " << top << " doesn't match " << current_input << endl;
  245.             return 0;
  246.         }
  247.     }
  248.  
  249.     if (input.empty()) {
  250.         cout << "String matches the grammar!\n";
  251.     } else {
  252.         cout << "Input string could not be completely parsed.\n";
  253.     }
  254.  
  255.     return 0;
  256. }
  257.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement