CSc 109 Final Examination Friday 18 May 2001 SUGGESTED ANSWERS 1. Suppose we added the symbol ">>" to the syntax of bool expression in the Simple Language. In particular, >> would be true if the absolute value of is >= the absolute value of and are stored on the virtual stack, at StkPtr+2 and at StkPtr+1. Write the function GREATABS() which stores in a file the Simple Machine code which should be generated for the expression IF >> GOTO ONE where the code for evaluating and storing and ) on the virtual stack has already been generated. The call to GREATABS() would take the form GREATABS(out,StkPtr,PC,ONE_ADD); where "out" is of type ostream, StkPtr, PC, and ONE_ADD are integers. PC gives the current value of the program counter (the number of words of Simple Machine code generated so far), and ONE_ADD is the address corresponding to the Simple Language variable "ONE". This question is similar to question 4 on test 2. There you were asked to write the sasm code; here you are asked to write the C++ code which generates the simple machine code. Hint: You would be wise to write some functions to call. void digit(ostream &out,int d){ if(d<10) cout<255){ cerr<<"Code overflow"; exit(1); } out< and off the virtual stack } 2. (This question and question 3 are related. Design your answer to this question so that it can be used in question 3.) Write a template class PRay for "protected arrays." A protected array does not let you access entries outside the preset bounds of the array. For such a class the following code should compile, but should crash at runtime, because it accesses entries outside the bounds of the array. PRay x; //only allow x[-3], x[-2], ... x[10] for(int j=5; j<9;j++) x[j]=j*j+0.01; for(int j=7; j<12; j++) cout< #include #include template class PRay{ public: PRay(); PRay(const PRay & p); T & operator[] (int n); protected: T ray[hi-lo+1]; static void check(bool ok,char *mess); }; template PRay::PRay(){ } template PRay::PRay(const PRay & p){ for(int j=0;j T & PRay::operator[](int n){ check(n>=lo && n<=hi,"([]) Range error"); return ray[n-lo]; } template void PRay::check(bool ok,char *mess){ if(!ok){ cerr<<"ERROR: "< x; //only allow x[3], x[4], ... x[10] for(int j=3; j<9;j++) x[j]=abs(30-j*j); x.setN(6); x.sort(); cout<<"I sort "< class OPRa: public PRay{ public: OPRa(); OPRa(const OPRa & op); void sort(); int getN(); void setN(int j); private: int n; }; template OPRa::OPRa(){ n=0; } template OPRa::OPRa(const OPRa & op): PRay(){ n=0; } template void OPRa::sort(){ bool done; int loc; do{ done=true; for(int j=0; jray[j+1]){ T temp=ray[j]; ray[j]=ray[j+1]; ray[j+1]=temp; done=false; } }while(!done); } template void OPRa::setN(int j){ check(j>=0 && j<=hi-lo+1,"(setN() Bad value of n"); n=j; } template int OPRa::getN(){ return n; } 4. Below, for two different tables, I ask you to depict, step-by-step, the probes made when an item is put in a hash table using a quadratic probe. Both tables have the same three entries in the same three places, but the first table has room for 8 entries, and the second has room for 11 entries. Suppose we probe until a place is found. State which of the two tables below is inappropriate for using a quadratic probe and state why it is inappropriate. The table with 8 entries is innapropriate, because the quadratic probe is only guaranteed to be effective when the size of the table is prime. When the size is prime, then the quadratic probe will search at least half the table before probing the same location twice. Assume the word "Tom" produces the hash number 91. For each table below list, in order, the first 10 locations probed when trying to find a place to store "Tom", using a quadratic probe. If it takes fewer than 10 probes, list the complete sequence. Table 1 Table 2 ------- ------- 0 0 1 1 4 2 3 "COLD" 3 "COLD" 4 "HOT" 4 "HOT" 5 5 6 6 7 "Hal" 7 "Hal" 8 9 10 In Table 1. 91%8 == 3. Thus we probe 3, 3+1=4, 4+3=7, 7+5=12%8=4, 4+7=11%8=3, 3+9=12%8=4, 4+11=15%8=7, 7+13=20%8=4, 4+15%8=3, 3+17=20%8=4. Gee, this may never quit. I tried 10 times.... In Table 2. 91%11=3. Thus we probe 3, 3+1=4, 4+3=7, 7+5=12%11=1 a free space. Store "Tom" in location 1. 5. Write a program that simulates recursion for the following algorithm for finding the nth fibonacci number: int fib(int n){ if(n<=1) return 1; else return fib(n-1)+fib(n-2); I provide the main program; you provide the rest. int main(){ int n; cout<<"Enter n, and I find fibonacci(n)- "; cin>>n; cout< #include "stack.h" #include "fibstack.h" const int START=0, PUSH=1, POP=2, EXEC=3, QUIT=4; class Frame{ public: int n, left, right, result, PC; }; int fib(int n); void pop(FibStack & st, int &state); void start(FibStack & st,int &state, int n); void exec(FibStack &st, int &state); void push(FibStack &st, int &state); int fib(int n){ FibStack st; int state; state=START; while(state!=QUIT) switch(state){ case START: start(st,state,n); break; case EXEC: exec(st,state); break; case PUSH: push(st,state); break; case POP: pop(st,state); break; } return st.discarded().result; } void pop(FibStack & st, int &state){ st.pop(); if(st.empty()) state=QUIT; else state=EXEC; } void start(FibStack & st,int &state, int n){ Frame f; f.n=n; f.PC=0; st.push(f); state=EXEC; } void exec(FibStack &st, int &state){ switch(st.peek().PC){ case 0: if(st.peek().n<=0){ st.peek().result=1; state=POP; } else state=PUSH; break; case 1: st.peek().left=st.discarded().result; state=PUSH; break; case 2: st.peek().right=st.discarded().result; st.peek().result=st.peek().left+st.peek().right; state=POP; } } void push(FibStack&st,int &state){ Frame f,peek; peek=st.peek(); switch(peek.PC){ case 0: f.n=peek.n-1; f.PC=0; st.peek().PC=1; break; case 1: f.n=peek.n-2; f.PC=0; st.peek().PC=2; break; default: cout<<"Programmer error (push 0)"; exit(2); } st.push(f); state=EXEC; } #ifndef STACK_H #define STACK_H #include template class Stack{ public: Stack(const Stack & st); Stack(); T & peek(); T pop(); void push(const T &t); bool empty(); bool full(); protected: T stk[stSize]; int max,ptr; static void check(bool ok,char *mess); }; template Stack::Stack(){ ptr=-1; max=stSize; } template void Stack::check(bool ok, char *mess){ if(!ok){ cerr<<"ERROR: "< Stack::Stack(const Stack &st){ check(stSize==st.max,"(Stack(Stack)) Mismatch of stack size"); ptr=st.ptr; max=stSize; for(int j=0;j<=ptr;j++) stk[j]=st.stk[j]; } template T & Stack::peek(){ check(ptr>=0,"(peek()) Empty stack"); return stk[ptr]; } template T Stack::pop(){ check(ptr>=0,"(peek()) Empty stack"); ptr--; return stk[ptr+1]; } template bool Stack::full(){ return ptr>=max-1; } template bool Stack::empty(){ return ptr<0; } template void Stack::push(const T &t){ check(ptr #include void check(bool ok,char *mess){ if(!ok){ cerr<<"ERROR: "<=2,"Too few command line arguments"); ifstream test; ofstream out; test.open(arg[2]); if(test.good()){ copyfile(test,arg[2]); test.close(); } out.open(arg[2]); out<<"SUCCESS"< #include "word.cc" class Rek{ public: Word key,entry; Rek(); Rek(const Rek &r); }; Rek::Rek(){ key=NULL; entry=NULL; } Rek::Rek(const Rek &r){ key=Word(r.key); entry=Word(r.entry); } class Dictionary{ public: Dictionary(int n=100); Dictionary(const Dictionary &d); ~Dictionary(); Word at(char *key)const; void atPut(char *key,char *entry); void remove(char *key); private: int size,count; int locate(char *key)const; static void check(bool ok, char *mess); Rek **table; }; Dictionary::Dictionary(int n){ check(n>0,"(Dictionary(int)) non-positive argument"); size=n; count=0; table=new Rek *[n]; check(table!=NULL,"(Dictionary(int)) Heap overflow"); for(int j=0;j=count) return Word(NULL); return Word(table[loc]->entry); } void Dictionary::atPut(char *key, char *entry){ int loc; loc=locate(key); if(locentry=entry; else{ table[count]=new Rek(); check(table[count]!=NULL,"(atPut()) Heap overflow"); table[count]->key=key; table[count]->entry=entry; count++; } } void Dictionary::remove(char *key){ int loc; loc=locate(key); check(loc>=0 && lockey==key)) loc++; return loc; } void Dictionary::check(bool ok, char *mess){ if(!ok){ cerr<<"ERROR[Dictionary]: "<(5)--->[A]--->[B]------------------> | +-------->[A]--->[S]-------------------------> | +-------->[B]--->[S]-------------------------> A ------->(1)--->[A]--->[B]----------------------> | +---->(2)------------------------------------> B ------->(3)--->[A]--->[S]----------------------> | +---->(4)------------------------------------> #include class Parse{ public: Parse(); void parse(); private: char ch; bool s(); bool a(); bool b(); void getch(); }; Parse::Parse(){} void Parse::parse(){ getch(); if(s() && ch=='\n') cout<<"String is acceptable\n"; else cout<<"String has an error\n"; } bool Parse::s(){ switch(ch){ case '1': case '2': return (a() && s()); case '3': case '4': return (b() && s()); case '5': getch(); return(a() && b()); default: return false; } } bool Parse::a(){ switch(ch){ case '1': getch(); return(a() && b()); case '2': getch(); return true; default: return false; } } bool Parse::b(){ switch(ch){ case '3': getch(); return(a() && s()); case '4': getch(); return true; default: return false; } } void Parse::getch(){ if(cin.good()) cin.get(ch); if(!cin.good()) ch='\n'; }