Understanding Exception Handling and Coroutines in µC++

School
University of Waterloo**We aren't endorsed by this school
Course
CS 343
Subject
Computer Science
Date
Dec 11, 2024
Pages
8
Uploaded by KidAtomPigeon11
CS 343Fall 2024 – Assignment 1Instructor: Peter BuhrDue Date: Wednesday, September 18, 2024 at 22:00Late Date: Friday, September 20, 2024 at 22:00September 12, 2024This assignment introduces exception handling and coroutines inμC++. Use it to become familiar with these newfacilities, and ensure you use these concepts in your assignment solution. Unless otherwise specified, writing a C-style solution for questions is unacceptable and receives little or no marks. (You may freely use the code from theseexample programs.)1.(a) Transform the C++ program in Figure1replacing thethrow/catchfor exceptionsEx1,Ex2, andEx3with:i. C++ program using global status-flag variables for the alternate outcomes. The main outcome (double)is the only value returned from the routines.ii. C++ program replacing the main outcome (double) with a C++17variantas the return code, containingthe different outcomes. There are two approaches: passing the outcomes by value or pointer (usinginheritance) in thevariantreturn-type.iii. C program replacing the main outcome (double) with a taggedunionas the return code, containing thedifferent outcomes. In addition, replace the exception handling in the program main, which handlesthe command-line arguments, with multi-level exits.Output from the transformed programs must be identical to the original program. Useprintfformat “%gto print floating-point numbers in C.(b)i. Compare the original and transformed programs with respect to performance by doing the following:• Time the executions using thetimecommand:$ /usr/bin/time-f"%Uu%Ss%E"./a.out 100000000 10000 10033.21u 0.02s 0:03.32Output fromtimediffers depending on the shell, so use the systemtimecommand. Compare theusertime (3.21u) only, which is the CPU time consumed solely by the execution of user code(versus system and real time).• If necessary, change the first command-line parametertimesto adjust program execution into therange 1 to 100 seconds. (Timing results below 1 second are inaccurate.) Use the same command-line values for all experiments, if possible; otherwise, increase/decrease the arguments as neces-sary and scale the difference in the answer.• Run the experiments again after recompiling the programs with compiler optimization turned on(i.e., compiler flag-O2).• Include the 8 timing results to validate the experiments.ii. State the performance difference (larger/smaller/by how much) between the original and transformedprograms, and the reason for the difference.iii. State the performance difference (larger/smaller/by how much) between the original and transformedprograms when compiler optimization is used.(c)i. Run a similar experiment with compiler optimization turned on but vary the exception period (secondcommand-line parametereperiod) with values 500 50 25 12.• Include the 16 timing results to validate the experiments.ii. State the performance difference (larger/smaller/by how much) between the original and transformedprograms as the exception period decreases, and the reason for the difference.2.(a) Transform the C++ program in Figure2, p. 3by replacingonlythethrow/catchfor exceptionsEwithlongjmp/setjmp. No changes are allowed to the return type or parameters of routineAckermann. No dy-namic allocation is allowed, but creation of a global variable is allowed.No more calls tosetjmpare1
Background image
CS 343 - Assignment 12#include<iostream>#include<cstdlib>// access: rand, srand#include<cstring>// access: strcmpusing namespacestd;#include<unistd.h>// access: getpidstructEx1 {short intcode; };structEx2 {intcode; };structEx3 {long intcode; };intmax_t eperiod = 10000;// exception periodintrandcnt = 0;intRand() { randcnt += 1;returnrand(); }doublertn1(doublei ) {if( Rand() % eperiod == 0 ) {throw Ex1{ (short int)Rand() }; }// replacereturni + Rand();}doublertn2(doublei ) {if( Rand() % eperiod == 0 ) {throw Ex2{ Rand() };}// replacereturnrtn1( i ) + Rand();}doublertn3(doublei ) {if( Rand() % eperiod == 0 ) {throw Ex3{ Rand() };}// replacereturnrtn2( i ) + Rand();}staticintmax_t convert(const char*str ); // copy fromhttps://student.cs.uwaterloo.ca/~cs343/examples/convert.hintmain(intargc,char*argv[ ] ) {intmax_t times = 100000000, seed = getpid();// default valuesstructcmd_error {};try{switch( argc ) {case4:if( strcmp( argv[3],"d") != 0 ) {// default ?seed = convert( argv[3] );if( seed <= 0 )throwcmd_error(); }case3:if( strcmp( argv[2],"d") != 0 ) {// default ?eperiod = convert( argv[2] );if( eperiod <= 0 )throwcmd_error(); }case2:if( strcmp( argv[1],"d") != 0 ) {// default ?times = convert( argv[1] );if( times <= 0 )throwcmd_error(); }case1:break;// use all defaultsdefault:throwcmd_error();}// switch}catch( . . . ) {cerr <<"Usage:"<< argv[0] <<"[times>0|d[eperiod>0|d[seed>0|d]]]"<< endl;exit( EXIT_FAILURE );}// trysrand( seed );doublerv = 0.0;intev1 = 0, ev2 = 0, ev3 = 0;intrc = 0, ec1 = 0, ec2 = 0, ec3 = 0;for(inti = 0; i < times; i += 1 ) {try { rv += rtn3( i ); rc += 1; }// replace// analyse exceptioncatch( Ex1 ev ) { ev1 += ev.code; ec1 += 1; }// replacecatch( Ex2 ev ) { ev2 += ev.code; ec2 += 1; }// replacecatch( Ex3 ev ) { ev3 += ev.code; ec3 += 1; }// replace}// forcout <<"randcnt"<< randcnt << endl;cout <<"normalresult"<< rv <<"exceptionresults"<< ev1 <<’’<< ev2 <<’’<< ev3 << endl;cout <<"calls"<< rc <<"exceptions"<< ec1 <<’’<< ec2 <<’’<< ec3 << endl;}Figure 1: Dynamic Multi-Level Exit
Background image
CS 343 - Assignment 13#include<iostream>#include<cstdlib>// access: rand, srand#include<cstring>// access: strcmpusing namespacestd;#include<unistd.h>// access: getpid#ifdefNOOUTPUT#definePRINT( stmt )#else#definePRINT( stmt ) stmt#endif// NOOUTPUTstructE {};// exception typeintmax_t eperiod = 100, excepts = 0, calls = 0, dtors = 0, depth = 0;// countersPRINT(structT { ~T() { dtors += 1; } }; )long intAckermann(long intm,long intn,long intdepth ) {calls += 1;if( m == 0 ) {if( rand() % eperiod <= 2 ) { PRINT( T t; ) excepts += 1;throw E();}// replacereturnn + 1;}else if( n == 0 ) {try{returnAckermann( m-1, 1, depth + 1 );// replace}catch( E ){// replacePRINT( cout <<"depth"<< depth <<"E1"<< m <<""<< n <<"|");if( rand() % eperiod <= 3 ) { PRINT( T t; ) excepts += 1;throw E();}// replace}// tryPRINT( cout <<"E1X"<< m <<""<< n << endl );}else{try{returnAckermann( m-1, Ackermann( m, n-1, depth + 1 ), depth + 1 );// replace}catch( E ){// replacePRINT( cout <<"depth"<< depth <<"E2"<< m <<""<< n <<"|");if( rand() % eperiod == 0 ) { PRINT( T t; ) excepts += 1;throw E();}// replace}// tryPRINT( cout <<"E2X"<< m <<""<< n << endl );}// ifreturn0;// recover by returning 0}staticintmax_t convert(const char*str ); // copy fromhttps://student.cs.uwaterloo.ca/~cs343/examples/convert.hintmain(intargc,char*argv[ ] ) {volatileintmax_t m = 4, n = 6, seed = getpid();// default values (volatile needed for longjmp)structcmd_error {};// command-line errorstry{// process command-line argumentsswitch( argc ) {case5:if( strcmp( argv[4],"d") != 0 ) {// default ?eperiod = convert( argv[4] );if( eperiod <= 0 )throwcmd_error(); }case4:if( strcmp( argv[3],"d") != 0 ) {// default ?seed = convert( argv[3] );if( seed <= 0 )throwcmd_error(); }case3:if( strcmp( argv[2],"d") != 0 ) {// default ?n = convert( argv[2] );if( n < 0 )throwcmd_error(); }case2:if( strcmp( argv[1],"d") != 0 ) {// default ?m = convert( argv[1] );if( m < 0 )throwcmd_error(); }case1:break;// use all defaultsdefault:throwcmd_error();}// switch}catch( . . . ) {cerr <<"Usage:"<< argv[0] <<"[m(>=0)|d[n(>=0)|d""[seed(>0)|d[eperiod(>0)|d]]]]"<< endl;exit( EXIT_FAILURE );}// trysrand( seed );// seed random numbertry{// replacePRINT( cout <<"Arguments"<< m <<""<< n <<""<< seed <<""<< eperiod << endl );long intval = Ackermann( m, n, 0 );PRINT( cout <<"Ackermann"<< val << endl );}catch( E ){// replacePRINT( cout <<"E3"<< endl );}// trycout <<"calls"<< calls <<"exceptions"<< excepts <<"destructors"<< dtors << endl;}Figure 2: Throw/Catch
Background image
CS 343 - Assignment 14allowed than the number oftry. . .catch( E )statements.Note, typejmp_bufis an array allowing in-stances to be passed tosetjmp/longjmpwithout having to take the address of the argument. Output fromthe transformed program must be identical to the original program,except for one aspect, which you willdiscover in the transformed program.(b)i. Explain why the output is not the same between the original and transformed program.ii. Compare the original and transformed programs with respect to performance by doing the following:• Recompile both the programs with preprocessor option-DNOOUTPUTto suppress output.• Time the executions using thetimecommand:$ /usr/bin/time-f"%Uu%Ss%E"./a.out 12 12 103 283.21u 0.02s 0:03.32Output fromtimediffers depending on the shell, so use the systemtimecommand. Compare theusertime (3.21u) only, which is the CPU time consumed solely by the execution of user code(versus system and real time).• If necessary, change the command-line parameters to adjust program execution into the range 1to 100 seconds. (Timing results below 1 second are inaccurate.) Use the same command-linevalues for all experiments, if possible; otherwise, increase/decrease the arguments as necessaryand scale the difference in the answer.• Run the experiments again after recompiling the programs with compiler optimization turned on(i.e., compiler flag-O2).• Include the 4 timing results to validate the experiments.iii. State the performance difference (larger/smaller/by how much) between the original and transformedprograms, and the reason for the difference.iv. State the performance difference (larger/smaller/by how much) between the original and transformedprograms when compiler optimization is used.3. This question requires the use ofμC++, which means compiling the program with theu++command, which isavailable on theundergraduate computing environment.Write asemi-coroutinewith the following public interface (you may only add a public destructor and privatemembers):_CoroutineStringLiteral {charch;// character passed by cocaller// YOU ADD MEMBERS HEREvoidmain();// coroutine mainpublic:enumEncoding { C, Wide/*u*/, Integer/*U or L*/, UTF8/*u8*/};_ExceptionMatch {// last character matchpublic:Encoding prefix;// string encodingunsigned intlength;// string lengthstd::string & str;// string valueMatch( Encoding prefix,unsigned intlength, std::string&str ): prefix{prefix}, length{length}, str{str} {}};_ExceptionError {};// last character invalidvoidnext(charc ) {ch = c;// communication inputresume();// activate}};which verifies a string of characters corresponds to a C++ string-literal described by the following grammar:string-literal :encoding-prefixopt"s-char-sequenceopt"encoding-prefixopt:u8|u|U|L|ǫ(empty string)
Background image
CS 343 - Assignment 15s-char-sequenceopt:s-char|s-char-sequenceopts-char|ǫs-char :any character except double-quote ("), backslash (\), or new-line|escape-sequenceescape-sequence :simple-escape-sequence|octal-escape-sequence|hexadecimal-escape-sequencesimple-escape-sequence :\|\"|\?|\\|\a|\b|\f|\n|\r|\t|\voctal-escape-sequence :\octal-digit|\octal-digitoctal-digit|\octal-digitoctal-digitoctal-digitoctal-digit :0|1|2|3|4|5|6|7hexadecimal-escape-sequence :\xhexadecimal-sequencehexadecimal-sequence :hexadecimal-sequencehexadecimal-digit|hexadecimal-digithexadecimal-digit :0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|A|B|C|D|E|FEach hexadecimal escape sequence must be thelongestsequence of characters that can constitute the escapesequence. The following are examples of valid and invalid C++ string literals:validinvalid""""a\n""a"abc"ab""xyz\012""\\\""xyz\x000c""\9"L"www"l"www"To simplify parsing, assume avalidstring literal starts at the beginning of an input line, i.e., there is no leadingwhitespace. No checking is required for this assumption and no test data contains examples of this form. Seethe C library routineisxdigit(c), which returns true if charactercis a hexadecimal digit. An octal or hexadecimalescape sequence represents a single character. Therefore, the escape sequence must be converted from multiplecharacters to its single character value. There is a cheap and cheerful C pattern to convert octal/hexadecimaldigits from characters to its value. Marks will be deducted for expensive approaches for converting charactersto values, such asstringstream.After creation, the coroutine is resumed with a series of characters from a string (one character at a time).Eventually, the coroutine raises one of the following exceptions at its resumer:Matchmeans the characters form a valid string and the exception instance contains detailed informationabout the string.Errormeans the last character forms an invalid string.When generating the return string convert any unprintable characters (isprint(c)) into’X’, otherwise the unprint-able characters can cause problems with shell tools. After the coroutine raises an exception, at its last resumer,itmustterminate and NOT be resumed again; sending more characters to a terminated coroutine generates anerror.Write a programstringliteralthat checks if a string is a C++ string-literal. The shell interface to thestringliteralprogram is as follows:stringliteral [ infile ](Square brackets indicate optional command line parameters, and do not appear on the actual command line.)If no input file name is specified, input comes from standard input. Output is sent to standard output.Forany specified command-line file, check it exists and can be opened. You may assume I/O reading and writing
Background image
CS 343 - Assignment 16"":""yes0 0"""a\n":"a\n"yes0 2"aX""abc":"abc"yes0 3"abc""xyz\012":"xyz\012"yes0 4"xyzX""xyz\x000c":"xyz\x000c"yes0 4"xyzX"L"www": L"www"yes2 3"www""abc"xyz :"abc"yes0 3"abc" --extraneous characters"xyz"Warning! Blank line.":"no"a:"a noab":ano--extraneouscharacters"b"""\\\":"\\\"no"\9":"\9 no--extraneous characters"""l"www":lno--extraneouscharacters""www""Figure 3: String Literal Examplesdo not result in I/O errors.There is anexampleμC++ programsdemonstrating how to handling command-lineparameters.The program main should:• read a line from the input file into a string,• create aStringLiteralcoroutine,• pass characters from the input line to the coroutine one at time.• print an appropriate message when the coroutine returns exceptionMatchorError, or if there are no morecharacters to send,• check for extra characters on the line,• terminate the coroutine, and• repeat these steps for each line in the input file.For every non-empty input line, print the line, how much of the line is parsed, and the stringyesif the string isvalid andnootherwise. If valid, also print string details. Figure3shows some example output. If there are extracharacters (including whitespace) on a line after parsing, print these characters with an appropriate warning.Print the warning "Warning! Blank line." for an empty input line, i.e., a line containing only’\n’.WARNING:When writing coroutines, try to reduce or eliminate execution “state” variables and control-flow state-ments using them.A state variable contains information that is not part of the computation and exclusively usedfor control-flow purposes (like flag variables). Use of execution state variables in a coroutine usually indicates youare not using the ability of the coroutine to remember prior execution information.Little or no marks will be givenfor solutions explicitly managing “state” variables.See Section 3.1.3 in theCourse Notesfor details on this issue.Also, make sure a coroutine’s public methods are used for passing information to the coroutine, but not for doing thecoroutine’s work, which must be done in the coroutine’smain.Submission GuidelinesFollow these guidelines carefully. Review theAssignment GuidelinesandC++ Coding Guidelinesbeforestarting eachassignment.Each text or test-document file, e.g.,*.{txt,testdoc}file, must be ASCII text and not exceed 500 linesin length, using the commandfold-w120*.testdoc | wc-l.Programs should be divided into separate compilationunits, i.e.,*.{h,cc,C,cpp}files, where applicable. Use thesubmitcommand to electronically copy the following files tothe course account.1.q1returnglobal.{cc,C,cpp},q1returntype.{cc,C,cpp},q1returntypec.c– code for question1a, p. 1.No programdocumentation needs to be present in your submitted code. No test documentation is to be submitted for
Background image
CS 343 - Assignment 17this question.Output for this question is checked via a marking program, so it must match exactly withthe given program.2.q1returntype.txt– contains the information required by questions1b, p. 1and1c, p. 1.3.q2longjmp.{cc,C,cpp}– code for question2a, p. 1.No program documentation needs to be present in yoursubmitted code. No test documentation is submitted for this question.Output for this question is checkedvia a marking program, so it must match exactly with the given program.4.q2longjmp.txt– contains the information required by question2b, p. 4.5.q3*.{h,cc,C,cpp}– code for question3, p. 4. Split your code across*.hand*.{cc,C,cpp}files as needed.Programdocumentation must be present in your submitted code.6.q3*.testdoc– test documentation for question 3, which includes the input and output of your tests.Poor docu-mentation of how and/or what is tested can results in a loss of all marks allocated to testing.7. Modify the followingMakefileto compile the programs for question1, p. 1, question2a, p. 1, and question3, p. 4by inserting the object-file names matching your source-file names.OUTPUT = OUTPUTGVERSION =-12CXX = u++# uC++ compiler#CXX = /u/cs343/cfa-cc/bin/cfa# CFA compilerCXXFLAGS =-g-Wall-Wextra-MMD-Wno-implicit-fallthrough-D${OUTPUT}# compiler flagsMAKEFILE_NAME = ${firstword ${MAKEFILE_LIST}}# makefile name.SUFFIXES: .cfa# CFA default rules.cfa.o :${CXX} ${CXXFLAGS}-c $<OBJECTS01 = q1exception.o# optional build of given programEXEC01 = exception# given executable nameOBJECTS1 = q1returnglobal.o# 1st executable object filesEXEC1 = returnglobal# 1st executable nameOBJECTS2 = q1returntype.o# 2nd executable object filesEXEC2 = returntype# 2nd executable nameOBJECTS3 = q1returntypec.o# 3rd executable object filesEXEC3 = returntypec# 3rd executable nameOBJECTS02 = q2throwcatch.o# optional build of given programEXEC02 = throwcatch# given executable nameOBJECTS4 = q2longjmp.o# 4th executable object filesEXEC4 = longjmp# 4th executable nameOBJECTS5 =# object files forming 5th executable with prefix “q3”EXEC5 = stringliteral# 5th executable nameOBJECTS = ${OBJECTS1} ${OBJECTS2} ${OBJECTS3} ${OBJECTS4} ${OBJECTS5}DEPENDS = ${OBJECTS:.o=.d}EXECS = ${EXEC1} ${EXEC2} ${EXEC3} ${EXEC4} ${EXEC5}#############################################################.PHONY: all cleanall : ${EXECS}# build all executables
Background image
CS 343 - Assignment 18${EXEC01} : ${OBJECTS01}# optional build of given programg++${GVERSION} ${CXXFLAGS} $^-o $@q1%.o : q1%.cc# change compiler 1st executable, CHANGE SUFFIX FOR .C/.cppg++${GVERSION} ${CXXFLAGS}-std=c++17-c $<-o $@${EXEC1} : ${OBJECTS1}# compile and link 1st executableg++${GVERSION} ${CXXFLAGS} $^-o $@${EXEC2} : ${OBJECTS2}# compile and link 2nd executableg++${GVERSION} ${CXXFLAGS} $^-o $@q1%.o : q1%.c# change compiler 2nd executablegcc${GVERSION} ${CXXFLAGS}-c $<-o $@${EXEC02} : ${OBJECTS02}# optional build of given programg++${GVERSION} ${CXXFLAGS} $^-o $@${EXEC3} : ${OBJECTS3}# compile and link 3rd executableg++${GVERSION} ${CXXFLAGS} $^-o $@q2%.o : q2%.cc# change compiler 4th executable, CHANGE SUFFIX FOR .C/.cppg++${GVERSION} ${CXXFLAGS}-c $<-o $@${EXEC4} : ${OBJECTS4}# compile and link 4th executableg++${GVERSION} ${CXXFLAGS} $^-o $@${EXEC5} : ${OBJECTS5}# compile and link 5th executable${CXX} ${CXXFLAGS} $^-o $@#############################################################${OBJECTS} : ${MAKEFILE_NAME}# OPTIONAL : changes to this file => recompile-include${DEPENDS}# include*.d files containing program dependencesclean :# remove files that can be regeneratedrm-f*.d*.o ${EXEC01} ${EXEC02} ${EXECS}This makefile is used as follows:$ make returnglobal$ ./returnglobal . . .$ make returntype$ ./returntype . . .$ make returntypec$ ./returntypec . . .$ make longjmp$ ./longjmp . . .$ make stringliteral$ ./stringliteral . . .Put thisMakefilein the directory with the programs, name the source files as specified above, and then typemake returnglobal,make returntype,make returntypec,make longjmp, ormake stringliteralin the directory tocompile the programs. ThisMakefilemust be submitted with the assignment to build the program, so it mustbe correct. Use the web toolRequest Test Compilationto ensure you have submitted the appropriate files, yourmakefile is correct, and your code compiles in the testing environment.Follow these guidelines. Your grade depends on it!
Background image