In this problem, you will modify your solution to the previous problem to parse WLP4 programs, and to produce a representation of a parse tree as output.

The input no longer contains a CFG or parsing DFA, and is no longer formatted into components. Instead, the input format is simply the output format of the WLP4 scanner.

The output format of the parser is also different. You should construct a parse tree for the program, in which the value stored at each node in the tree is either the production rule used to expand the nonterminal at the node (if it is an internal node), or the token kind and lexeme (if it is a leaf node). If the parse is successful, the print the node values, one per line, using a left-to-right preorder traversal of the tree:

Print the value at the root of the tree (that is, print the production rule or the token kind and lexeme, depending on which kind of node).
Visit the children in order from left to right. For each child subtree, recursively print the values in the subtree using a left-to-right preorder traversal.
The result of this preorder traversal is a .wlp4i (WLP4 Intermediate) file.

In this problem, it is possible that the parse will be unsuccessful. This happens if there is no transition on the kind of the next token when the parsing DFA tells you to shift. If this occurs, output a single line consisting of the string ERROR at k (terminated with a line feed) to standard error, where k is one greater than the number of WLP4 tokens that were successfully read from the input prior to the error.

Note that BOF and EOF are not part of the input, so they do not contribute to the value of k in this problem. Note also that "one token" means a kind and lexeme pair; so each line of the input contains one token.

Unlike in some earlier assignments, where your error message simply had to contain "ERROR", in this problem your error message must exactly match the required message. Extraneous output (such as debugging output) on standard error will cause you to fail some Marmoset tests.

WLP4 Grammar and Parsing Data
You may find the following files useful:
wlp4data.h is a C++ header file that provides four string constants:
WLP4_CFG is a CFG component for the augmented WLP4 grammar.
WLP4_TRANSITIONS is a TRANSITIONS component for the WLP4 SLR(1) DFA.
WLP4_REDUCTIONS is a REDUCTIONS component for the WLP4 SLR(1) DFA.
WLP4_COMBINED is a single string containing the above three strings followed by a .END line.
wlp4data.rkt is a Racket module that provides four string constants:
wlp4-cfg is a CFG component for the augmented WLP4 grammar.
wlp4-transitions is a TRANSITIONS component for the WLP4 SLR(1) DFA.
wlp4-reductions is a REDUCTIONS component for the WLP4 SLR(1) DFA.
wlp4-combined is a single string containing the above three strings followed by a .END line.
Example
For the following input:

INT int
WAIN wain
LPAREN (
INT int
ID a
COMMA ,
INT int
ID b
RPAREN )
LBRACE {
RETURN return
NUM 42
SEMI ;
RBRACE }
The output should be:

start BOF procedures EOF
BOF BOF
procedures main
main INT WAIN LPAREN dcl COMMA dcl RPAREN LBRACE dcls statements RETURN expr SEMI RBRACE
INT int
WAIN wain
LPAREN (
dcl type ID
type INT
INT int
ID a
COMMA ,
dcl type ID
type INT
INT int
ID b
RPAREN )
LBRACE {
dcls .EMPTY
statements .EMPTY
RETURN return
expr term
term factor
factor NUM
NUM 42
SEMI ;
RBRACE }
EOF EOF

this code parses through the CFG and gets the shifts and reductions

int main() {
    string line;
    vector<pair<string, vector<string>>> cfg;
    deque<string> inputs;

    map<pair<int, string>, int> transitions;
    map<pair<int, string>, int> reductions;
    set<int> accept;

    int cfgIt = 0;
    string start = "";

    // Parsing CFG
    while (getline(cin, line)) {
        if (line == ".CFG") {
            continue;
        }
        if (line == ".INPUT") {
            break;
        }

        istringstream iss(line);
        string cfgStart;
        string it;

        vector<string> cfgResult;
        iss >> cfgStart;

        if (cfgIt == 0) {
            start = cfgStart;
        }

        while (iss >> it) {
            if (it == ".EMPTY") {
                cfgResult.clear();
                break;
            }
            cfgResult.push_back(it);
        }

        cfg.push_back({cfgStart, cfgResult});
        
        cfgIt++;
    }

    // Parsing input sequence
    while (getline(cin, line)) {
        if (line == ".TRANSITIONS") {
            break;
        }

        istringstream iss(line);
        string it;
        while (iss >> it) {
            inputs.push_back(it);
        }
    }

    // Parsing transitions
    while (getline(cin, line)) {
        if (line == ".REDUCTIONS") {
            break;
        }

        istringstream iss(line);
        string it;
        int state, nextState;

        iss >> state >> it >> nextState;
        transitions[{state, it}] = nextState;
    }

    // Parsing reductions
    while (getline(cin, line)) {
        if (line == ".END") {
            break;
        }

        istringstream iss(line);
        int state, target;
        string token;
        
        iss >> state >> target >> token;

        if (token == ".ACCEPT") {
            accept.insert(state);
        } else {
            reductions[{state, token}] = target;
            while (iss >> token) {
                reductions[{state, token}] = target;
            }
        }
    }

we want to manipulate the stack to contain root nodes instead of just regular items. then traverse through.

Bottom-up parsing, specifically with an SLR(1) parser, is about constructing a parse tree while using a state machine to manage shifts and reductions based on the look-ahead symbol. Instead of simply recognizing an input string, this parsing method builds a structured representation of the input, using a stack to keep partial parse trees. Each time a reduction is performed, the parser integrates previously processed symbols or trees into a new parse tree node, reflecting the structure dictated by the grammar rules.

which should give the correct output given the input. answer this carefully. print out at each stage the stack so if there is an error we know exactly why. BE SUPER CAREFUL ABOUT NO ERRORS PLEASE