Assignment FAQ


General questions

Q1. What is the purpose of this page?

A1. This page is a list of the most frequently asked questions received by the staff for the current homework assignment. Before sending us e-mail with a question regarding specification or implementation details of the assignment, you should check this FAQ page to see if the question has already been answered. If the question is not on the page, or if the explanation on the page is unclear, feel free to post the question to the newsgroup or e-mail cs143-aut1011-staff@lists with the question.

If you're looking for common questions about general course adminstration and procedures rather than issues concerning a specific assignment, check the policies page.

Q2. What do I do when I have a question?

A2. A couple of places to look for help:


Q3. How can I run the reference compiler?

A3. Try /usr/class/cs143/bin/coolc test.cl

Q4. How do I execute the program using SPIM?

A4. Try /usr/class/cs143/bin/spim -f test.s

Q5. How can I set up the newsgroup?

A5. Follow the directions at http://www.stanford.edu/services/usenet/. Our class newsgroup is "su.class.cs143".

Q6: I can't seem to submit the assignment. What might be going wrong?

A6. First, make sure that you put your Stanford user id (SUNetId) at the very top of your README file in the form "user: my_user_id". Second, be sure that you are using the corn university machine for submitting; other university machines might have missing dependencies and our submit script might not work on some of the other university machines. Third, the submission script does not allow you to submit the assignment more than 10 times; so try to keep your number of submissions under 10. If you really need to submit more than 10 times, please e-mail the CS143 staff list so that we can delete your old submissions. Finally, for the written assignments, your submitted assignment should not exceed 2 MB; so make sure that your file size is not excessively large. If you try all of these suggestions and the submission script still does not work, please notify the CS143 staff ASAP.
Programming Assignment 1 Questions:

Q: How can I run the reference lexer?

A. Try /usr/class/cs143/bin/lexer test.cl

Q: Do I report errors by printing on the console?

A. No, you do not report error messages by outputting to the console. In Flex, you can report errors like this: yylval.error_msg = "EOF in comment"; and in JLex, you report them like this: return new Symbol(TokenConstants.ERROR, "EOF in comment");

Q: How do I write the null character to a file for testing?

A. This depends on the editor you use. In VI, you can write the null character as "Ctrl-V Ctrl-@"; in Emacs try "C-q 000".

Q: What do you mean by nested comments? Is (* (* Hello *) a valid nested comment?

A. No, each (* should be matched by a closing *).
Written Assignment 1 Questions:

Q: In the fifth question, am I allowed to use the "?" operator?

A. Yes, you are allowed to use the "?" syntax.
Programming Assignment 2 Questions:

Q: How can I run the reference parser?

A. /usr/class/cs143/bin/lexer your-coolfile.cl | /usr/class/cs143/bin/parser

Q: The let construct described in the Cool manual allows binding multiple variables in one let expression; but the let constructor defined in the starter code allows binding only one variable. How can we handle binding multiple variables?

A. You should treat the expression "let x:T1<-e1, y:T2<-e2 in e3" the same as "let x:T1<-e1 in (let y:T2<-e2 in e3)".
Programming Assignment 3 Questions:

Q: How can I run the reference semantic analyzer?

A. /usr/class/cs143/bin/lexer your-coolfile.cl | /usr/class/cs143/bin/parser | /usr/class/cs143/bin/semant

Q: How can I run the debugger on my semantic analyzer?

A. /usr/class/cs143/bin/lexer your-coolfile.cl | /usr/class/cs143/bin/parser >temp.txt
gdb ./semant
In GDB type: run < temp.txt
Written Assignment 3 Questions:
In problem 2a: You example must never exhibit a runtime error, even if we add additional classes to your example code.

Optimizer Questions (Extra Credit Assignment)

Q: When should I do the optimizer?

A. You should, under no circumstances, start on the optimizer before you finish your code generator.

Q: I plan to do the extra credit assignment. Is it a good idea to convert the AST to a low-level intermediate representation that I can take advantage of in both the code generator and the optimizer?

A. No, that would not be a good idea. We recommend that you completely finish your code generator before you do invest any time and effort into the extra credit assignment.

Q: Coud you give us some specific suggestions about what kinds of optimizations might have a large impact on Cool programs?

A. The most important improvement you can make in Cool code is to unbox integers. No other optimization will make much difference unless you improve the integer representation first. "Unboxing" a value means storing it as a raw value rather than an object. Integers in Cool are boxed by default---they live inside of a "box" (the object) and can only be gotten out by dereferencing a pointer. An unboxed integer, in contrast, is an integer held in a register or stored directly on the stack (not as part of an object). There are two complications in unboxing integers. First, you will now have different kinds of representations that the generated code must deal with; you have to know when something is an integer and when it is an object. Second, the garbage collector will have the same problem---you can't have integers that look like pointers anywhere that the garbage collector might stumble across them. In particular, you can't just store unboxed integers in the stack without somehow telling the garbage collector that they are not pointers. For problem 1, you can use the type system to help you out. Maintain the following invariant: any expression of type Int is represented by an unboxed integer; any expression of any other type is represented by an object. The only problem is when type Int is implicitly or explicitly cast to type Object, or vice-versa. For example, in a method call, the actual parameter might be of type Int and the formal parameter might be of type Object. Similarly, a case expression might downcast a value of type Object to Int. There are other places in the language where such a conversion can happen, but you can find them all by looking for uses of subtyping in the type checking rules. Whenever a value of static type Int is converted to a value of static type Object, you will have to produce code that boxes the integer (allocates an integer object and stores the unboxed integer inside it). Similarly, when a case downcasts an Object to type Int, you need to unbox the integer: load the integer value in the object into the accumulator. For problem 2, you can either tag integers stored in the stack, or you can store the unboxed integers somewhere other than the stack. There are several ways you could do this. The first solution is used widely in Lisp and functional language implementations. The low order bit of an unboxed pointer or integer is reserved as a tag: if it is 0 the word is a pointer, if it is 1 the word is an integer. For pointers that is the end of the story; they function just as usual. For integers, the upper 31 bits are the integer value. To do arithmetic operations, the simplest thing is to shift each argument right to get rid of the low order bit, do the op, and then left shift 1 bit and or in the tag bit. So, for example, c = a * b, where a, b, and c are all registers, would translate to shiftr a 1 shiftr b 1 mul c a b shiftl c 1 or c #0001 and an add of the form c = a +b can be translated into a two instruction sequence: and a #FFFE add c a b These values can be saved in the stack and the garbage collector will ignore them since they do not look like pointers. The downsides of this approach are the slower than optimal instruction sequences and the fact that you now have only 31 bit integers, which is a problem sometimes in practice. If you take this approach please document it and we won't penalize you for test cases that appear to fail due to the limited integer range. Another, non-standard, approach would be to simply box integers that get stored in the stack---saving an integer into the stack is a coercion that allocates an object, just like those introduced by subtyping Int -> Object. This preserves the full range of integers and all programs will work as expected. A third approach would be to allocate a separate stack just for integer values in an area not touched by the garbage collector. The only space readily available for that is the global data area, so that stack would need to be fixed size. For non-recursive procedures, or for integers that do no survive across function calls, you could just pre-allocate memory for every int the procedure uses. For recursive procedures you would have to do something different, presumably saving a (boxed) integer in the regular stack.