0

Write a program that will correct a C++ program that has errors in which operator, << or >>, it uses with cin and cout. The program replaces each (incorrect) occurrence of

cin << with the corrected version cin >>

and each (incorrect) occurrence of cout >> with the corrected version cout <<

Allow for the possibility that there may be any number of whitespace characters (one or more) between cin and << and between cout and >>. The replacement corrected version has only one blank between the cin or cout and the following operator.

Your program should get the source filename as an input from the user. The corrected version should be output to a file with name corrected.txt and it should also be displayed on the terminal. That means output of your program (after getting the filename) should be exactly same as the contents of the file corrected.txt. Your program should define a function that is called with the input- and output-file streams as arguments.

There are no compile errors for the code. However, the code output's nothing (The file exists). Also the words in the file will disappear after I compile the program. Can anyone give me some advice? Thanks!

#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <cctype>
#include <fstream>
#include <string>
using namespace std;

void print(ifstream& input,ofstream& output, char next)
{

    input.get(next);
    cout << next;
    output.put(next);

    while(input >> next)
    {
        if(next=='c')
        {
            output.put(next);
            cout << next;
            input.get(next);

            if(next=='i')
            {   output.put(next);
                cout << next;
                input.get(next);


                if(next=='n')
                {
                    output.put(next);
                    cout << next;
                    while(next==' ')
                    {
                        input.get(next);
                    }
                    output.put(' ');
                    if(next=='<')
                    {

                        input.get(next);

                        if(next == '<')

                        {
                            cout << ">>";
                            input.get(next);

                        }
                        else
                        {
                            output.put(next);
                            cout << next;
                        }
                    }
                    else
                    {
                        output.put(next);
                        cout << next;
                    }
                }

                else
                {
                    output.put(next);
                    cout << next;
                }
            }

            else if (next=='o')
            {
                output.put(next);
                cout << next;
                input.get(next);

                if(next=='u')
                {
                    output.put(next);
                    cout << next;
                    input.get(next);


                    if(next=='t')
                    {
                        output.put(next);
                        cout << next;
                        while(next==' ')
                        {
                            input.get(next);
                        }
                        output.put(' ');
                        if(next=='>')
                        {

                            input.get(next);

                            if(next == '>')

                            {
                                cout << "<<";
                                input.get(next);

                            }
                            else
                            {
                                output.put(next);
                                cout << next;
                            }

                        }
                        else
                        {
                            output.put(next);
                            cout << next;
                        }

                    }
                    else
                    {
                        output.put(next);
                        cout << next;
                    }
                }

                else
                {
                    output.put(next);
                    cout << next;
                }
                input.get(next);
            }

        }

    }
}

