Link to home
Start Free TrialLog in
Avatar of jandhb
jandhb

asked on

parse an input file

Can someone tell me where I can find a tutorial or code to help me along with...

Writing a program to parse an input file and verify that all opening brackets have a matching closing bracket. This applies to ( [ and { also.

I just need help with how to do...

1. The function to parse the file and
2. how to display the result of the parsing.
Avatar of brettmjohnson
brettmjohnson
Flag of United States of America image

What you are looking for is a data structure called a "stack",
a "Last In, First Out" linear storage mechanism:
http://webster.cs.uga.edu/~boanerg/csci6900/hci/partc/stack.htm

As you scan the input stream, when you encounter the opening element of
balanced pair "({[", push it on the stack.  If you encounter the closing element
of a balanced pair "]})", compare it against the item at the top of the stack.
If they match, () [] or {}, then you have a balanced pair, you can pop the
match off of the top of the stack and continue scanning input.  If the closing
element does not match the opening element on the top of stack, you have
an unbalance and should generate an error.   If you encounter a closing
element and the stack is empty, you have an imbalance (too many closing
elements) and should generate an error.  If you encounter end-of-file and
the stack is not empty, you have an imbalance (too few closing elements),
and should generate an error.

Avatar of jandhb
jandhb

ASKER

That is exactly what I want to do. I'm new to this. Could you supply some code to get me started or something like that?
Here's a quick'n'dirty:

--------8<--------
#include <iostream>
#include <iterator>

int count[256];

int main()
{
        typedef std::istreambuf_iterator<char> Citr;
        Citr end;
        for (Citr itr(std::cin);itr != end;++itr)
                count[*itr]++;
        if (int unmatches = count['{']-count['}'])
                std::cout << unmatches << " unmatched braces\n";
}
--------8<--------

Usage:

./a.out < yourfile
Avatar of jandhb

ASKER

This is probably an obvious question, but I'll ask anyway...

How would I use a file to parse. In other words, I want to check for matching ( ] }, but I want to check a simple .cpp file. You know what I mean. I think I would need to open this file and go through it, but I'm not sure how. Does that make sense?
You can use standard input like I did, or open the file in your program using an ifstream. If you use standard input, you need to use your program from the command line and redirect the source code file into your parser.
Avatar of jandhb

ASKER

I want to prompt the user for the name of the file to be parsed, open that file, and then basically parse the file for those characters by using the stack as explained above. Can you show me how this would be done. Sorry, real new to this. I thank you. I'm not clear on what your doing here ./a.out < yourfile.
Avatar of jandhb

ASKER

I tried doing this to prompt the user for the file to be opened, but its not working. Why?

#include <iostream>
#include <fstream>

int main()
{
      //declare file stream object
      ifstream input;
      char fileName;

      cout << "File to be opened:  " << endl;
      cin >> filename;
      input.open(filename, ios::in);
      cout << filename << "was opened." << endl;

      return 0;
}
Avatar of jandhb

ASKER

I dont understand why it says, ifstream undeclared identifier. I'm using VSStudio.net 2002 version 7.0. Does that matter? I tried #include <fstream.h> but it gave a warning and said it was deprecated.
Avatar of jandhb

ASKER

I had to put in using namespace std:

ok. Now unto parsing the file...
Avatar of jandhb

ASKER

I'm using this so far in main()

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
      //declare file stream object
      ifstream input;
      char fileName[50];

      cout << "File to be opened:  " << endl;
      cin.getline(fileName, 50);
      input.open(fileName, ios::in);
      cout << fileName << "was opened." << endl;

      return 0;
}

When I ask the user to open the file does the file have to be in the same directory as the other .cpp and .h files? Does it search the entire hard drive to find the file to open??
Avatar of jandhb

ASKER

I have opened the file with this code.

      ifstream input;
      char fileName[50];
      char characters [50];

      cout << "File to be opened:  " << endl;
      cin.getline(fileName, 50);
      input.open(fileName, ios::in);
      cout << fileName << " was opened." << endl;

How now do I begin to read this file and parse it and check the values that I need to check for?
Avatar of jandhb

ASKER

The file I want to read looks like this...

float f1 (int a[], int b)
{
      float sum = 0;
            for(int i=0; i<b; i++)
            {
                  sum += a[i];
            }
            return sum/b;
}

When I do this in main()

      while (!input.eof())
      {
            cout << input;
      }

I get a bunch of 0's scrolling down the screen?

Have you finished helping me here??
jandhb, I've been away from my computer for most of today and have returned to see a trail of questions and solutions which have been immediate concerns, most of which you have figured out yourself.

When you next post, let us know what you have been unable to figure out and we can help.
Avatar of jandhb

ASKER

I need help with a couple of things.

1. How do I pass the file to my parseFile() and have that function go through and find (  [ } it needs to push them unto the stack and look for a matching ) ] }. If it finds a match it needs to pop it off the stach. I need help with this.

2. After that I just need to display the results.
(1) You can use one of the following approaches:
 (a) Use standard input to read the contents of the file
 (b) Open the file within your program for reading
   Adopt one of the following approaches:
    (i) Hard code the file name and always use a file with that name
    (ii) Use a command line argument to specify the filename and run the program with a different command line for different filenames
    (iii) Prompt the user for the filename

Having done that you are still left with the problem of implementing the parseFile function. I have shown you a quick'n'dirty method of doing this and brettmjohnson has proposed an approach which could allow you to communicate much more information.

(2) Decide what the format of the results are that you want to display and then you can write a program accordingly. My quick'n'dity fulfills a very basic promise and the push/pop design can fulfill much more sophisticated promises. What promises do your program need to fulfill? Do you need line numbers and column numbers to indicate the whereabouts of unmatched braces...?

I am happy to help you with this project, but I'm not willing to do it for you. Assuming the project is educational, I would be doing you a disservice.
Avatar of jandhb

ASKER

I already have accomplished part 1.

Here is what I have so far, but I need help with the display, push and parseInput functions. To answer your question about the display...I just have to somehow display the results of what it found, no special formatting or anyting. For example, "All ( ) were found" "All { } were found". Something like that.

--------------------------------------------------------------------------------
Parse.h

#ifndef PARSE_H
#define PARSE_H
#include <fstream>

using namespace std;

typedef char T;
class Parse
{
public:
      //constructor
      Parse(T size);
      //destructor
      ~Parse();
      //function to parse input file
      void parseInput(istream&);
      //display results of parse
      void display() const;
      //push
      void push(T);
      //pop
      void pop();
      //empty
      bool empty() const;
      //full
      bool full()const;

private:
      //list is an array of values
      T *list;
      //current number of elements in stack
      T stackTop;
      T maxSize;
};
#endif
--------------------------------------------------------------------

Parse.cpp

#include "Parse.h"
#include <iostream>


//constructor
Parse::Parse(T size) : maxSize(size), stackTop(0)
{
      //dynamically allocate array to list size
      list = new T[size];
}

//destructor
Parse::~Parse()
{
      delete [] list;
}

//parseInput
void Parse::parseInput(istream& input)
{
      char characterLine[800];

      while (!input.eof())
      {
            input.getline(characterLine,800,' ');

            for (int i = 0; i > sizeof(characterLine); i++)
            {
                  switch(characterLine[i])
                  {
                  case '(':
                        {
                              //push unto stack
                              push(characterLine(i);
                        } break;
                  case ')':
                        {
                              //check to see if top element is matching closing ')'
                              if (list->top == '(' && characterLine(i) == ')')
                              {
                                    //we have a match, pop element from stack
                                    pop();
                              }
                        } break;
                  case '[':
                        {
                              //push unto stack
                              push(characterLine(i);
                        }break;
                  case ']':
                        {
                              //check to see if top element is matching closing ']'
                              if (list->top == '[' && characterLine(i) == ']')
                              {
                                    //we have a match, pop element from stack
                                    pop();
                              }
                        }break;
                  case '{':
                        {
                              //push unto stack
                              push(characterLine(i);
                        }break;
                  case '}':
                        {
                              //check to see if top element is matching closing '}'
                              if (list->top == '{' && characterLine(i) == '}')
                              {
                                    //we have a match, pop element from stack
                                    pop();
                              }
                        }break;
                  default: break;
                  }
            }
      }
}

//display
void Parse::display() const
{


}

//push
void Parse::push(T)
{
      if (!full())
      {
            list[stackTop] = item;
            //increment stack by one
            ++stackTop;
      }
}

//pop
void Parse::pop()
{
      if(!empty())
      {
            --stackTop;
      }
}

//empty
bool Parse::empty() const
{
      return (stackTop == 0);
}

//full
bool Parse::full() const
{
      return (stackTop == maxSize);
}
-------------------------------------------------------------------------
Driver.cpp


#include "Parse.h"
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
      //declare object of class Parse
      Parse pobject;

      //declare file stream object
      ifstream input;
      char fileName[50];

      cout << "File to be opened:  " << endl;
      cin.getline(fileName, 50);
      input.open(fileName, ios::in);
      //verify file was opened
      cout << fileName << " was opened." << endl;
      
      //call parseInput, pass it the file to be parsed
      pobject.parseInput(input);

      return 0;
}

When you get more comfortable with the standard library, you'll find that there is an adaptor for a container called a stack, which gives you push/pop/top. I've illustrated how to handle the output below, using it instead of your home-grown class. If your lecturer hasn't covered standard library containers, you'd do better to stick with your own implementation.

It looks like your utility would do best to display the first error and then quit, because a mismatched brace is a hard act to follow. For that reason, it is probably best to display errors as you come to them.

Missing from this handling is recognition of quotes and recognition of comments. If you parse the source code below with its own executable, you'll find that it misdiagnoses an unmatched brace because of the quoted characters in the match function. Unrealistic problem perhaps for most source code, but it is realistic to have something like...

    //if (blah) {  // Oops didn't mean to do this
    if (blahdiblah) { // That's better
    }

...and the parser isn't comment-savvy.

--------8<--------
#include <iostream>
#include <fstream>
#include <iterator>
#include <stack>
#include <string>

char match(char brace)
{
      switch (brace) {
      case '{': return '}';
      case '[': return ']';
      case '(': return ')';
      case '}': return '{';
      case ']': return '[';
      case ')': return '(';
      }
      return 0;
}

int main()
{
      typedef std::pair<int,int> LineColumn;
      typedef std::pair<char,LineColumn> Brace;
      typedef std::stack<Brace> BraceStack;
      typedef std::istreambuf_iterator<char> Citr;

      std::cout << "Enter your filename: ";
      std::string filename;
      std::cin >> filename;
      std::ifstream fin(filename.c_str());
      if (!fin) {
            std::cout << "Error: Unable to open " << filename << '\n';
            return 1;
      }

      BraceStack braceStack;
      Citr end;
      int line = 1,column = 1;
      for (Citr itr(fin);itr != end;++itr) {
            switch (*itr) {

            // Pushes
            case '{':
            case '[':
            case '(':
                  braceStack.push(Brace(*itr,LineColumn(line,column)));
                  break;

            // Pops
            case '}':
            case ']':
            case ')':
                  if (braceStack.empty()) {
                        std::cout
                              << "Error: " << filename << " line " << line << " column " << column
                              << ": Unmatched closing brace '" << *itr << "'\n";
                        return 1;
                  }
                  else if (braceStack.top().first != match(*itr)) {
                        const LineColumn& lineColumn = braceStack.top().second;
                        std::cout
                              << "Error: " << filename << " line " << lineColumn.first << " column " << lineColumn.second
                              << ": Unmatched opening brace '" << braceStack.top().first
                              << "' found closing brace '" << *itr
                              << "' at line " << line << " column " << column
                              << "\n";
                        return 1;
                  }
                  braceStack.pop();
                  break;

            // EOL
            case '\n':
                  column = 0;
                  line++;
            }
            column++;
      }
      if (!braceStack.empty()) {
            const LineColumn& lineColumn = braceStack.top().second;
            std::cout
                  << "Error: " << filename << " line " << lineColumn.first << " column " << lineColumn.second
                  << ": Unmatched opening brace '" << braceStack.top().first
                  << "'\n";
            return 1;
      }
      return 0;
}
--------8<--------
Avatar of jandhb

ASKER

Ok. Much of what you did here is new to me, so would you mind answering a few questions....

1. Are you saying that I should get rid of the class that I had? If yes, what portion of the code you did replaces that, if any? What portion should I keep? I'm just trying to understand what is happening.
2. Is the char match(char brace) function to go in a different file or just above the main function?
3. It's ok that I use the standard library containers I just need to understand what is happening.
Avatar of jandhb

ASKER

Maybe I'm doing this wrong, but I am trying to understand what you did.

1. I put a file (file.cpp) in the same directory as the other project files. I was going to use this file as the one to parse. Well, it asks me for the filename and I type it in and it says, unable to open. What am I doing wrong? What is filename.c_str() saying?
Avatar of jandhb

ASKER

Ok. I just read that c_str() converts a string object into a character array.

My question is then why does the file not open? Do I have to have it in another directory or something?
Is there a way to clean up main() a little bit and just call the functions that are being used, maybe have them in another file?? If yes, how would this be implemented?
Avatar of jandhb

ASKER

I'm probably missing something so simple, but I can't figure out why no file I type in will open.

I'm simply typing in the the file that I want to parse?? This file is in the same folder as all the other files for the project.

In your code does it cout << for ] } and ) or just "brace". In other words, when it, for example, finds say a matching ) for the ( will it output matching paranthesis found? You know what I mean?
Since you say that it is OK to use standard library containers, you really ought to replace the stack functionality in your Parse class with a standard library stack.

If you want to wrap a class around the stack that's fine. I've been pushing/popping a standard library pair where part of the pair is a pair itself. That's a bit ugly, but it shortens the illustration. It would be more legible to have a user-defined class to contain the brace character, line and column (assuming you do indeed want to display line and column). This is your utility. The best design is the one you feel most comfortable with.

> 2. Is the char match(char brace) function to go in a different file or just above the main function?

It is too small to bother putting in a separate module. I'd leave it above main, but if you prefer to put it into a separate module, you'll need a header file with the function prototype. If you wrap the parsing code into a class (as before), you could make the match function a static class function.

> 1. I put a file (file.cpp) in the same directory as the other project files. I was going to use this file as the one to parse. Well, it asks me for the filename and I type it in and it says, unable to open. What am I doing wrong?

Are you using a GUI to develop your application (e.g. Visual Studio). If so, I expect that your working directory is not where your source files are. Try using a fully qualified path - e.g. c:\file.cpp - but beware that your code does not handle filenames/paths with spaces.

> What is filename.c_str() saying?

That gets a C-style '\0' terminated string from the std::string, which is what you need for std::ifstream's constructor. [It always strikes me as a shame that std::ifstream's ctor doesn't accept a std::string.]
If you are getting confused by paths etc. try repacing:

>     std::ifstream fin(filename.c_str());

with
 
       std::ifstream fin("c:\\file.cpp"); // Double backslash because '\' is an escape

Step through the code with your debugger.
Avatar of jandhb

ASKER

1. "replace the stack functionality in your Parse class with a standard library stack"....I will need some help with this, please. I really want to learn but this is something totally new. can you please help with the implementation of this.

2. "If you want to wrap a class around the stack that's fine." I'm not sure what you mean. Help me. I would like to do this "It would be more legible to have a user-defined class to contain the brace character, line and column (assuming you do indeed want to display line and column).", but I need help man. I just dont know at this point.  

3. "Are you using a GUI to develop your application" This is a simple console application.
Avatar of jandhb

ASKER

I am not clear, since were using this container, on what my class should look like...Can you show me, please?

"I've been pushing/popping a standard library pair where part of the pair is a pair itself." What do you mean by this? Are you saying that this code will parse the file?? Sorry for my fundamentary ?'s. I'm just learning this new way of doing it.
> Is there a way to clean up main() a little bit and just call the functions that are being used, maybe have them in another file?? If yes, how would this be implemented?

Certainly you can make it more modular. You'll find that code posted here on EE tends to be geared towards making the post short. I think you know the answers to your questions... or at least know enough to be able to experiment.

Let me know if you hit a brick wall.
Avatar of jandhb

ASKER

I have hit a brick wall in that I dont know what the class should now look like....Can you show me? Thank you for your help.
Avatar of jandhb

ASKER

I have tried to just have

     //std::cout << "Enter your filename: ";
     std::string filename;
     //std::cin >> filename;
       //convert a string object into a character array 'c_str()'
     //std::ifstream fin(filename.c_str());
       std::ifstream fin("c:\\file.cpp");
     if (!fin) {
          std::cout << "Error: Unable to open " << filename << '\n';
          return 1;
     }

But it still says, unable to open file. What am I doing wrong?
Avatar of jandhb

ASKER

Ok. It now appears to be opening, but it does not do anything. I mean when I run the program using the cmd and I hit enter to run it all it does is display c:\documents and settings\my name>

why is it not parsing the file and displaying the results?
> 1. "replace the stack functionality in your Parse class with a standard library stack"....I will need some help with this, please. I really want to learn but this is something totally new. can you please help with the implementation of this.

Let me know when you need the help. Sure I can help when you get snagged, but the rate at which you are firing questions makes me think that you'd do better if you spent some more time trying to do it yourself.

> 2. "If you want to wrap a class around the stack that's fine." I'm not sure what you mean. Help me. I would like to do this

A class can contain a class. If you want to implement a class called Parser, you could have a data member in the class which is the standard library stack. It is a nice way to organise your code.

> "It would be more legible to have a user-defined class to contain the brace character, line and column (assuming you do indeed want to display line and column).", but I need help man. I just dont know at this point.
> ... pair etc.

OK, here's how you might write a user-defined class:

  class Brace {
  char brace_character; // '{', '(' or '['
  int line,column; // Line and column where the brace character appears
  // ... etc...
  };

To be quick, I used some a couple of typedefs:

  typedef std::pair<int,int> LineColumn;
  typedef std::pair<char,LineColumn> Brace;

...but this left my code less legible than it would have been, if I'd gone for a user-defined class.

> 3. "Are you using a GUI to develop your application" This is a simple console application.

You misunderstood my question. When you develop your console application, what tools are you using? Are the tools all from the command line or are you developing within an integrated development environment (i.e. GUI)? If you are using a GUI to develop, it is quite possible that you have not set the working directory.
> why is it not parsing the file and displaying the results?

It indicates nothing when there are no parse errors.

You could add a no errors message at the end.

e.g.

--------8<--------
// ...

    std::cout << "No parse errors in " << filename << '\n';
    return 0;

} // end of main
--------8<--------
Avatar of jandhb

