CS253 HW5: Jail!
Justice is served
Changes
Updates to the assignment will be noted here. None yet!
                
Description
For this assignment, you will build on your HW3 work, and write a
standalone class called Jail
, which will represent a program in a
small language, JAIL (Just An Interpreted Language).
Specifically, you will provide Jail.h
, which will contain the
interface of that class, and the library libhw5.a
, which will
contain the implementation of that class.
The case-independent tokens of JAIL are exactly those of HW3.
Comments & whitespace are treated the same as in HW3.
                
Semantics
- JAIL has 26 long variables,
a
…z
.
- The valid JAIL statements:
- variable
=
value -
Assign the value to the variable.
- variable
+=
value -
- variable
-=
value -
- variable
*=
value -
- variable
/=
value -
Add/subtract/multiply/divide the variable by the value.
-
if
value =
value optional-statements fi
-
-
if
value ≠
value optional-statements fi
-
-
if
value <
value optional-statements fi
-
-
if
value >
value optional-statements fi
-
-
if
value ≤
value optional-statements fi
-
-
if
value ≥
value optional-statements fi
-
If the comparison is true, do the optional statements.
-
print
value -
Display the value, followed by a newline.
-
return
value -
Terminate the JAIL program, returning the given value.
If a JAIL program ends without returning a value, its return
value is zero.
- value is defined as a variable or a number.
- optional-statements is defined as any number of statements,
zero or more, including
if
…fi
statements, nested to any depth.
- All calculations are integer calculations, using long arithmetic.
Execution
A Jail
object has two actions: construction (ctor), when
lexical analysis is performed (and lexical errors thrown)
and execution (.run()
), when the tokens are interpreted as
a program.
                
Errors
Throw a descriptive runtime_error if:
- an unrecognized token is encountered:
- a syntactically incorrect statement is encoutered
- division by zero is attempted
- an
if
is encoutered without a matching fi
- an
fi
is encoutered without a matching if
.
The word “encountered” means “ran into as part of execution”. You are
not required to diagnose all errors (though you may), just the ones
hit during execution. That means that this program must throw an
error upon trying to execute = 3
:
if 1 < 2
= 3
fi
whereas this program may or may not generate an error, since = 4
is never executed:
if 1 > 2
= 4
fi
You may throw these errors during Jail
construction, or during
Jail::run()
, whenever you happen to detect them. However, lexical
analysis must occur at Jail
construction, so unrecognized tokens
(e.g., &
) must throw an error during Jail
construction,
even if they’re never executed, and may not deferred until .run()
.
                
Of course, if an error is thrown during object construction, then the
object never exists, so what to do with such an object during .run()
is a zen sort of question.
                
Methods
One method is forbidden:
- no default ctor
-
The default (no-argument) ctor for
Jail
must fail to compile.
This is not a run-time error; it’s a compile-time error.
Jail
must have the following public methods:
-
Jail(string)
-
Perform lexical analysis on the given multi-line string.
If any bad tokens are detected, throw a runtime_error.
If other errors are detected, you may throw an error,
or defer that until
.run()
.
- 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.
-
.run(
optional-arguments)
-
Execute the program associated with this object. There may be zero to
ten long arguments to
.run()
. If they are given, they set the
initial values for the corresponding variables a
…j
. All other
variables are set to zero.
For example, foo.run(11,22,33)
sets a
to 11
, b
to
22
, and c
to 33
, and d
…z
are zero.
The return value of this method is the value given to return
in the program, or zero if no return
statement was executed.
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
Jail
class, the user need only #include "Jail.h"
, not any
other header files.
                
Hints
Sensible students will use their Lexan
from HW3. Jail
will
has-a Lexan
data member, which it will construct as part of
Jail
’s constructor.
                
Debugging
If you encounter “STACK FRAME LINK OVERFLOW”, then try this:
export STACK_FRAME_LINK_OVERRIDE=ffff-ad921d60486366258809553a3db49a4a
Libraries
libhw5.a
is a library file. It contains a number of *.o
(object) files. It must contain Jail.o
, but it may also contain
whatever other *.o
files you need. It is quite likely that it
will also contain Lexan.o
. The CMakeLists.txt
shown
creates libhw5.a
, which does not contain main().
                
Sample Run
Here is a sample run, where %
is my shell prompt:
                
% cat CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(hw5)
# 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} Jail.cc Lexan.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 test.cc {Jail,Lexan}.{cc,h} CMakeLists.txt)
% cat test.cc
#include "Jail.h"
#include "Jail.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ifstream in("ctof");
if (!in) {
cerr << "can’t open ctof for reading\n";
return 1;
}
string prog;
getline(in, prog, '\0');
try {
Jail j(prog);
// 100 is the boiling point of water
// 30 is hot
// 20 is nice
// 10 is cool
// and 0 is ice
for (int celsius : {100, 30, 20, 10, 0})
cout << celsius << "°C = " << j.run(celsius) << "°F\n";
cout << "π ≈ ";
Jail("n=999999999999999n/=31830989printn").run();
Jail bad("🐟");
}
catch (const exception &e) {
cerr << "Caught error: " << e.what() << '\n';
}
return 0;
}
% cat ctof
# Celsius to Fahrenheit converter
#
# Input: First argument, A, contains Celsius temperature
# Output: return Fahrenheit temperature
#
# °F = °C × 9/5 + 32
# 100°C = 212°F
# 30°C = 86°F
# 20°C = 68°F
# 10°C = 50°F
# 0°C = 32°F
A *= 9 A /= 5 # °C × 9/5
a+=0032 # °C × 9/5 + 32
F = A # Put it in F for Fahrenheit
Z = 0 # Constants have no sign, so compute a negative number.
Z -= 459 # absolute zero (should really be −459.67°)
if F ≤ Z # If temperature is too low:
F=Z # Make it absolute zero.
fi
return F
% cmake .
… cmake output appears here …
% make
… make output appears here …
% ./test
100°C = 212°F
30°C = 86°F
20°C = 68°F
10°C = 50°F
0°C = 32°F
π ≈ 31415926
Caught error: invalid token starting with “🐟”
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 libhw5.a
.
Particularly, do not put main() in Lexan.h
or
Lexan.cc
. You will also have to create Lexan.h
, and put it into
hw5.tar
. We will test your program by doing something like
this:
                
mkdir a-new-directory
cd the-new-directory
tar -x </some/where/else/hw5.tar
cmake . && make
cp /some/other/place/test-program.cc .
g++ -Wall test-program.cc libhw5.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 hw5.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.
                
Requirements
- No
Jail
method should call exit(), or produce any output,
except for executing print
.
- 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 via 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.
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:
hw5.tar
- It must contain:
- source files (
*.cc
), including Jail.cc
and probably
Lexan.cc
- header files (
*.h
), including Jail.h
CMakeLists.txt
, which will create the library file
libhw5.a
.
- These commands must produce the library lib
hw5.a
:
cmake . && make
- Your
CMakeLists.txt
must use at least -Wall
when compiling.
How to submit your work:
In Canvas, check in the
file
hw5.tar
to the assignment
“HW5”.
                
How to receive negative points:
Turn in someone else’s work.