Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Soreland, a software company, is planning on releasing its first C++ compiler wi

ID: 3732627 • Letter: S

Question

Soreland, a software company, is planning on releasing its first C++ compiler with the hopes of putting MiniSoft's Visual C++ out of business (that reminds me of another story). Consequently, Soreland has contracted with the Fruugle Corporation to design and build part of their compiler. Of course, since Fruugle gets all of its labor by exploiting El Camino undergraduate students, you'll be doing all of the programming.

For Fruugle, you will write a C++ program to test the "balance" of certain features of C++ programs. This is a task that is done by C++ compilers. The technique you will use is similar to the technique used by a typical C++ compiler.

Requirements

There are many features in C++ programs that must be ``balanced'' to be syntactically correct. For example, every ( must be balanced by a corresponding ). Similarly for {} and []. There are other (somewhat more complex) situations.

Block comments must be balanced. Each /* must be balanced by a */ The complication here is that the tokens being balanced are not composed of single characters. Moreover, the ``closing comment'' */ starts with a character that is used in other ways (pointers, multiplication). Quotes must be balanced. This applies to single quotes and double quotes. The complication here is that all the material between the matching quotes can contain any characters. The characters between the quotes do not require balancing. For example, the string "This is a /* ' * quote" is legal, and the comment and single-quote need not be balanced. Inline comments are not balanced. Anything that comes after a comment is ignored until you get to the end of the line that's read in.