ASKER

1. As I said, can you PLEASE just show me how this is done. I don't know. I think I have made that clear. Can you just help me to understand how to implement this.

2. Sure I would like to keep the class I have written. But my question again is, how do I implement the standard library stack and also have that be a data member of the Parser class I have already? I'm just trying to put this all together.
Avatar of jandhb

ASKER

I am using Visual Studio.Net 2002 version 7.0

To run the program I just open cmd and drag the exe unto the screen and hit enter.
Avatar of jandhb

ASKER

Ok. I have...

     //std::cout << "Enter your filename: ";
     std::string filename;
     //std::cin >> filename;
       //convert a string object into a character array 'c_str()'
     //std::ifstream fin(filename.c_str());
       std::ifstream fin("D:\\AlgorithmsFall04\\A4b\\4brev1\\file.cpp");
     if (!fin) {
          std::cout << "Error: Unable to open " << filename << '\n';
          return 1;
     }
       else {
             std::cout << "File opened" << '\n';
       }

And it says, file opened

And I know the file does not have any errors

However, I put this code in at the end like you said

 std::cout << "No parse errors in " << filename << '\n';

And when it runs it just says, No parse errors in              There is no filename?? Why is that?
That makes the working directory whatever your cmd prompt says it is. You'd need to have file.cpp in that directory.

e.g. If you see:

C:\My stuff>"C:\Documents and Settings\jandhb\Desktop\test\test.exe"

...your working directory is "c:\My stuff"
> There is no filename?? Why is that?

You commented out the code that takes the filename
I'm going to leave you with your problems until tomorrow. I need to get on with other things now. Hope you can pick things up from here.
Avatar of jandhb

ASKER

If your still there what does the column mean? In other words, inside the file that its parsing how are the columns defined. I think the lines are easy to understand.
In a file that goes:

--------8<--------
abcdef
ghijkl
mnopqr
--------8<--------

Line 3 column 4 contains 'p'

Note that hard tab stops can make columns confusing.
Avatar of jandhb

ASKER

Well...I talked to my instructor and he said that I can't at this point use the built in stack class. I have to build my own and basically use what we have been taught so far. With that said..I guess I'm back at square one, but hopefully not. I just have to read in the information like you are written above, push/pop where necessary and display the results. So, my thinking is that it is basically the same as what you wrote above, but that I have to write the class for it. How do I do that? Like I said, here is what I have so far....Can you take me through this and tell me what I need to change....

----------------------------------------
 Driver.cpp

#include "Parse.h"
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
      //declare object of class Parse
      Parse pobject;

      //declare file stream object
      ifstream input;
      char fileName[50];

      cout << "File to be opened:  " << endl;
      cin.getline(fileName, 50);
      input.open(fileName, ios::in);
      //verify file was opened
      cout << fileName << " was opened." << endl;
      
      //call parseInput, pass it the file to be parsed
      pobject.parseInput(input);

      return 0;
}

--------------------------------------------------------
Parse.h

#ifndef PARSE_H
#define PARSE_H
#include <fstream>

using namespace std;

typedef char T;
class Parse
{
public:
      //constructor
      Parse(T size);
      //destructor
      ~Parse();
      //function to parse input file
      void parseInput(istream&);
      //display results of parse
      void display() const;
      //push
      void push(T);
      //pop
      void pop();
      //empty
      bool empty() const;
      //full
      bool full()const;

private:
      //list is an array of values
      T *list;
      //current number of elements in stack
      T stackTop;
      T maxSize;
};
#endif
-----------------------------------------------------------
Parse.cpp

#include "Parse.h"
#include <iostream>


//constructor
Parse::Parse(T size) : maxSize(size), stackTop(0)
{
      //dynamically allocate array to list size
      list = new T[size];
}

//destructor
Parse::~Parse()
{
      delete [] list;
}

