Project 0: Program Trace Verifier

Due Friday, 8/24/2018, 11:59:59PM

Before you start this project, you should have read the project submission guidelines, how to test with the command-line shell, and the coding style rules.

After that, get started on the project immediately! Here is the upload site. Make sure that you can log in to the upload site.

Project description

The goals of this project are to:

When a compiled C++ program executes, it usually starts in the function called main. From there, it can call another function, say read_input, which in turn might call another function, such as istream::operator>>, etc. Each called function takes the next slot (or `frame') on the program's call stack. The currently-executing function is on the top of that stack. The executing program also returns from each called function, in the reverse order from the call order. So continuing our example, it must first return from istream::operator>>, then return from read_input, then return from main. Conversely, it could not return from read_input before it had returned from the inner call to istream::operator>>.

There are many program analysis tools that allow programmers to examine the behavior of executing programs. You're probably familiar with debuggers, which allow a programmer to pause an executing program, examine variables, etc. The program Valgrind (pronounced "val-grinned") examines executing programs for various problems like memory leaks. Many such tools can operate on or produce program traces, which describe things like the order of function calls and returns. We expect traces to be valid, in that every function call has an appropriately matched return from that function.

Here are examples of valid and invalid program traces. We'll assume that we are starting in the (unnamed) outermost function (e.g. main).

Trace 1 (valid) Trace 2 (invalid) Trace 3 (invalid) Trace 4 (invalid)
call read_input
call istream::operator>>
return istream::operator>>
call istream::operator>>
return istream::operator>>
return read_input
call solve
call log
return log
call abs
return abs
call ostream::operator<<
return ostream::operator<<
return solve
call read_input
call istream::operator>>
return istream::operator>>
call istream::operator>>
return read_input
call solve
call log
return log
call abs
return abs
call ostream::operator<<
return ostream::operator<<
return solve
call read_input
call istream::operator>>
return istream::operator>>
call istream::operator>>
return istream::operator>>
return read_input
call log
return log
call abs
return abs
call ostream::operator<<
return ostream::operator<<
return solve
call read_input
call istream::operator>>
return istream::operator>>
call istream::operator>>
return istream::operator>>
return read_input
call solve
call log
return log
call abs
return abs
call ostream::operator<<
return ostream::operator<<

Trace 1 is valid, because every function call return in the correct order. Traces 2-4 are invalid, because:

Your task for this project is to determine the validity of program traces. You'll be given a trace of an executing program, and you should determine whether the trace is valid or not. If it's not valid, your program should describe why.

Use an STL stack to keep track of called functions. Here is a good algorithm for validating program traces:

You might want to refer to the STL documentation on the stack and string data types.

Input format

Your program should read from standard input (i.e. cin). It should write to standard output (i.e. cout). This is the way we construct ALL of our projects, unless otherwise indicated.

Each input consists of one trace, containing between 0 and 10,000 lines. Input ends at end-of-file. Each line starts with either the word call or return, followed by a single space, followed by a function name. The function name contains 1 to 30 characters, consisting only of letters (a-z), digits (0-9) and some punctuation (underscore, period, colon, less than, and greater than). If the line starts with call, that indicates a called function; while return indicates a function that is returning.

Program output

If the program call trace is valid, output two things: "Valid trace" and "Maximum call depth was DEPTH", where DEPTH is the maximum size of the call stack at any time during the program's execution. If the program call trace is not valid, then stop processing it as soon as the first error is encountered. Print out "Invalid trace at line LINENUMBER", where LINENUMBER is the line of input (starting at 1) where the error is earliest detected. After this, specify the type of error (filling in appropriate names for FUNCTION1 and FUNCTION2):

After this, print "Stack trace" and then the names of the functions on the call stack (from top of the stack to bottom) when the error occurred, one line per name.

Use the sample executables to see real examples of how the output should be formatted.

Provided code

You should use the .cpp file provided here, modify it appropriately, and upload your solution. You may modify anything you like, but it has a basic structure you can follow.

Sample executables

Here are sample executables for you which correctly solve this problem. When you design test cases, you can judge your output against the output from the correct solution. Here is a correct solution in various compiled formats:

For each of these, you need to run them from the command-line (i.e. DOS or bash or Terminal.app). You can't just download them and double-click them to run. Also, for the linux and OSX binaries, after you've downloaded them you need to make sure that they are executable. To do this, from the command line type chmod +x file, where file is the name of the program you downloaded.

If you give a command-line argument to these executables, they will print extra information about how it is processing the input. For example, this will execute the program like normal, redirecting input from a file called my_input.txt:

% project0_solution_dos.exe < my_input.txt

But here is the mode of operation that will cause the program to print out what it is doing in more detail:

% project0_solution_dos.exe printMore < my_input.txt
The command-line argument doesn't have to be the word "printMore", it can be anything.

Sample input files

Use these sample input files to compare the output of your solution to the correct output. You can get the correct output by running the input through one of the sample executables. You should download these input files to your computer (in other words, don't copy and paste), and use file redirection to redirect the inputs into the sample executable and into your program. You should also use file redirection to capture the outputs from these programs. Don't use copy/paste, and don't type things directly into your program. Please read this for a more complete description of how to test your program, and how to use file redirection..

Please note that you may see the wrong thing if you view these input files in your web browser — it may interpret the text as HTML, when it should show you plain text. Instead, you should download them directly to your computer (e.g. right-click on each link and select the appropriate download option). In general, you should AVOID copy-and-pasting input and output in this class.

These are not the only inputs your program must solve; they are merely examples. The upload site will have more tests, to which you do not have access. Therefore, making your own tests is essential.

Final notes

Remember when writing this program to adhere to the coding style guidelines. This is an individual project, so you must work alone. No credit will be given for a solution which does not pass the online judging system. For more detailed instructions, read the project submission guidelines.


Copyright © 2018 Greg Hamerly.
Computer Science Department
Baylor University

valid html and css