CSE 109 Final Examination Wednesday 11 May 2005 >>>>>>>>>>>>>>>>>>>>>>>>>>>SUGGESTED ANSWERS<<<<<<<<<<<<<<<<<<<<<<<<<<<< 1. Write the prototypes and declarations for the functions called in the program below, which I intend to compile with the gcc compiler using the -xc option. The program should read two integers from the text file "final.inp" and store them, the larger first, in the text file "final.out". int main() {int a,b; getdata(&a,&b); storedata(a,b); } >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #include void getdata(int *a, int *b); void storedata(int a, int b); void getdata(int *a, int *b) {FILE *in; in=fopen("final.inp","r"); if(in==NULL) {printf("Failure to open input file\n"); exit(1); } fscanf(in,"%d %d",a,b); } void storedata(int a, int b) {FILE *out; out=fopen("final.out","w"); if(out==NULL) {printf("Failure to open output file\n"); exit(2); } fprintf(out," %d %d ", a>b?a:b,a>b?b:a); } <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 2. Write a template for (the definition and code for) a class called Range that maintains the largest and smallest values it has been given, discarding the rest. It should have a constructor that takes two values of the base type to set the initial range. It should overload += to enable (the potential) addition of new values to the range, it should have methods max() and min() for access to the largest and smallest value, and it should overload << for display of the largest and smallest value, e.g., "[12, 23]". The class can assume that instances of the base type enable '<' and '>'. Here is some sample code. Range x(10,20); //constructor requires min before max, min>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #include template class Range {public: Range(const X &a, const X&b); Range(); X min()const; X max()const; Range & operator+=(const X&x); template friend ostream & operator<<(ostream & out,const Range &r); private: X small,large; static void check(bool b, char*mess); }; template Range::Range(const X&a, const X&b):small(a),large(b) {check(a Range::Range(){check(false,"No range specified");} template X Range::min()const{return small;} template X Range::max()const{return large;} template Range & Range::operator+=(const X &x) {if(xlarge) large=x; return *this; } template ostream & operator<<(ostream & out,const Range &r) {out<<"["< void Range::check(bool b,char*mess) {if(!b) {cerr<<"ERROR: "<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> char * value(int n,Rek *r[],int size) {int h,rep; char *temp; rep=1; h=n%size; while(repSSNumber!=n) {h=(h+rep)%size; rep+=2; } if(r[h]==NULL || r[h]->SSNumber!=n) return NULL; temp=new char[strlen(r[h]->name)+1]; if(temp==NULL) {cerr<<"Heap overflow\n"; exit(1); } strcpy(temp,r[h]->name); return temp; } <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 4. My implementation of mcall depends upon a number of files that have the following relationships. parse.h has the declaration of class Parser, which has a data member of type Lex. parse.cc has the code for class Parser and uses the constants in emulate.h. fullparse.h has the declaration for the class FullParser, which is a subclass of class Parser fullparse.cc has the code for class FullParser lex.h has the declaration of class Lex. Class Lex has a data member that is of type Table lex.cc has the coder for class Lex. table.h has templates for class Table<>. word.h has the declaration of the class Word word.cc has the code for class Word mcall.cc contains the main program, which has a variable of type FullParser Write the makefile for compiling the code files and linking them to create the executable file mcall. >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> OPT= -c -Werror -Wall mcall: mcall.o parse.o fullparse.o word.o lex.o g++ -o mcall mcall.o parse.o fullparse.o word.o lex.o mcall.o: mcall.cc parse.h fullparse.h word.h lex.h table.h emulate.h g++ $(OPT) mcall.cc lex.o: lex.cc table.h word.h lex.h g++ $(OPT) lex.cc word.o: word.h word.cc g++ $(OPT) word.cc parse.o: parse.cc parse.h lex.h word.h table.h emulate.h g++ $(OPT) parse.cc fullparse.o: fullparse.cc fullparse.h parse.h lex.h word.h table.h emulate.h g++ $(OPT) fullparse.cc clean: rm -f *.o *~ mcall <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 5. Assume that in developing the class Word from lecture, I have progressed to the point of having the declaration below. Continue the development by slightly modifying class Word and by writing the declaration and definition (code) of a subclass of Word, Wordy, that simply implements []. The behavior of instances of Wordy is indicated by the code below the declaration. class Word {public: Word(char *x=""); friend ostream & operator<<(ostream &out,const Word & t); private: static void check(bool b, char *mess); char *str; }; Wordy x("One"); cout<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> NOTE: IN CLASS WORD CHANGE private TO PROTECTED class Wordy: public Word {public: Wordy(char *x=""); char & operator[](int n); char operator[](int n)const; }; Wordy::Wordy(char *x):Word(x){} char & Wordy::operator[](int n) {check(n>=0 && n=0 && n9 goto 100 write 100 100 halt end >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1080000 read x [1] 4000806 load x-9 into 0 [2] 8040405 skip if >0 [3] 2070000 write 100 [4] 0 halt [5] 9 const 9 [6] 100 const 100 [7] E x appears in [8] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 7. Someone complained that the syntax diagrams for expressions were too complicated, so I simplified them below. For this question, to greatly simplfy the lexical analysis, assume that identifiers are single lower case letters, that numbers are single digits, and no spaces are allowed. First, state how the new diagrams would change the syntax, and state how the new diagrams would change the code generation (which might appear on next year's final). Then, write a program that determines whether a line of text entered at the keyboard obeys the syntax for Expression, either diagnosing the first error or writing "Good syntax." Note: Parentheses indicate circles, while square brackets indicate boxes. The symbols are +, -, *, /, {, and } Expression ------------>[Factor]-------------------------------------+ ^ +--(+)<-----| | |--(-)<-----| +-[Factor]<--|--(*)<-----| +--(/)<-----+ Factor --------------->({)--[Expression]--(})---+ |--->[Digit]-------------------| +--->[Letter]-----------------------> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Aside from changing the definition of Number and Identifier, the new diagrams will accept and reject exactly the same strings as the old diagrams. However, with the new diagrams, when the code is generated, all operators will have the same precedence, rather than * and / having precedence over + and -. #include void expression(char &ch); void factor(char &ch); void check(bool b, char *mess); void getch(char &ch); int main() {char ch; getch(ch); expression(ch); check(ch=='\n',"End of line expected"); cout<<"Good syntax\n"; } void expression(char &ch) {factor(ch); while(ch=='+' || ch=='-' || ch=='*' || ch=='/') {getch(ch); factor(ch); } } void factor(char &ch) {if(ch>='0' && ch<='9' || ch>='a' && ch<='z') getch(ch); else {check(ch=='('," digit, letter or '(' expected"); getch(ch); expression(ch); check(ch==')'," ')' expected"); getch(ch); } } void check(bool b,char *mess) {if(!b) {cerr<<"<---ERROR: "< class A {public: A(){} char one(char ch) {return ch>='a' && ch<='z'? two(ch): (ch>='A' && ch<='Z'?three(ch):ch);} char two(char ch){return ch-1;} virtual char three(char ch){return ch-2;} }; class B:public A {public: B(){} char two(char ch){return ch+3;} char three(char ch){return ch+1;} }; int main() {char ch,*final="Gbwf b Fppe Ubdbujpo"; B b; int loc; loc=0; while(final[loc]!='\0') {cout<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>