//parseInput
void Parse::parseInput(istream& input)
{
      char characterLine[800];

      while (!input.eof())
      {
            input.getline(characterLine,800,' ');

            for (int i = 0; i > sizeof(characterLine); i++)
            {
                  switch(characterLine[i])
                  {
                  case '(':
                        {
                              //push unto stack
                              push(characterLine(i);
                        } break;
                  case ')':
                        {
                              //check to see if top element is matching closing ')'
                              if (list->top == '(' && characterLine(i) == ')')
                              {
                                    //we have a match, pop element from stack
                                    pop();
                              }
                        } break;
                  case '[':
                        {
                              //push unto stack
                              push(characterLine(i);
                        }break;
                  case ']':
                        {
                              //check to see if top element is matching closing ']'
                              if (list->top == '[' && characterLine(i) == ']')
                              {
                                    //we have a match, pop element from stack
                                    pop();
                              }
                        }break;
                  case '{':
                        {
                              //push unto stack
                              push(characterLine(i);
                        }break;
                  case '}':
                        {
                              //check to see if top element is matching closing '}'
                              if (list->top == '{' && characterLine(i) == '}')
                              {
                                    //we have a match, pop element from stack
                                    pop();
                              }
                        }break;
                  default: break;
                  }
            }
      }
}

//display
void Parse::display() const
{


}

//push
void Parse::push(T)
{
      if (!full())
      {
            list[stackTop] = item;
            //increment stack by one
            ++stackTop;
      }
}

//pop
void Parse::pop()
{
      if(!empty())
      {
            --stackTop;
      }
}

//empty
bool Parse::empty() const
{
      return (stackTop == 0);
}

//full
bool Parse::full() const
{
      return (stackTop == maxSize);
}
----------------------------------------------------------

If it would be easier you can show me how to read in one character at a time. Whatever it takes to get this done, really.
Avatar of jandhb

ASKER

I made a few changes. I still need help with the parseInput() and display() I think. The parseInput() should not be displaying anything. This should be done in the display(). How do I implement that? I don't think the parseInput() is right.



------------------------------------------
driver.cpp

#include "Parse.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
      Parse pObject;

       cout << "Enter your filename: ";
     string filename;
     cin >> filename;
       //convert a string object into a character array 'c_str()'
     //std::ifstream fin(filename.c_str());
       ifstream fin("D:\\AlgorithmsFall04\\A4b\\4brev1\\file.cpp");
     if (!fin) {
          std::cout << "Error: Unable to open " << filename << '\n';
          return 1;
     }
       else {
             std::cout << "File opened" << '\n';
       }

      //call parseInput and pass the file to be parsed
      pObject.parseInput(fin);


      return 0;
}

-----------------------------------------
parse.cpp

#include "Parse.h"
#include <iostream>
 
typedef std::istreambuf_iterator<char> Citr;

//constructor
Parse::Parse(T size) : maxSize(size), stackTop(0)
{
      //dynamically allocate array to list size
      list = new T[size];
}

//destructor
Parse::~Parse()
{
      delete [] list;
}

//parseInput
void Parse::parseInput(istream& input)
{
     int line = 1,column = 1;
     for (Citr itr(fin);itr != end;++itr) {
          switch (*itr) {

          // Pushes
          case '{':
          case '[':
          case '(':
               Parse.push(Brace(*itr,LineColumn(line,column)));
               break;

          // Pops
          case '}':
          case ']':
          case ')':
               if (Parse.empty()) {
                    std::cout
                         << "Error: " << filename << " line " << line << " column " << column
                         << ": Unmatched closing brace '" << *itr << "'\n";
                    return 1;
               }
               else if (Parse.top().first != match(*itr)) {
                    const LineColumn& lineColumn = braceStack.top().second;
                    std::cout
                         << "Error: " << filename << " line " << lineColumn.first << " column " << lineColumn.second
                         << ": Unmatched opening brace '" << braceStack.top().first
                         << "' found closing brace '" << *itr
                         << "' at line " << line << " column " << column
                         << "\n";
                    return 1;
               }
               Parse.pop();
               break;

          // EOL
          case '\n':
               column = 0;
               line++;
          }
          column++;
     }
     if (!Parse.empty()) {
          const LineColumn& lineColumn = braceStack.top().second;
          std::cout
               << "Error: " << filename << " line " << lineColumn.first << " column " << lineColumn.second
               << ": Unmatched opening brace '" << braceStack.top().first
               << "'\n";
          return 1;
     }

       std::cout << "No parse errors in " << filename << '\n';
}

//display
void Parse::display() const
{



}

//push
void Parse::push(T)
{
      if (!full())
      {
            //list[stackTop] = item;
            //increment stack by one
            ++stackTop;
      }
}

//pop
void Parse::pop()
{
      if(!empty())
      {
            --stackTop;
      }
}

//empty
bool Parse::empty() const
{
      return (stackTop == 0);
}

//full
bool Parse::full() const
{
      return (stackTop == maxSize);
}

-----------------------------------------------
parse.h

#ifndef PARSE_H
#define PARSE_H
#include <fstream>

using namespace std;

typedef char T;
class Parse
{
public:
      //constructor
      Parse(T size);
      //destructor
      ~Parse();
      //function to parse input file
      void parseInput(istream&);
      //display results of parse
      void display() const;
      //push
      void push(T);
      //pop
      void pop();
      //empty
      bool empty() const;
      //full
      bool full()const;

private:
      //list is an array of values
      T *list;
      //current number of elements in stack
      T stackTop;
      T maxSize;
};
#endif
Presumably, if you are not allowed to use the standard library for a stack, you are also not allowed to use a standard library for a vector. I don't understand why people are taught to use arrays in the first stages of C++.

So you need to have an array of somethings to copy your brace information into. Consider what information you need to copy. I suggest retaining the brace character (to differentiate between {, ( and [), the line number and column. A suitable structure to store this information would be:

  struct Brace {
  char brace_character; // '{', '(' or '['
  int line,column; // Line and column where the brace character appears
  };

No need to make it a class really. So have an array of Brace.

Can you take this on from here?
Avatar of jandhb

ASKER

So, then would this be correct for the class declaration (my parse.h file)

#ifndef PARSE_H
#define PARSE_H
#include <fstream>

using namespace std;

typedef char T;

  struct Brace
 {
  char brace_character; // '{', '(' or '['
  int line,column; // Line and column where the brace character appears
  };

class Parse
{
public:
      //constructor
      Parse(T size);
      //destructor
      ~Parse();
      //function to parse input file
      void parseInput(istream&);
      //display results of parse
      void display() const;
      //push
      void push(T);
      //pop
      void pop();
      //empty
      bool empty() const;
      //full
      bool full()const;

private:
      //list is an array of values
      T *list;
      //current number of elements in stack
      T stackTop;
      T maxSize;
};
#endif


If yes, can you please show me what the parseInput() would look like...I think what I currently have needs to be modified.
Avatar of jandhb

ASKER

Also, is my constructor correct like this...

Parse::Parse(T size) : maxSize(size), stackTop(0)
{
      //dynamically allocate array to list size
      list = new T[size];
}

Or is there a better way to do this?

Also, as I said, I don't need to display anthing in the parseInput() only in the display()
Avatar of jandhb

ASKER

With the implementation of the struct Brace can you please tell me what I would need to modify in my parseInput() to get this to work....Here is what I have so far?

void Parse::parseInput(istream& fin)
{
     int line = 1,column = 1;
       Citr end;
     for (Citr itr(fin);itr != end;++itr) {
          switch (*itr) {

          // Pushes
          case '{':
          case '[':
          case '(':
               Parse.push(Brace(*itr,LineColumn(line,column)));
               break;

          // Pops
          case '}':
          case ']':
          case ')':
               if (Parse.empty()) {
                    std::cout
                         << "Error: " << filename << " line " << line << " column " << column
                         << ": Unmatched closing brace '" << *itr << "'\n";
                    return 1;
               }
               else if (Parse.top().first != match(*itr)) {
                    const LineColumn& lineColumn = braceStack.top().second;
                    std::cout
                         << "Error: " << filename << " line " << lineColumn.first << " column " << lineColumn.second
                         << ": Unmatched opening brace '" << braceStack.top().first
                         << "' found closing brace '" << *itr
                         << "' at line " << line << " column " << column
                         << "\n";
                    return 1;
               }
               Parse.pop();
               break;

          // EOL
          case '\n':
               column = 0;
               line++;
          }
          column++;
     }
     if (!Parse.empty()) {
          const LineColumn& lineColumn = braceStack.top().second;
          std::cout
               << "Error: " << filename << " line " << lineColumn.first << " column " << lineColumn.second
               << ": Unmatched opening brace '" << braceStack.top().first
               << "'\n";
          return 1;
     }

       std::cout << "No parse errors in " << filename << '\n';
}
Have good think about the type T.

--------8<-------
Parse::Parse(T size) : maxSize(size), stackTop(0)
{
     //dynamically allocate array to list size
     list = new T[size];
}
--------8<-------

You have typedefed it as a char, which has the range -128...+127 which means that your array has a maximum size of 127.

In your constructor, I suggest that you use an array of Brace instead, and to avoid confusion remove T from your code (rather than being temped by typedefing Brace as T).

Conventionally size_t (which is typically a typedef for unsigned int) is used for sizes. Use size_t, if you have come across it or int, if your lecturer has yet to introduce size_t to you.

Change the ctor to:
--------8<-------
Parse::Parse(size_t size) : maxSize(size), stackTop(0)
{
     //dynamically allocate array to list size
     list = new Brace[size];
}
--------8<-------

The class member stackTop and maxSize should also be of type size_t (or unsigned int):

   size_t stackTop;
   size_t maxSize;

For convenience, you'll want to define a non-default ctor to set the Brace struct data members, but that means you also need to define a default ctor, because the compiler doesn't automatically define a default ctor, if you have a non-default ctor defined. You need the default ctor to construct the array. Also, since it is an academic project, you probably ought to use a class with setters and getters instead of the struct.

i.e.
--------8<-------
class Brace {
     char brace_character; // '{', '(' or '['
     int line,column; // Line and column where the brace character appears
public:
     Brace() {}

     int getLine() const {return line;}
     int getColumn() const {return column;}
     char getBrace_character() const {return brace_character;}

     void setLine(int line) {Brace::line = line;}
     void setColumn(int column) {Brace::column = column;}
     void setBrace_character(char brace_character) {Brace::brace_character = brace_character;}

     char getMatching_brace_character() const;
};

// Returns the character, which matches Brace::brace_character
char Brace::getMatching_brace_character() const
{
     switch (brace_character) {
     case '{': return '}';
     case '[': return ']';
     case '(': return ')';
     case '}': return '{';
     case ']': return '[';
     case ')': return '(';
     }
     return 0;
}
--------8<-------

Having done this, you have the following tweaks to your code:

(1) In Parse::parseInput

(a)
>               Parse.push(Brace(*itr,LineColumn(line,column)));
               push(Brace(*itr,line,column));

   (NB: When calling one class function from another, you do not need to write Parse::push and it is incorrect to write Parse.push.

(b) To implement top(), you should use something like this:

// Returns true, if the Brace stack is empty
bool Parse::empty() const {
    return stackTop == 0;
};

// Returns the size of the stack
size_t Parse::size() const {
    return stackTop;
};

// Returns a const reference to the Brace at the top of the stack
// Only works when size() > 0 (i.e. !empty())
const Brace& Parse::top() const
{
    return list[size()-1];
}

(c)
 
               else if (top().getMatching_brace_character() != *itr) {
                    const Brace& brace = top();
                    std::cout
                         << "Error: " << filename << " line " << brace.getLine() << " column " << brace.getColumn()
                         << ": Unmatched opening brace '" << brace.getBrace_character()
                         << "' found closing brace '" << *itr
                         << "' at line " << line << " column " << column
                         << "\n";
                    return 1;
               }

Get the idea?
Avatar of jandhb

ASKER

a couple of questions about that? are you saying that my class should now look like this?

#ifndef PARSE_H
#define PARSE_H
#include <fstream>

using namespace std;

struct Brace
{
      // '{', '(' or '['
      char brace_character;
      // Line and column where the brace character appears
      int line,column;
};

typedef char T;
class Brace {
     char brace_character; // '{', '(' or '['
     int line,column; // Line and column where the brace character appears
public:

      //destructor
      ~Brace();
      //function to parse input file
      void parseInput(istream&);
      //display results of parse
      void display() const;
      //push
      void push(T);
      //pop
      void pop();
      //empty
      bool empty() const;
      //full
      bool full()const;
      Brace() {}
      int getLine() const {return line;}
    int getColumn() const {return column;}
    char getBrace_character() const {return brace_character;}

    void setLine(int line) {Brace::line = line;}
    void setColumn(int column) {Brace::column = column;}
    void setBrace_character(char brace_character) {Brace::brace_character = brace_character;}

    char getMatching_brace_character() const;


private:
      //list is an array of values
      T *list;
      size_t stackTop;      
      size_t maxSize;
};

// Returns the character, which matches Brace::brace_character
char Brace::getMatching_brace_character() const
{
     switch (brace_character) {
     case '{': return '}';
     case '[': return ']';
     case '(': return ')';
     case '}': return '{';
     case ']': return '[';
     case ')': return '(';
     }
     return 0;
}


#endif
Avatar of jandhb

ASKER

Is this information here supposed to be inside my existing Parse class?? I'm not clear on that.

class Brace {
     char brace_character; // '{', '(' or '['
     int line,column; // Line and column where the brace character appears
public:
     Brace() {}

     int getLine() const {return line;}
     int getColumn() const {return column;}
     char getBrace_character() const {return brace_character;}

     void setLine(int line) {Brace::line = line;}
     void setColumn(int column) {Brace::column = column;}
     void setBrace_character(char brace_character) {Brace::brace_character = brace_character;}

     char getMatching_brace_character() const;
};

// Returns the character, which matches Brace::brace_character
char Brace::getMatching_brace_character() const
{
     switch (brace_character) {
     case '{': return '}';
     case '[': return ']';
     case '(': return ')';
     case '}': return '{';
     case ']': return '[';
     case ')': return '(';
     }
     return 0;
}
Avatar of jandhb

ASKER

I'm not sure if  this is correct, but I just made another file called "Brace.h" and in it I put...

class Brace {
     char brace_character; // '{', '(' or '['
     int line,column; // Line and column where the brace character appears
public:
     Brace() {}

     int getLine() const {return line;}
     int getColumn() const {return column;}
     char getBrace_character() const {return brace_character;}

     void setLine(int line) {Brace::line = line;}
     void setColumn(int column) {Brace::column = column;}
     void setBrace_character(char brace_character) {Brace::brace_character = brace_character;}

     char getMatching_brace_character() const;
};

// Returns the character, which matches Brace::brace_character
char Brace::getMatching_brace_character() const
{
     switch (brace_character) {
     case '{': return '}';
     case '[': return ']';
     case '(': return ')';
     case '}': return '{';
     case ']': return '[';
     case ')': return '(';
     }
     return 0;
}

----------------------------------------

Then in my Parse.cpp file at the top I put #include "Brace.h"

Is this correct to do it like this?

-------------------------------------------------------

My Parse class (Parse.h) file now looks like this....

#ifndef PARSE_H
#define PARSE_H
#include <fstream>

using namespace std;

typedef char T;
class Parse
{
public:
      //constructor
      Parse(T size);
      //destructor
      ~Parse();
      //function to parse input file
      void parseInput(istream&);
      //display results of parse
      void display() const;
      //push
      void push(T);
      //pop
      void pop();
      //empty
      bool empty() const;
      //full
      bool full()const;
      size_t size() const;

private:
      //list is an array of values
      T *list;
      //current number of elements in stack
      size_t stackTop;
      size_t maxSize;

};
#endif
Avatar of jandhb

ASKER

Here is my Parse.cpp file. I'm getting a lot of errors, but the first couple have to do with this line

 push(Brace(*itr,LineColumn(line,column)));

It says, error C2065: 'LineColumn' : undeclared identifier

Then on this line it says, error C2065: 'filename' : undeclared identifier

<< "Error: " << filename << " line " << line << " column " << column

I don't want to be displaying things in parseInput?? I should be using my display function for that, right?

-----------------------------------------------------------
Parse.cpp

#include "Parse.h"
#include "Brace.h"
#include <iostream>
 
typedef std::istreambuf_iterator<char> Citr;

//constructor
Parse::Parse(T size) : maxSize(size), stackTop(0)
{
      //dynamically allocate array to list size
      list = new T[size];
}

//destructor
Parse::~Parse()
{
      delete [] list;
}

//parseInput
void Parse::parseInput(istream& fin)
{
     int line = 1,column = 1;
       Citr end;
     for (Citr itr(fin);itr != end;++itr) {
          switch (*itr) {

          // Pushes
          case '{':
          case '[':
          case '(':
               push(Brace(*itr,LineColumn(line,column)));
               break;

          // Pops
          case '}':
          case ']':
          case ')':
               if (Parse.empty()) {
                    std::cout
                         << "Error: " << filename << " line " << line << " column " << column
                         << ": Unmatched closing brace '" << *itr << "'\n";
                    return 1;
               }
              else if (top().getMatching_brace_character() != *itr) {
                    const Brace& brace = top();
                    std::cout
                         << "Error: " << filename << " line " << brace.getLine() << " column " << brace.getColumn()
                         << ": Unmatched opening brace '" << brace.getBrace_character()
                         << "' found closing brace '" << *itr
                         << "' at line " << line << " column " << column
                         << "\n";
                    return 1;
               }
               Parse.pop();
               break;

          // EOL
          case '\n':
               column = 0;
               line++;
          }
          column++;
     }
     if (!Parse.empty()) {
          const LineColumn& lineColumn = braceStack.top().second;
          std::cout
               << "Error: " << filename << " line " << lineColumn.first << " column " << lineColumn.second
               << ": Unmatched opening brace '" << braceStack.top().first
               << "'\n";
          return 1;
     }

       std::cout << "No parse errors in " << filename << '\n';
}

//display
void Parse::display() const
{



}

//push
void Parse::push(T)
{
      if (!full())
      {
            //list[stackTop] = item;
            //increment stack by one
            ++stackTop;
      }
}

//pop
void Parse::pop()
{
      if(!empty())
      {
            --stackTop;
      }
}

//empty
bool Parse::empty() const
{
      return (stackTop == 0);
}

//full
bool Parse::full() const
{
      return (stackTop == maxSize);
}

// Returns the size of the stack
size_t Parse::size() const {
    return stackTop;
};

// Returns a const reference to the Brace at the top of the stack
// Only works when size() > 0 (i.e. !empty())
const Brace& Parse::top() const
{
    return list[size()-1];
}
-------------------------------------------------------------------------

Driver.cpp

#include "Parse.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
      Parse pObject;

       cout << "Enter your filename: ";
     string filename;
     cin >> filename;
       //convert a string object into a character array 'c_str()'
     //std::ifstream fin(filename.c_str());
       ifstream fin("D:\\AlgorithmsFall04\\A4b\\4brev1\\file.cpp");
     if (!fin) {
          std::cout << "Error: Unable to open " << filename << '\n';
          return 1;
     }
       else {
             std::cout << "File opened" << '\n';
       }

      //call parseInput and pass the file to be parsed
      pObject.parseInput(fin);


      return 0;
}
----------------------------------------------------------------

Brace.h

class Brace {
     char brace_character; // '{', '(' or '['
     int line,column; // Line and column where the brace character appears
public:
     Brace() {}

     int getLine() const {return line;}
     int getColumn() const {return column;}
     char getBrace_character() const {return brace_character;}

     void setLine(int line) {Brace::line = line;}
     void setColumn(int column) {Brace::column = column;}
     void setBrace_character(char brace_character) {Brace::brace_character = brace_character;}

     char getMatching_brace_character() const;
};

// Returns the character, which matches Brace::brace_character
char Brace::getMatching_brace_character() const
{
     switch (brace_character) {
     case '{': return '}';
     case '[': return ']';
     case '(': return ')';
     case '}': return '{';
     case ']': return '[';
     case ')': return '(';
     }
     return 0;
}

> push(Brace(*itr,LineColumn(line,column)));

You skipped the edit (1) (a) in http:/Q_21136122.htm#12100696
> Then on this line it says, error C2065: 'filename' : undeclared identifier

That is because it is undeclared in the Parse class.

You could do one of the following:

(1) Make it a global variable - this is generally considered the last resort in C++
(2) Declare a member variable in Parse which is initialised by a setter function - e.g. Parse::setFilename(const string&) - this is not ideal practice because it is easy to forget to initialise the variable
(3) Declare a member variable in Parse which is initialised by the Parse constructor - this is the best approach
> I don't want to be displaying things in parseInput?? I should be using my display function for that, right?

There are elegant ways of separating out display, which you might use. However, I recommend you set yourself the target of getting this working and leave that kind of consideration for another project.
You've posted a load of questions, which I've not addressed. I suspect that you've mostly answered them for yourself.
One other thing I spotted...

In Parse::parseInput you call class functions empty() and pop() using Parse.empty() and Parse.pop(). This is a syntax error, which will throw up an error in the compiler. You could write Parse::empty() and Parse::pop() to specify the Parse functions explicitly, but you'll find that as you hone your C++ skills (and get into class inheritence) it is better simply to call pop() and empty(), because those names are within scope.


Avatar of jandhb

ASKER

I don't understand what you mean by this...

push(Brace(*itr,LineColumn(line,column)));

You skipped the edit (1) (a) in http:/Q_21136122.htm#12100696

What should this line look like. It is telling me error C2064: term does not evaluate to a function. It also says, error C2661: 'Brace::Brace' : no overloaded function takes 2 parameters

push(Brace(*itr,LineColumn(line,column)));

Also, I declared LineColumn in my constructor like you said. So, now it looks like this..

Parse::Parse(T size) : maxSize(size), stackTop(0), LineColumn(0)
{
      //dynamically allocate array to list size
      list = new T[size];
}

However, on this line in parseInput() I get an error saying, undeclared identifier. Do I have to do the same thing for lineColumn?

const LineColumn& lineColumn = braceStack.top().second;

And in this function...

const Brace& Parse::top() const
{
    return list[size()-1];
}

I get... error C2039: 'top' : is not a member of 'Parse'
error C2270: 'top' : modifiers not allowed on nonmember function
error C2065: 'list' : undeclared identifier




In http:Q_21136122.htm#12100696 (1) (a) I wrote the following:

--------8<--------
>               Parse.push(Brace(*itr,LineColumn(line,column)));
               push(Brace(*itr,line,column));
--------8<--------

The line starting with the character '>' shows you the code which you have. The following line shows you what I suggest you change it to. There are essentially two changes: the Parse::push() function does not need a qualifier (the correct qualifier would have been Parse:: rather than Parse. anyhow); the Brace object is created by a three parameter constructor (you were using std::pair constructor with a std::pair parameter from my earlier posting - since you are using a user-defined Brace class, the constructor is simpler).

Brace(*itr,line,column) creates an object of your user-defined Brace class, using a non-default constructor, which I've just noticed that I failed to flesh out for you. Sorry, if this caused confusion.

Here it is:
--------8<--------
class Brace {
     char brace_character; // '{', '(' or '['
     int line,column; // Line and column where the brace character appears
public:

     /* Here is the default ctor - which was only necessary because we are defining a non-default ctor - otherwise the compiler-generated default ctor would have been fine for our purposes, because we don't want the default ctor to bother initialising anything */
     Brace() {}

     /* Here's the non-default ctor I missed in my hasty posting... */
     Brace(char brace_character,int line,int column) : brace_character(brace_character),line(line),column(column) {}

     int getLine() const {return line;}
     int getColumn() const {return column;}
     char getBrace_character() const {return brace_character;}

     void setLine(int line) {Brace::line = line;}
     void setColumn(int column) {Brace::column = column;}
     void setBrace_character(char brace_character) {Brace::brace_character = brace_character;}

     char getMatching_brace_character() const;
};
--------8<--------

> Also, I declared LineColumn in my constructor like you said.
> const LineColumn& lineColumn = braceStack.top().second;

LineColumn was used in the construction of the std::pair version of the Brace class, which with hindsight I regret suggesting. Since your lecturer doesn't want you to use standard library stacks, s/he will also not want you to use standard library tuples like std::pair<>.

Please use the code in http:Q_21136122.htm#12100696 (1) (c).

i.e.
--------8<--------
void Parse::parseInput(istream& fin)
{
     int line = 1,column = 1;
     Citr end;
     for (Citr itr(fin);itr != end;++itr) {
          switch (*itr) {

          // Pushes
          case '{':
          case '[':
          case '(':
               push(Brace(*itr,line,column));
               break;

          // Pops
          case '}':
          case ']':
          case ')':
               if (empty()) {
                    std::cout
                         << "Error: " << filename << " line " << line << " column " << column
                         << ": Unmatched closing brace '" << *itr << "'\n";
                    return 1;
               }
              else if (top().getMatching_brace_character() != *itr) {
                    const Brace& brace = top();
                    std::cout
                         << "Error: " << filename << " line " << brace.getLine() << " column " << brace.getColumn()
                         << ": Unmatched opening brace '" << brace.getBrace_character()
                         << "' found closing brace '" << *itr
                         << "' at line " << line << " column " << column
                         << "\n";
                    return 1;
               }
               pop();
               break;

          // EOL
          case '\n':
               column = 0;
               line++;
          }
          column++;
     }
     if (!empty()) {
            const Brace& brace = top();
            std::cout
                 << "Error: " << filename << " line " << brace.getLine() << " column " << brace.getColumn()
                 << ": Unmatched opening brace '" << brace.getBrace_character()
                 << "' found closing brace '" << *itr
                 << "' at line " << line << " column " << column
               << "'\n";
          return 1;
     }
     std::cout << "No parse errors\n";
}
--------8<--------

> I get... error C2039: 'top' : is not a member of 'Parse'

You need to add it to the Parse class definition.

i.e.

// This is the definition
class Parse {
    // .... blah
public:
    // .... blah
    const Brace& Parse::top() const;
};    

// This is the implementation
const Brace& Parse::top() const
{
    return list[size()-1];
}
Avatar of jandhb

ASKER

Ok. I will make those changes either tonight or tomorrow and let you know how it goes. I'm at work right now and have class tonight that is why I will not be able to get to it until then. Thanks for all your help.

BTW - Just to let you know whenever you put lines like this in your comments http:Q_21136122.htm#12100696 and I click on it the page goes to "unable to find specified url".
Oops, missed the 'l' in .html - this should work http:Q_21136122.html#12100696 
Avatar of jandhb

ASKER

Based upon recommended changes here is what we have so far....I will pst another comment after this showing some of the errors being received.

----------------------------------------------
Parse. h

#ifndef PARSE_H
#define PARSE_H
#include <fstream>

using namespace std;

typedef char T;
class Parse
{
public:
      //constructor
      Parse(T size);
      //destructor
      ~Parse();
      //function to parse input file
      void parseInput(istream&);
      //display results of parse
      void display() const;
      //push
      void push(T);
      //pop
      void pop();
      //empty
      bool empty() const;
      //full
      bool full()const;
      size_t size() const;
      const Brace& Parse::top() const;

private:
      //list is an array of values
      T *list;
      //current number of elements in stack
      size_t stackTop;
      size_t maxSize;
      size_t LineColumn;
      

};
#endif
------------------------------------------------

Parse.cpp

#include "Parse.h"
#include "Brace.h"
#include <iostream>
 
typedef std::istreambuf_iterator<char> Citr;

//constructor
Parse::Parse(T size) : maxSize(size), stackTop(0), LineColumn(0)
{
      //dynamically allocate array to list size
      list = new T[size];
}

//destructor
Parse::~Parse()
{
      delete [] list;
}

//parseInput
void Parse::parseInput(istream& fin)
{
     int line = 1,column = 1;
     Citr end;
     for (Citr itr(fin);itr != end;++itr) {
          switch (*itr) {

          // Pushes
          case '{':
          case '[':
          case '(':
               push(Brace(*itr,line,column));
               break;

          // Pops
          case '}':
          case ']':
          case ')':
               if (empty()) {
                    std::cout
                         << "Error: " << filename << " line " << line << " column " << column
                         << ": Unmatched closing brace '" << *itr << "'\n";
                    return 1;
               }
              else if (top().getMatching_brace_character() != *itr) {
                    const Brace& brace = top();
                    std::cout
                         << "Error: " << filename << " line " << brace.getLine() << " column " << brace.getColumn()
                         << ": Unmatched opening brace '" << brace.getBrace_character()
                         << "' found closing brace '" << *itr
                         << "' at line " << line << " column " << column
                         << "\n";
                    return 1;
               }
               pop();
               break;

          // EOL
          case '\n':
               column = 0;
               line++;
          }
          column++;
     }
     if (!empty()) {
            const Brace& brace = top();
            std::cout
                 << "Error: " << filename << " line " << brace.getLine() << " column " << brace.getColumn()
                 << ": Unmatched opening brace '" << brace.getBrace_character()
                 << "' found closing brace '" << *itr
                 << "' at line " << line << " column " << column
               << "'\n";
          return 1;
     }
     std::cout << "No parse errors\n";
}

//display
void Parse::display() const
{



}

//push
void Parse::push(T)
{
      if (!full())
      {
            //list[stackTop] = item;
            //increment stack by one
            ++stackTop;
      }
}

//pop
void Parse::pop()
{
      if(!empty())
      {
            --stackTop;
      }
}

//empty
bool Parse::empty() const
{
      return (stackTop == 0);
}

//full
bool Parse::full() const
{
      return (stackTop == maxSize);
}

// Returns the size of the stack
size_t Parse::size() const {
    return stackTop;
};

// Returns a const reference to the Brace at the top of the stack
// Only works when size() > 0 (i.e. !empty())
const Brace& Parse::top() const
{
    return list[size()-1];
}
-------------------------------------------------------------------------

Driver.cpp


#include "Parse.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
      Parse pObject;

       cout << "Enter your filename: ";
     string filename;
     cin >> filename;
       //convert a string object into a character array 'c_str()'
     //std::ifstream fin(filename.c_str());
       ifstream fin("D:\\AlgorithmsFall04\\A4b\\4brev1\\file.cpp");
     if (!fin) {
          std::cout << "Error: Unable to open " << filename << '\n';
          return 1;
     }
       else {
             std::cout << "File opened" << '\n';
       }

      //call parseInput and pass the file to be parsed
      pObject.parseInput(fin);


      return 0;
}
--------------------------------------------------------------

Brace.h


class Brace {
     char brace_character; // '{', '(' or '['
     int line,column; // Line and column where the brace character appears
public:

     /* Here is the default ctor - which was only necessary because we are
       defining a non-default ctor - otherwise the compiler-generated default
       ctor would have been fine for our purposes, because we don't want the
       default ctor to bother initialising anything */
     Brace() {}

     /* Here's the non-default ctor I missed in my hasty posting... */
     Brace(char brace_character,int line,int column) : brace_character(brace_character),line(line),column(column) {}

     int getLine() const {return line;}
     int getColumn() const {return column;}
     char getBrace_character() const {return brace_character;}

     void setLine(int line) {Brace::line = line;}
     void setColumn(int column) {Brace::column = column;}
     void setBrace_character(char brace_character) {Brace::brace_character = brace_character;}

     char getMatching_brace_character() const;
};

Avatar of jandhb

ASKER

On  this line in Parse.h
const Brace& Parse::top() const;
receiving error C2143: syntax error : missing ';' before '&' and warning C4183: 'top': missing return type; assumed to be a member function returning 'int'

On this line in Parse.cpp
push(Brace(*itr,line,column));
receiving error C2664: 'Parse::push' : cannot convert parameter 1 from 'Brace' to 'T'

On this line in Parse.cpp
<< "Error: " << filename << " line " << line << " column " << column
receiving error C2065: 'filename' : undeclared identifier

On this line in Parse.cpp
else if (top().getMatching_brace_character() != *itr) {
receiving error C2228: left of '.getMatching_brace_character' must have class/struct/union type

On this line in Parse.cpp
return 1;
receiving error C2562: 'Parse::parseInput' : 'void' function returning a value

That is not all of them, but I think hopefully if you can help me get these resolved it will help the others??
ASKER CERTIFIED SOLUTION
Avatar of rstaveley
rstaveley
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jandhb

ASKER

Here is the code with revisions....

------------------------------------------
Parse.h

#ifndef PARSE_H
#define PARSE_H
#include <fstream>
#include "Brace.h"

using namespace std;

class Parse
{
public:
      //constructor
      Parse(size_t size,const string& filename);
      //destructor
      ~Parse();
      //function to parse input file
      int parseInput(istream&);
      //push
      void push(const Brace&);
      //pop
      void pop();
      //empty
      bool empty() const;
      //full
      bool full()const;
      size_t size() const;
      const Brace& top() const;

private:
      //list is an array of values
      Brace *list;
      //current number of elements in stack
      size_t stackTop;
      size_t maxSize;
      string filename;
};
#endif
--------------------------------------------------------

Parse.cpp

#include "Parse.h"
#include "Brace.h"
#include <iostream>
#include <string>
 
typedef std::istreambuf_iterator<char> Citr;

//constructor
Parse::Parse(size_t size,const string& filename) : maxSize(size), stackTop(0),filename(filename)
{
    list = new Brace[size]; // <- Array of Brace not char
}




//destructor
Parse::~Parse()
{
      delete [] list;
}

//parseInput
int Parse::parseInput(istream& fin)
{
     int line = 1,column = 1;
     Citr end;
     for (Citr itr(fin);itr != end;++itr) {
          switch (*itr) {

          // Pushes
          case '{':
          case '[':
          case '(':
               push(Brace(*itr,line,column));
               break;

          // Pops
          case '}':
          case ']':
          case ')':
               if (empty()) {
                    std::cout
                         << "Error: " << filename << " line " << line << " column " << column
                         << ": Unmatched closing brace '" << *itr << "'\n";
                    return 1;
               }
              else if (top().getMatching_brace_character() != *itr) {
                    const Brace& brace = top();
                    std::cout
                         << "Error: " << filename << " line " << brace.getLine() << " column " << brace.getColumn()
                         << ": Unmatched opening brace '" << brace.getBrace_character()
                         << "' found closing brace '" << *itr
                         << "' at line " << line << " column " << column
                         << "\n";
                    return 1;
               }
               pop();
               break;

          // EOL
          case '\n':
               column = 0;
               line++;
          }
          column++;
     }
     if (!empty()) {
            const Brace& brace = top();
            std::cout
                 << "Error: " << filename << " line " << brace.getLine() << " column " << brace.getColumn()
                 << ": Unmatched opening brace '" << brace.getBrace_character()
                 << "' found closing brace '" << *itr
                 << "' at line " << line << " column " << column
               << "'\n";
          return 1;
     }
       std::cout << "No parse errors in " << filename << '\n';
       return 0;
}

//push
void Parse::push(const Brace& item)
{
     if (!full())
     {
          list[stackTop] = item;
          //increment stack by one
          ++stackTop;
     }
}

//pop
void Parse::pop()
{
      if(!empty())
      {
            --stackTop;
      }
}

//empty
bool Parse::empty() const
{
      return (stackTop == 0);
}

//full
bool Parse::full() const
{
      return (stackTop == maxSize);
}

// Returns the size of the stack
size_t Parse::size() const {
    return stackTop;
};

// Returns a const reference to the Brace at the top of the stack
// Only works when size() > 0 (i.e. !empty())
const Brace& Parse::top() const
{
    return list[size()-1];
}
------------------------------------------------------------

Driver.cpp

#include "Parse.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
       Parse pObject(1024,filename);

       //cout << "Enter your filename: ";
     //string filename;
     //cin >> filename;
       string filename = "D:\\AlgorithmsFall04\\A4b\\4brev1\\file.cpp";

    //convert a string object into a character array 'c_str()'
    //std::ifstream fin(filename.c_str());
    ifstream fin(filename.c_str()); // <- Use variable name for file
    if (!fin) {
          std::cout << "Error: Unable to open " << filename << '\n';
          return 1;
     }
     else {
           std::cout << "File opened" << '\n';
     }

     //call parseInput and pass the file to be parsed
     return pObject.parseInput(fin);

}
---------------------------------------------------------------

Brace.h

class Brace {
     char brace_character; // '{', '(' or '['
     int line,column; // Line and column where the brace character appears
public:

     /* Here is the default ctor - which was only necessary because we are
       defining a non-default ctor - otherwise the compiler-generated default
       ctor would have been fine for our purposes, because we don't want the
       default ctor to bother initialising anything */
     Brace() {}

     /* Here's the non-default ctor I missed in my hasty posting... */
     Brace(char brace_character,int line,int column) : brace_character(brace_character),line(line),column(column) {}

     int getLine() const {return line;}
     int getColumn() const {return column;}
     char getBrace_character() const {return brace_character;}

     void setLine(int line) {Brace::line = line;}
     void setColumn(int column) {Brace::column = column;}
     void setBrace_character(char brace_character) {Brace::brace_character = brace_character;}

     char getMatching_brace_character() const;
};
------------------------------------------------------------------------

Brace.cpp

#include "Brace.h"

// Returns the character, which matches Brace::brace_character
char Brace::getMatching_brace_character() const
{
     switch (brace_character) {
     case '{': return '}';
     case '[': return ']';
     case '(': return ')';
     case '}': return '{';
     case ']': return '[';
     case ')': return '(';
     }
     return 0;
}
Avatar of jandhb

ASKER

On this line in Brace.h
class Brace {
Its telling me error C2011: 'Brace' : 'class' type redefinition

On this line in Driver.cpp
Parse pObject(1024,filename);
Its telling me error C2065: 'filename' : undeclared identifier

Also, with having string filename = "D:\\AlgorithmsFall04\\A4b\\4brev1\\file.cpp"; in Driver.cpp this does not really allow me to type in the filename, right? I do want that info. and that file, but I need to be able to prompt for it and then enter it. You know what I mean? So, would something like this work...

string filename;
Cout << "Enter filename";
cin >> filename; //basically the same information as we have now.


Avatar of jandhb

ASKER

rstaveley,

If your around now and have a few minutes to address these few more topics, hopefully, I would like to work together now. I have a little time if you do.

Avatar of jandhb

ASKER

Errors are fixed. I had to put...

#ifndef BRACE_H
#define BRACE_H
....
#endif

in the Brace.h

And I had to put

string filename = "D:\\AlgorithmsFall04\\A4b\\4brev1\\file.cpp";

above the defining of the pObject

Well, it appears to be working as it should. I really appreciate your help, and it has been that indeed. Thank you for taking the time to help me. You have suggested many things in which I can grow into. Thanks again. If there was a way to get you again when I post a question I would request that. :) Thanks!
I'm around, when things are slack at work, but there are a lot of very good experts here.

However, you'll need to use more question points, if you want to get good attention, generally. Most of us are motivated by points like Muttley is motivated by medals http://www.diceyhome.free-online.co.uk/muttleyonline.gif :-)
Avatar of jandhb

ASKER

rstaveley,

I need to modify what we were working on here...I say modify because I think as far as I can see this program reads a string of characters and pushes them unto a stack, right? Ok...now I need to use this + I need to add each character to a queue. Then I need to use basic stack and queue operations to determine if the string is a palindrome.

How could I go about these changes?
Avatar of jandhb

ASKER

Here is what I have so far. I'm getting plenty of errors. For example, I don't know what the stackInput function (to determine if its a palindrome) and push function should look like. I'm not sure if its the right way to go about adding them to Q either, but its a start..... Please let me know where I go from here with it. Thank you.

---------------------------------------------------
Stack.h

#ifndef STACK_H
#define STACK_H
#include <fstream>
//include the definition for the Queue class
#include "Queue.h"

using namespace std;

class Stack
{
public:
      //constructor
      //size_t for sizes instead of char
      //initialise filename in the constructor
      Stack(size_t size,const string& filename);
      //destructor
      ~Stack();
      //function to parse input file
      //Uses a return value (0 = success)
      int stackInput(istream&);
      //push
      //Pushing copies of items of type Brace
      void push(const Brace&);
      //pop
      void pop();
      //empty
      bool empty() const;
      //full
      bool full()const;
      size_t size() const;
      const Queue& top() const;
            
private:
      //storing character objects
      Queue *list;
      //current number of elements in stack
      size_t stackTop;
      size_t maxSize;
      //Used in output
      string filename;
};
#endif
--------------------------------------------------------------
Queue.h

#ifndef QUEUE_H
#define QUEUE_H

typedef char T;

class Queue
{
public:
      Queue();
      ~Queue();
      void enqueue(const T&item);
      //gets rid of first value in queue
      void dequeue();
      //look at value at front of queue
      T front() const;
      bool full() const;
      bool empty() const;

private:
      //markers
      char queueFront;
      char queueBack;
      char* values;
      char maxQSize;
      //number of elements currently in queue
      char count;
};
#endif
------------------------------------------------------------
Stack.cpp

#include "Stack.h"
#include <iostream>
#include <string>

typedef std::istreambuf_iterator<char> Citr;

//constructor
//Using size_t for size, initialising filename
Stack::Stack(size_t size,const string& filename) : maxSize(size), stackTop(0), filename(filename)
{
       //Array of Queue
    list = new Queue[size];
}

//destructor
Stack::~Stack()
{
      delete [] list;
}

//parseInput
int Stack::stackInput(istream& fin)
{

}

//push
//Pushing items
void Stack::push(const Queue& item)
{
     if (!full())
     {
             //Put the item in the stack
             list[stackTop] = item;
         //increment stack by one
             ++stackTop;
     }
}

//pop
void Parse::pop()
{
      if(!empty())
      {
            --stackTop;
      }
}

//empty
bool Stack::empty() const
{
      return (stackTop == 0);
}

//full
bool Stack::full() const
{
      return (stackTop == maxSize);
}

// Returns the size of the stack
size_t Stack::size() const {
    return stackTop;
};

// Returns a const reference to the Queue at the top of the stack
// Only works when size() > 0 (i.e. !empty())
const Queue& Stack::top() const
{
    return list[size()-1];
}
----------------------------------------------------------

Queue.cpp

#include "Queue.h"

//constructor
Queue::Queue(char s) : count(0), maxQSize(s), queueFront(0), queueBack(s-1)
{
      values = new T[s];
}

//destructor
Queue::~Queue()
{
      delete[] values;
}

//full
bool Queue::full() const
{
      return (count == maxQSize);
}

//empty
bool Queue::empty() const
{
      return (count == 0);
}

//front
T Queue::front() const
{
      return values [queueFront];
}

//enqueue
void Queue::enqueue(const T&item)
{
      if (!full())
      {
            queueBack = (queueBack + 1) % MaxQSize;
            values [queueBack] = item;
            ++ count;
      }
}

//dequeue
void Queue::dequeue()
{
      if (!empty())
      {
            -- count;
            queueFront = (queueFront + 1) % maxQSize;
      }
}
------------------------------------------------------
Driver.cpp

#include <iostream>
#include <fstream>
#include <string>
#include "Stack.h"
#include "Queue.h"

using namespace std;

int main()
{
      string filename;
      cout << "Enter filename:  " << endl;
      cin >> filename;

      //Need size and filename for constructor
      Stack sObject(1024,filename);

      //convert a string object into a character array 'c_str()'
      //Use variable name for file
    ifstream fin(filename.c_str());
    if (!fin)
      {
            std::cout << "Error: Unable to open " << filename << '\n';
            return 1;
     }
     else
       {
             std::cout << "File opened" << '\n';
     }

      return 0;
}


Can you post this as a ne question, jandhb? I'm under the kosh right now. It's best if you can put this into another expert's radar.
Avatar of jandhb

ASKER

np with that.

Here is something maybe a little simpler that you can help me with. Currently, in this main() I am hardcoding the words that I want to insert into the front and end functions. Can you tell me how I would read in a simple text file, say that looks like this...

sun
tree
apple

and have that be the data that gets inserted into the front and end. And then when I search I'm not hardcoding the word I am just looking through the file to see if its there. Does that make sense? Basically, I need to use this little txt file instead of me hard coding the words in. Here is what main() currently looks like.

-------------------------------------------------------
#include "LinkedList.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
     LinkedList list;
     string word;

     //insertFront
     list.insertFront("Tree");

     //insertEnd
     list.insertEnd("Apple");
     list.display();

     //insertFront user input
     cout << "Enter a word:  " << endl;
     cin >> word;
     list.insertFront(word);
     cout << "After user input list now contains:  " << endl;
     list.display();

     //search
     cout << "Search for:  " << endl;
     cin >> word;
     if (list.search(word))
     {
          cout << "Already on list." << endl;
     }

     //list size
     cout << "List size:  " << list.getLength() << endl;

     //return first value
     //use the c_str() method to get a 'const char*' that cout can deal with
     cout << "First value is: " << list.GetFirstValue().c_str() << std::endl;
     //list.GetFirstValue();

     //remove
     list.remove("Tree");
     cout << "After remove() is called list size is:  " << list.getLength() << endl;
     cout << "After remove(Tree) is called values in list are:  " << endl;
     list.display();

     //remove first node
     cout << "Remove First Node:  " << endl;
     list.RemoveFirstNode();
     cout << "Items in list after removing first node:  " << endl;
     list.display();

     //empty
     cout << "Is the list empty:  " << list.empty() << endl;

     //deleteList
     list.deleteList();
     cout << "After deleteList() is called list size is:  " << list.getLength() << endl;

    return 0;
}
Use getline to read lines from an ifstream into a string.

e.g.
--------8<--------
#include <fstream>
#include <string>
#include "LinkedList.h"
using namespace std;

int main()
{
    ifstream fin("input.txt");
    string line;
    LinkedList list;
    while (getline(fin,line)) {
        list.insertFront("Tree");
    }
    // ...
}
--------8<--------

Please note that this is going to be my last post in this thread.