CS253 HW3: Time to get classy!                
Changes                
Previous versions erroneously showed the filename or class as
“Word”, singular. That’s wrong—it should be “Words”, plural:
class Words
, Words.h
, Words.cc
.
                
A compile-time error is also acceptable if the value of .size()
or .empty()
is ignored.
                
Description                
Contrary to the predictions of nearly everybody, management is pleased
with your previous work, and want you to write a standalone class called
Words
, a simple lexical analyzer. Specifically, you will provide
Words.h
, which will contain the interface of that class, and the
library libhw3.a
, which will contain the implementation of that
class.
                
Input Format                
The definitions of words, whitespace, backslash, and parens, are the
same as HW2, except that the input may contain multiple lines.
                
Methods                
One method is forbidden:                
- no default ctor
-
The default (no-argument) ctor for
Words
must fail to compile.
This is not a run-time error; it’s a compile-time error.
Words
must have the following public methods:                
-
Words(string input)
-
Perform lexical analysis on the multi-line
input
,
as if .analyze()
were called.
- Copy constructor
-
Copy all information from another object of the same class.
- Assignment operator
-
Copy all information from another object of the same class,
replacing any previous information.
- Destructor
-
Destroy.
-
.analyze(string input)
-
Perform lexical analysis on the given multi-line
input
.
Calling this method more than once
will start from scratch, and ignore any previous input.
-
.size()
-
Return a
size_t
representing the numer of words detected by the
lexical analysis. For example,
Words(" a +=#hi\nb ").size()
would
return a size_t
with the value 3.
Ignoring the result of .size()
must generate a compile-time warning
or a compile-time error.
-
.empty()
-
Return true iff there are no words in this
object.
Ignoring the result of this method must generate a compile-time warning
or a compile-time error.
-
.get(size_t n, string &, bool &)
-
The first argument n is an index into the words, where
0
represents the first word. If n is out of range, return false
to indicate failure. Otherwise, set the string argument to the
corresponding word, set the bool argument to true if that word was
escaped in the input, and false if not, and return true to
indicate success. By “escaped”, I mean if any character of that word
was escaped by a backslash.
The types and names in the method descriptions, above, do not
determine the C++ declarations of those methods. They only serve to
informally describe what sort of arguments a method might take.
For example, I expect that you will give a name to all the arguments of
.get()
. You might pass certain arguments by reference, use const,
declare return types, etc.
                
Non-methods:                
-
ostream << Words
-
Write the words in this object to the ostream, separated by commas.
cout << Words("foo)")
must emit exactly the five characters
foo,)
and nothing else.
Const-correctness, for arguments, methods, and operators, is your job.
For example, it must be possible to call .size()
on a
const Words
, or to copy a const Words
to a non-const Words
.
                
You may define other methods or data, public or private, as you see fit.
You may define other classes, as you see fit. However, to use the
Words
class, the user need only #include "Words.h"
, not any
other header files.
                
Non-Requirements                
Several things are not specified by this assignment.
That means that the answer to these questions is “It’s up to you.”
- What is the return type of
.analyze()
?
- What does
.get()
put in the string argument, if anything,
when it returns false?
- Should I have one
.cc
file, or several?
Debugging                
If you encounter “STACK FRAME LINK OVERFLOW”, then try this:
export STACK_FRAME_LINK_OVERRIDE=ffff-ad921d60486366258809553a3db49a4a
Libraries                
libhw3.a
is a library file. It contains a number of *.o
(object) files. It must contain Words.o
, but it may also contain
whatever other *.o
files you need. The CMakeLists.txt
shown
creates libhw3.a
. It does not contain main().
                
Testing                
You will have to write a main() function to test your code. Put it
in a separate file, and do not make it part of libhw3.a
.
Particularly, do not put main() in Words.h
or
Words.cc
. You will also have to create Words.h
, and put it into
hw3.tar
. We will test your program by doing something like
this:
                
mkdir a-new-directory
cd the-new-directory
tar -x </some/where/else/hw3.tar
cmake . && make
cp /some/other/place/test-program.cc .
g++ -Wall test-program.cc libhw3.a
./a.out
We will supply a main program to do the testing that we want.
You should do something similar. It’s your choice whether to
include your test program in your hw3.tar
file.
However, cmake . && make
must work. If it fails
because you didn’t package test.cc
, but your CMakeLists.txt
requires test.cc
, then your build failed, and you get no points.
Test your tar file, not just your code.
                
Sample Run                
Here is a sample run, where %
is my shell prompt:
                