There are some balanced C++ programs you need not test. For example, some balanced C++ programs contain character constants such as ''' or '"'. These are inherently unbalanced and would require a bit more work to catch. You need not worry about such problems for the compiler (unless you like the modest challenge).

The Basic Algorithm

Please think and know there are different ways to do this, think of structure. But note that simply counting the number of characters will not work. For example, the expression }abc{ has the correct number of balancing braces (one opening brace and one closing brace), but it is not valid C++ code. A stack provides the mechanism needed for the algorithm. Basically, whenever a closing symbol (such as }) is seen, it must match the nearest opening symbol of the same type (such as {). One important point: do not write a large main file. Your main file should simply get a file name, call a function to print the file with line numbers, and then call a balance-checking function.

Explanation / Answer

PROGRAM:

main.cpp

#include <iostream>

#include <string>

#include <fstream>

#include <iomanip>

#include "Balancer.h"

using namespace std;

void main() {

    string fileName;

    cout << "Please enter filename for C++ code: ";

    cin >> fileName;

    ifstream printFile(fileName);

    string buffer;

    int line = 1;

    while (getline(printFile, buffer))

    {

        cout << setw(3) << setiosflags(ios::right) << line << " " << buffer << endl;

        line++;

    }

    ifstream infile(fileName);

    if (!infile)

    {

        cerr << "file not found" << endl;

        return;

    }

    Balancer* check = new Balancer();

    bool isBalanced = check->balance(&infile);

    if (isBalanced)

    {

        cout << "Balance is ok" << endl;

    }

    delete check;

    check = nullptr;

}

Balancer.cpp

#include <iostream>

#include <fstream>

#include <sstream>

#include <string>

#include <stack>

#include "Balancer.h"

#include "globals.h"

using namespace std;

Balancer::Balancer()

{

    m_prevChar = NULL;

    m_waitChar = NULL;

    m_lineNum = 1;

}

Balancer::~Balancer()

{

}

const bool Balancer::balance(ifstream* file)

{

    while (getline(*file, m_line))           // Get one line

    {

        stringstream line2word(m_line);

        while (line2word >> m_word)               // Get word token

        {

            int lineCode = wordCheck(&m_word);

            if (lineCode == 2)                   // Check word token

                break;                           

            if (lineCode == 0)

            {

                cerr << "word ERR ";

                return 0;                       // Error out

            }

        }

        if (m_waitChar != NULL && m_waitChar != '*')

        {

            cerr << "unbalanced quote " << m_waitChar << " at line " << m_lineNum << endl;

            return 0; // Error because end of line and the quote hasnt been balanced

        }

        m_lineNum++;

    }

    if (!m_stack.empty())

    {

        cerr << "Unbalanced " << m_stack.top() << " at line " << m_stackLine.top() << endl;

        return 0;

    }

    Else

        return 1;

}

const int Balancer::wordCheck(string* line)

{

   stringstream word2char(*line);

    while (word2char.get(m_char))       // Get character

    {

        int wordCode = charCheck(&m_char);

        if (wordCode == 2)           // Check character

            return 2;

        if (wordCode == 0)           // Error out

            return 0;

        m_prevChar = m_char;

    }

    return 1;                       // No Errors

}

const int Balancer::charCheck(char* letter)

{

    for (int i = 0; i < OPENCHECKSIZE; i++) // Check for open characters

    {

        if (*letter == OPENCHECK[i] && m_waitChar == NULL)

        {

            m_stack.push(OPENCHECK[i]);

            m_stackLine.push(m_lineNum);

            return 1;

        }

    }

    for (int i = 0; i < CLOSECHECKSIZE; i++) // Check for close characters

    {

        if (*letter == CLOSECHECK[i] && m_waitChar == NULL)

        {

            if (m_stack.empty()) // Error if the stack is empty

            {

                cerr << "[ERR] charCheck: Stack is empty!" << endl;

                return 0;

            }

            if (m_stack.top() == OPENCHECK[i])

            {

                m_stack.pop();

                m_stackLine.pop();

                cout << "pair matching " << OPENCHECK[i] << " and " << CLOSECHECK[i] << endl;

                return 1;

            }

            else

            {

                cerr << "Balance Error at line " << m_lineNum << ". " << m_stack.top() << " is not balanced" << endl;

                return 0;

            }

        }

    }

    for (int i = 0; i < UNICHECKSIZE; i++)             // Check for universal characters

    {

        if (*letter == UNICHECK[i])

        {

            if (m_waitChar != NULL || UNICHECK[i] == ''' || UNICHECK[i] == '"')       // Check for quotations            {

                if (UNICHECK[i] != ''' && UNICHECK[i] != '"' && UNICHECK[i] != '/')

                {

                    return 1; // Ignore whatever is between the quotes

                }

                //filtered it's either null or not with either " or '

                if (m_waitChar == NULL)

                {

                    m_stack.push(UNICHECK[i]);

                    m_stackLine.push(m_lineNum);

                    m_waitChar = UNICHECK[i];

                    return 1;

                }

                if (m_waitChar != NULL)

                {

                    if (UNICHECK[i] == '/' && m_prevChar == '*' && m_waitChar == '*')

                    {

                        m_stack.pop();

                        m_stackLine.pop();

                        m_stack.pop();

                        m_stackLine.pop();

                        m_waitChar = NULL;

                        cout << "pair matching / and /" << endl;

                        return 1;

                    }

                    if (UNICHECK[i] != m_stack.top())

                    {

                        return 1;

                    }

                    if (UNICHECK[i] == m_stack.top())

                    {

                        m_stack.pop();

                        m_stackLine.pop();

                        m_waitChar = NULL;

                        cout << "pair matching " << UNICHECK[i] << " and " << UNICHECK[i] << endl;

                        return 1;

                    }

                    cerr << "[ERR] UNICHECK: something went wrong in the quotation check!" << endl;

                    return 0; // ERROR

                }

            }

            if (UNICHECK[i] == '/' && m_waitChar == NULL) {   // Check for // comments

                if (!m_stack.empty())

                {

                    if (m_prevChar == '/')                       // Check if there was one behind it.

                    {

                        return 2;                               // ignore the rest of the line

                    }

                    else

                    {

                        return 1;                               // Skip

                    }

                }

                m_stack.push(*letter);

                m_stackLine.push(m_lineNum);

                return 1;

            }

            if (UNICHECK[i] == '*')

            {

                if (!m_stack.empty())

                {

                    if (m_stack.top() == '/')

                    {

                        m_stack.push(*letter);

                        m_stackLine.push(m_lineNum);

                        m_waitChar = UNICHECK[i];

                    }

                    else

                    {

                        return 1;

                    }

                }

            }

            return 1;

        }

    }

}

Balancer.h

#ifndef BALANCE_H

#define BALANCE_H

#include <string>

#include <stack>

using namespace std;

class Balancer

{

public:

    Balancer();

    ~Balancer();

    const bool balance(ifstream* file);

private:

    const int wordCheck(string* line);

    const int charCheck(char* letter);

    string m_line;

    string m_word;

    char m_char;

    int m_lineNum;

    char m_prevChar;

    char m_waitChar;

    stack <char> m_stack;

    stack <int> m_stackLine;

};

#endif

globals.h

#ifndef GLOBALS_H

#define GLOBALS_H

int OPENCHECKSIZE = 3;

int CLOSECHECKSIZE = 3;

int UNICHECKSIZE = 4;

const char OPENCHECK[3] = { '{', '[', '(' };

const char CLOSECHECK[3] = { '}', ']', ')' };

const char UNICHECK[4] = { ''', '"', '*', '/' };

#endif

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote