CS253: Software Development with C++

Fall 2020

HW 5

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

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.

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:

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 aj. 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 dz 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

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

    cmake . && make

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.