int main()
{
    ifstream input;
    ofstream output;
    char next;
    char filename[16];
    cout << "Enter filename:" << endl;
    cin >> filename;
    input.open(filename);
    if(input.fail()) {
        cout << "Could not open the file " << endl;
        exit(0);
    }
    output.open("original.txt");

    if (output.fail()) {
        cout << "Could not open the file " << filename << endl;
        exit(1);
    }
    print(input, output, next);

    input.close();
    output.close();

    return 0;
}
pansoh
  • 47
  • 2
  • 7
  • 5
    Cool assignment and good job for doing it. What do you see when debugging it? And maybe then you could remove all these and post just a [MCVE]? – Khalil Khalaf Jul 20 '16 at 18:01
  • 2
    Welcome to Stack Overflow! It sounds like you may need to learn how to use a debugger to step through your code. With a good debugger, you can execute your program line by line and see where it is deviating from what you expect. This is an essential tool if you are going to do any programming. Further reading: **[How to debug small programs](http://ericlippert.com/2014/03/05/how-to-debug-small-programs/)** – NathanOliver Jul 20 '16 at 18:02
  • What have you done so far to try debugging this? Have you stepped through it in a debugger? What test cases have you run it on? We can help you out best if you let us know what you've tried; otherwise it looks like you're trying to get us to do your homework for you. – templatetypedef Jul 20 '16 at 18:02
  • 4
    If the first character in your `input` stream isn't `'c'`, the entire while loop *spins*. You never read another character from input, so `next` always stays the same (i.e. not `'c'`), and `input` never reaches eof. You also will never write a single thing to your stream. I would suggest you consider what to do in the `else` case that currently doesn't exist for the most-outer `if` block. – WhozCraig Jul 20 '16 at 18:23
  • @WhozCraig: Although my file begins with 'c', it still output nothing. – pansoh Jul 20 '16 at 18:37
  • @FirstStep: I cannot find any errors when debugging it, I try to separate the code to look at it by small parts, it seems to make sense. – pansoh Jul 20 '16 at 18:41
  • @pansoh not gonna sit and argue. First, I don't believe it unless I see it, and since you never posted the sample program content you're trying to parse *in your question* that's that. Secondly, what I wrote still stands. If you *ever* get to the outer-most if-block if that while-loop, the current character is *not* a `'c'`, *and* you've not at `input.eof()`, this program *will* spin infinitely. If you can't see that in your program, you need to look at it again. – WhozCraig Jul 20 '16 at 18:41
  • Simply, **step throuh each word** in `std::istream` using `operator>>`, save it to `std::string`, if it's `cin` check if it's followed by `<<` if yes change it to `<<`. Same with `cout` – PcAF Jul 20 '16 at 18:49
  • 1
    Each word? Nah. Use `std::getline` to read everything between ';'s into a `std::string`. Search the `string` for "cin " or cout" and search and replace for "<<", ">>" or "<<", ">>" respectively if found. Write string to corrected file. Close all files. Replace original file with corrected file. This will trap deviant cases like `cout << "A" >> "B";` – user4581301 Jul 20 '16 at 19:47
  • @user4581301: Sorry! I am not very understand what you mean. You mean I need to put std::getline in the void function to read ";"s? – pansoh Jul 20 '16 at 23:19
  • `std::getline(input, command, ';');` will read everything up to the next ';' from the file and store it in string `command`. You can't trust words because they don't have enough context and a line also may not contain all the context you need or may contain too much. Fortunately `;` can be used to delimit the code most of the time. About the only fail case I can think of is someone has nested templates inside the same token as a `cin` or `cout`. A pretty rare case. – user4581301 Jul 20 '16 at 23:33
  • On second thought, `std::string fail = "cout >> hah ha ha you lose!";` will trip my code up. To build this and be sure you practically have to write a compiler. A fairly complete state machine at the very least. – user4581301 Jul 20 '16 at 23:39
  • @user4581301: After I put in the void function, it creates some errors. – pansoh Jul 20 '16 at 23:44
  • @WhozCraig: I use " input >> next" instead of "input.eof() ". – pansoh Jul 20 '16 at 23:50

1 Answers1

3

I can't explain this in a comment. Please don't judge this too harshly:

void print(ifstream& input,ofstream& output)
{
    bool first = true;
    std::string command;
    while(std::getline(input, command, ';'))
    { // loop until no more input to read or input fails to be read
        if (command.find("cin")!= std::string::npos)
        { // found cin somewhere in command. This is too crude to work. See below
            size_t pos = command.find("<<"); // look for the first <<
            while (pos != std::string::npos)
            { // keep replacing and looking until end of string
                command.replace(pos, 2, ">>"); // replace with >>
                pos = command.find("<<", pos); // look for another 
            }
        }
        else if (command.find("cout")!= std::string::npos)
        { // same as above, but other way around
            size_t pos = command.find(">>"); 
            while (pos != std::string::npos)
            {
                command.replace(pos, 2, "<<");
                pos = command.find(">>", pos);
            }
        }
        if (! first)
        {
            output << ';' << command; // write string to output
        }
        else
        {
            first = false;
            output << command; // write string to output
        }
    }
}

This will catch and correctly handle MOST cases. What it can't deal with is:

Stuff like

cout << Cincinnati; // find is just too dumb. Regex is not
           ^ finds a cin right here and starts reversing <<

Comments

/* cout >> hah ha ha Sucker!!!; */

String literals

std::string fail = "cout >> Got you again!!!";

[expletive deleted] macros

#define evil cout >\
> "Gotcha!!!";

And really odd stuff like

cout << vector<vector<int>>(42)[0];
                         ^ Muhuhahahahahaha!!!

To do this right, you need a non-trivial state machine that can detect and eliminate the above failure cases.

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • This way can transfer the word in input file to output file but it outputs nothing during compiling. The expect result is "#include " and "using namespace std;" This is the link for the submit result: https://submit.cs.ucsb.edu/submission/202937. May be you can have a look. – pansoh Jul 21 '16 at 01:10
  • This doesn't correctly write the semicolons (it prints one in the first iteration but not thereafter), as pointed out by @Deegeeek in [this question](http://stackoverflow.com/questions/40414721/i-o-stream-string-manipulation-correct-cin-cout-operators). The two lines starting with "output <<" should be swapped. – nomadictype Nov 04 '16 at 07:57
  • @nomadictype Thank you. Corrected. – user4581301 Nov 04 '16 at 15:30