% cat CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(hw3)
# Are we in the wrong directory?
if(CMAKE_SOURCE_DIR MATCHES "[Hh][Ww]([0-9])$")
if(PROJECT_NAME MATCHES "[^${CMAKE_MATCH_1}]$")
message(FATAL_ERROR "Building ${PROJECT_NAME} in ${CMAKE_SOURCE_DIR}")
endif()
endif()
# Using -Wall is required:
add_compile_options(-Wall)
# These compile flags are highly recommended, but not required:
add_compile_options(-Wextra -Wpedantic)
# Optional super-strict mode:
add_compile_options(-fmessage-length=80 -fno-diagnostics-show-option
-fstack-protector-all -g -O3 -std=c++17 -Walloc-zero -Walloca
-Wctor-dtor-privacy -Wduplicated-cond -Wduplicated-branches
-Werror -Wextra-semi -Wfatal-errors -Winit-self -Wlogical-op
-Wold-style-cast -Wshadow -Wunused-const-variable=1
-Wzero-as-null-pointer-constant)
# add_compile_options must be BEFORE add_executable.
# Create the executable from the source file main.cc:
add_library(${PROJECT_NAME} Words.cc)
add_executable(test test.cc)
target_link_libraries(test ${PROJECT_NAME})
# Create a tar file every time:
add_custom_target(${PROJECT_NAME}.tar ALL COMMAND
tar -cf ${PROJECT_NAME}.tar *.cc *.h CMakeLists.txt)
% cmake . && make
… cmake output appears here …
… make output appears here …
% cat test.cc
#include "Words.h"
#include "Words.h" // I meant to do that.
#include <iostream>
#include <cassert>
using namespace std;
int main() {
string w;
bool b;
const auto prog = R"(
n = \a +\=(b+6422527) # 😈
)";
Words words(prog);
cout << "There are " << words.size() << " words.\n";
for (size_t i=0; i<words.size(); i++) {
words.get(i, w, b);
cout << i << ": “" << w << "”";
if (b)
cout << " (escaped)";
cout << '\n';
}
cout << words << '\n';
words.analyze(")\tQ\n≠\rFNORD\f\v ");
assert(words.size() == 4);
const auto w2(words);
assert(w2.get(3, w, b) && w == "FNORD" && !b);
assert(!w2.get(999, w, b));
cout << w2 << "\nDone.\n";
return 0;
}
% ./test
There are 9 words.
0: “n”
1: “=”
2: “a” (escaped)
3: “+=” (escaped)
4: “(”
5: “b+6422527”
6: “)”
7: “#”
8: “😈”
n,=,a,+=,(,b+6422527,),#,😈
),Q,≠,FNORD
Done.
Requirements                
- No
Words
method should call exit(), or produce any output.
- You may use the
CMakeLists.txt
shown, or create your own.
- Do not put
using namespace std;
in any header file.
- All copies (copy ctor, assignment operator) are “deep”.
Do not share data between copies—that’s not making a copy.
- You may not use any external programs. You many not use
system(), fork(), popen(), execl(), execvp(), etc.
- You may not use C-style I/O,
such as printf(), scanf(), fopen(), and getchar().
- You may not use dynamic memory via new, delete,
malloc(), calloc(), realloc(), free(), strdup(), etc.
- It’s ok to implicitly use dynamic memory via containers
such as string or vector.
- You may not use the istream::eof() method.
- No global variables.
- For readability, don’t use ASCII int constants (
65
) instead of
char constants ('A'
) for printable characters.
- We will compile your code like this:
cmake . && make
- If that generates warnings, you will lose a point.
- If that generates errors, you will lose all points.
- There is no automated testing/pre-grading/re-grading.
- Test your code yourself. It’s your job.
- Even if you only change it a little bit.
- Even if all you do is add a comment.
- Test with the CSU compilers, not just your laptop’s compiler.
If you have any questions about the requirements, ask.
In the real world, your programming tasks will almost always be
vague and incompletely specified. Same here.
                
Tar file                
- The tar file for this assignment must be called:
hw3.tar
- It must contain:
- source files (
*.cc
), including Words.cc
- header files (
*.h
), including Words.h
CMakeLists.txt
, which will create the library file
libhw3.a
.
- These commands must produce the library lib
hw3.a
:
cmake . && make
- Your
CMakeLists.txt
must use at least -Wall
when compiling.
How to submit your work:                
In Canvas, check in the
file
hw3.tar
to the assignment “HW3”.
It’s due 10:00:00ᴘᴍ MT Saturday, with a 24-hour late period for a 25% penalty.
                
How to receive negative points:                
Turn in someone else’s work.