Friday, March 12, 2010

Midterm 2 key available

I've graded today's midterm and posted a key.

Overall you did well.  Maybe it was a bit too easy, but I'm satisfied that it showed you had a grasp of the material.  I don't think judging finer gradations of how deeply you understand one topic or another was something I could reasonably expect from a one-hour exam that covered so much material.

Tuesday, March 9, 2010

One more example question ...

I haven't thought of exactly how I would write this up ... but I can imagine asking you to create a data flow analysis for some particular problem, such as the "variables must be initialized on all paths before any possible use" check in Java.   I might give you one set of data flow equations as an example, and ask you to modify them (and describe what the gen and kill sets would be) for a different problem.

Sample final exam questions - part 2

These aren't from old final exams, but are sorts of things I could ask in the midterm Friday.

For these, assume a computer with a load/store architecture (that is, operands of any instruction other than load or store must be a register), and the following instructions  (rX are registers, mem are memory addresses, ";" introduces a comment till the end of the line
ADD  r0, r1, r2   ;; r0 := r1 + r2
SUB  r0, r1, r2   ;; r0 := r1 - r2
BZ   label    ;;  Branch if result of last operation was zero
BN  label     ;; Branch if result of last operation was negative
BNZ label   ;; Branch if result of last operation was not negative
LD  r0,mem  ;; r0 := Memory[mem]
ST  r0,mem  :: Memory[mem] := r

Assume an unlimited set of registers (i.e., assume that register allocation will be a separate step after generating code).

1a. Show an AST and then assembly code for  the following   (which might be Java or C or some similar language).

x = x + y;
y = y - x;

1b.  If your answer is not already in register SSA form (SSA except for memory references), show the assembly code in register SSA form.

2.  Show an AST and then assembly code for the following.

while (x < 0 || x < y) {
   x = x + y;
}

Monday, March 8, 2010

Sample final exam questions

We can discuss these in class on Wednesday, but you might want to try to work them out yourself in advance.

The first two are from a take-home exam.  Questions for take-home exams are written with the assumption that people can use search engines and compiler tools, and without quite the time constraint of an in-class exam.



1. Suppose class B extends (is a subclass of) class A, and we have a method M with the following Java signature:
B M(B o)
or, in Cool syntax
M(B o): B

The Java and Cool type systems do not allow passing an A object to M, but they do allow assigning the return value of M to a variable of type A. Why?

Be brief but clear and concrete. Don't tell me it is because it would be a violation of the type rules; I want to know why those type rules are in Java and Cool.




2. Storage for a Java variable of type int is allocated in the stack (activation record), as is storage for other primitive values like booleans. However, while references to objects are stored in the stack, storage for the objects themselves (including for example Int objects) is allocated in the heap. Why the difference? Be clear, precise, and brief.




The next question makes more sense if you are familiar with stack architectures and stack-oriented virtual machines (e.g., JVM), which we did not talk about this term. Nonetheless you may be able to figure it out.



3. Some of you generated code for the stack-oriented Java virtual machine, and some of you generated code for a physical processor with registers. If you generated Java byte code, you had to calculate the maximum number of stack slots required for expression evaluation. It is relatively simple to translate stack-oriented code into register-oriented code, provided you have as many available registers as the maximum required stack depth. Briefly describe how, and illustrate with an example of translation from postfix or stack-oriented code to register  oriented code for the expression

a + b − (c + d).




I'll try to make up a few new questions before Wednesday, since my stash of (suitable) old questions seems pretty small.  Ideally I would like to cover type checking, code generation, data flow analysis, and register allocation.  Realistically, in a 50-minute exam, I will not be able to cover everything, and it will difficult to craft questions that require some real understanding and yet can be answered quickly.  Probably there will be less of the "explain why" kind of question and more of the "generate code for this" kind of question, though there may be some of each.

Monday, March 1, 2010

Terminology: "Forward" and "Backward" analyses

I got to thinking about terminology after today's lecture, and I think I see how terminology for "forward" and "backward" analysis can be confusing.  When we "look forward" to see what will happen further ahead in execution, that's actually a "backward" flow analysis ... because the information flows backward (we are looking forward, but bringing the information back to here).  It also indicates the way an iterative data flow analysis algorithm orders the nodes it visits.  In a backward flow analysis, it is most efficient to iterate from last to first, again because that's the direction the information is moving.  In a work-list algorithm, if values at node N change, it is the predecessors of N that need to be added to the work list.

Bottom line: the term comes from which way the information is moving, which is reverse of the direction we are looking for it.  So if a flow equation takes in information from the successors of a node, it is a backward analysis, and if it takes in information from the predecessors of a node, it is a forward analysis. 

Thursday, February 25, 2010

Reminder - LALR(1) quiz tomorrow (Friday)

Remember, tomorrow (26 Feb) I will give a quiz (short midterm) so you can show that you've mastered the LR(0) and LALR(1) parsing material that gave you trouble on the first midterm. 

Object code lecture notes

Here are my lecture slides on LLVM IR code generation (up to data flow analysis, which I posted yesterday).  Some of these have been posted before, but I think the first of those below, on walking the AST to generate LLVM IR, has not.
I think that's it, but if you're missing something you recall from lecture, please let me know.

Wednesday, February 24, 2010

Data flow analysis intro slides

Here are the slides I used today, with a couple of corrections to the mistakes you caught.  (There might be more mistakes ... please let me know if you spot one.)

Clang and C++

I experimented a bit with how Clang compiles C++, but I'm not sure it provides much guidance.   With the classes:

class Rect {  ... };
class Square : public Rect { ... };

I end up with the llvm type declarations:

%class.Rect = type { i32, i32, i32, i32 }
%class.Square = type { [16 x i8] }

It does use bitcast to call inherited methods:

 %0 = bitcast %class.Square* %s to %class.Rect*  ; <%class.Rect*> [#uses=1]
  call void @_ZN4Rect9setBoundsEiiii(%class.Rect* %0, i32 0, i32 0, i32 10, i32 10)
  %call = call i32 @_ZN6Square4areaEv(%class.Square* %s) ; [#uses=1]

The strange names like "_ZN4Rect9setBoundsEiiii" are from "name mangling" in C++, which is how C++ provides overloading while maintaining compatibility with C which does not.  The source code name is "setBounds", and the random junk is added to make it unique. 

My C++ mojo has not been sufficient so far to really figure out how the dynamic dispatch is working, but it at least appears that the Clang front end (which is not as complete as the gcc front end) is using casts instead of using nested structures.  That doesn't mean nested structures is a bad idea ... I think either way should work.

Thursday, February 18, 2010

Lecture notes for Friday (more fun with addresses)

Tomorrow's slides (Friday 19 Feb) are here

It's pretty much a continuation of Wednesday's look at how we address things in LLVM, starting with a repeat of the last slide of LLVM code from Wednesday.  Normally I try not to stuff quite so much onto each slide, but in this case I really wanted stuff side-by-side, so we can compare between C and LLVM code.  There is also a slide that shows how the LLVM code becomes assembly code (with x86 assembly; of course it will look a little different if you produce assembly code for a different machine architecture).

Wednesday, February 17, 2010

LLVM web interface

Try the online LLVM demo to compile bits of C code into LLVM intermediate representation.   Also you can meet Bitter Melon, one of the smartest cats I have been introduced to.  Most cats are not very good programmers, because they are too easily distracted.

Thanks Kristy for the tip.

LLVM addressing slides

My slides for today's lecture (Wednesday 17 Feb) are full of example code ... it might be useful to have a printed copy, or an online copy to refer to.  A PDF version is  here.

Tuesday, February 16, 2010

llvm travails

I am now zero for three on compiles of llvm + Clang on ix.  It seems that the nearness to a new release is indeed causing difficulties ... every time I do "svn update" I get several newly updated files.  The first compile took 3+ hours; subsequent compiles have been a little faster.   I'll give it a couple more tries before I admit defeat and either pull an older version from SVN or try put together a binary-only set.

Wednesday, February 10, 2010

Grammar booboo

Suzanne asked about a weird production in the starter grammar I provided ... which seems to allow an expression on the left-hand-side of an assignment.    Oops. 

In many programming languages, there are "lexprs" (left-hand expressions) and "rexprs" (right-hand expressions), and there can be lexprs inside rexprs and vice versa.  For example, you could have something like this in Java:
     myArray[ j + 5 ].itsField =  (foo.bar()).baz();
where j + 5 is an rexpr (denoting a value), but myArray[j + 5] is a lexpr  (denoting a location from which we can get a value or into which we can store a value). 

But not in Cool.   All fields are private.  There are no arrays.  I don't think you can have anything more complicated than a simple identifier on the left side of an assignment.

My bad.  You could just check for this in the type-checker, but a better solution is to fix the grammar so that the left side of an assignment is an identifier and not an expression.  Good catch Suzanne.

A small request: README files

I get many assignments turned in as archives that expand to "Cool" or "Compilers".  I look in the README.txt file to remind me of which assignment was turned in by whom ... and usually what I see is the original README.txt from the scanner assignment.  Please replace the contents of the README file with some identifying information (e.g., "This is the type checker assignment, turned in by I.M. Smart and U.B.A. Mazed").   Thanks.

(I can deal with what I've got so far ... but please start doing this for the type checker and code generator assignments.)

Tuesday, February 9, 2010

List of static semantic checks

Thanks Alex for sifting through the Cool manual and making a list of all the static semantic checks that the "type checker" is supposed to check.  (The scare quotes are because, strictly speaking, a lot of these are not type rules, so really this is a static semantic analyzer which includes type checking and other checks).

1. [No undefined classes, pg. 7] If class C inherits B, then B must be
defined somewhere. This goes for any type specified by the programmer (ex:
let x:Foo := new Foo in 5, where Foo is never defined).

2. [No cycles in the class hierarchy, pg. 7] Class C must not inherit C,
nor should it inherit any other class that eventually inherits C.

3. [No class redefinitions, pg. 5] No two class definitions should use the
same name, i.e. "class C { ... }; ... class C { ... };" is invalid.

4. [No stdlib redefinitions, pg. 18] No class definition may use the names
Object, IO, Int, String, or Bool.

5. [Limited stdlib inheritance, pg. 18] No classes may inherit from Int,
Bool, or String. Classes may inherit from Object and IO.

6. [No attribute/method redefinitions, pg. 5] In the same class, no two
attributes/methods can have the same identifier. A method and an attribute
may share the same name, but not two methods or two attributes.

7. [No inherited attribute redefinitions, pg. 7] If class C inherits B,
and B defines an attribute "foo:Int", C must not contain an attribute
called foo.

8. [Limited inherited method redefinitions, pg. 10] If class C inherits B,
and B defins a method "foo(a:Int, b:Int):Int {}", then C can only
change the , it must not redefine the type signature of foo.

9. [No "self" redefinitions, pg. 12] It is an error to assign a value to
self, bind self in a let or case expression, or use self as the name of a
parameter to a method.

10. [Need a Main class / main method, pg. 19] Every program must have a
class called Main. In Main, there must be a method called main with no
parameters.

11. [All attributes/methods must typecheck, pg. 9] All methods and
attributes must pass the typechecker.

Thursday, February 4, 2010

LALR(1) Howto draft

You asked for a brief, step-by-step guide for creating LALR(1) context-free state machines (CFSMs).  I have created a draft:  Constructing the LALR(1) CFSM

I was shooting for 2 pages or maybe 3, but ended up with 7 ... and that's with no pictures and no worked examples.  I am willing to work on this some more to make it better, but I could use some feedback on the current version.  Is this clearer than the books you are using?  Less clear?  Is it too verbose, or too concise?   Too formal or too hand-wavy?  Can you see how the inductive rules for First and Nullable are the underlying logic for the pseudocode in the books?

There are small discrepancies in the construction from book to book.  I think the Dragon Book mixes together the Nullable and First set algorithms, placing an epsilon in the first set to indicate that a terminal symbol is nullable, while Crafting a Compiler treats these as two different analyses (as I do in this guide).  There may also be bugs in my description.  If you find something confusing, or think you have spotted an error in my instructions, please let me know.

Wednesday, February 3, 2010

AST assignment due Monday

As we decided in class, the AST-building assignment will be due Monday.

The requirement is very simple:  Parse Cool programs, and print the tree in any way you like.   Dot (GraphViz) is one very nice way to look at trees, but if you use it I suggest you find a way to look at just parts of the overall AST, because graphic depictions of large trees get unreadable fast.  While a nice indented listing is also good, I wouldn't invest a huge amount of time building a tree pretty-printer unless you think you will have other uses for it later.

Monday, February 1, 2010

AST example: Itsy bitsy teeny weeny compiler

Here is a very very simple example of  building (and then using) an AST. 

tiny.cup parses a very simple language of assignment statements with expressions as right-hand sides.  It builds a simple AST,which is passed back to the driver.

The driver (Tiny.java) obtains the AST from the parser, and hands it off to an evaluator. The evaluator emits simple stack code (in the form of pseudocode ... but you can see how you could modify this to be either real code in a language like C or Java or instructions to a stack-machine interpreter).

Sunday, January 31, 2010

Midterms are graded

... and will be handed back at the end of class on Monday.

Scores overall are pretty low, and what I learned from grading them is that we really aren't done with LR parsing  (LR(0) and especially LALR(1)) yet.  Some of you are close to mastering it, some are pretty lost, and many are somewhere in between. 

Why do I even care?  After all, we've got nice programs like bison and cup to do this for us.  But I do care, because LR parsing is an exemplar of a couple important algorithmic patterns:
  • Treating a back-tracking problem (searching for a parse tree) as a non-deterministic search (sending angels out to scout different possible parses) and then, because the number of branches we need to explore is finite, folding them together into a deterministic algorithm (just like the subset construction from NFA to DFA).  This is a powerful pattern that has other applications. 
  • Applying a set of rules (adding new items (productions) in a CFSM state) until none of the rules change anything.   We'll see this again in data flow analysis, and it appears in other domains as well.  Often we can look at a problem this way or in other ways, but this way is simpler and clearer.  For example, although most textbooks describe computation of "first" and "follow" sets in other ways, the simplest description is in terms of a set of recursive set inequalities that can be applied over and over until nothing changes. 
Could you grok this just as well without mastering the details of LALR(1) parse table construction?  Maybe ... but I think it helps.  As an analogy, consider that you studied and were expected to really understand red-black trees in data structures, even though there are perfectly good implementations of red-black trees available to you in libraries.    But red-black trees illustrate important concepts about maintaining balance within an acceptable bound and rebalancingwith local operations.  You'll forget the details, but the concepts stick partly because you mastered those details once. You'll forget the details of LALR(1) parsing approximately Wednesday of spring break (and so will I, and then relearn it once again next time I teach it), but the important concepts will stick better if you force yourself to really, really understand it inside and out for at least a little while. 

Friday, January 29, 2010

Midterm & key, and a couple notes

Here is the midterm you took today .

Here is a key to the midterm you took today ... although I haven't very carefully proofread it yet.  Please let me know if you find an error before I find and correct it. 

Looking through the completed exams, it looks to me like we will need to review parsing toward the end of the term.  You've got the basic idea, but most of you had some trouble grinding out the CFSMs.  Two common problems were not completing a state (adding productions for the non-terminals with dots before them) and making transitions to the wrong states (rather than to a state where the dot just moves forward).   Average scores are probably going to be pretty low, but don't panic ... we just need to work on this a little more.   

Tuesday, January 26, 2010

Wed. 2010.01.27 lecture plan

How to say something constructive about abstract syntax trees?  You know how to build tree data structures; all the choices you face in the next phase depend on how those trees will be used. So, what I plan to do is start looking at type checking.   You might want to bring along a copy of the Cool manual, because what I'd like to do is sketch a few trees for small chunks of Cool code, and then look at how we read and interpret the Cool type-checking rules with respect to those trees.

If there are any last-minute questions about the midterm, that's also fair game. 

Friday, January 22, 2010

Old midterms

The questions we did on the board today come from 2006. 
You might want to start with the version without the key, and only then look at the key.

There are a few older midterms available too ... but no keys for them.
I haven't reviewed these older midterms and am not sure how closely they match what we've been doing this term.  I used to spend more time on LL parsing, which I passed over quite quickly this term so that we could start building the parser sooner.

By the way, I was asked whether you should know how to construct First and Follow sets.  Yes, please do.  Note that First is used in LALR(1) parsing as well as LL parsing.  Follow is not used in LALR(1), but the lookahead sets we calculate are closely related, and you should be able to convince yourself that the lookahead set for an LALR(1) item is always a subset of the corresponding Follow set.

Another sample midterm question

I already mentioned this in lecture, and you may remember it ... but it's worth thinking through.  This question was required for students in CIS 561 and optional extra credit for students in CIS 461.

L is the set of all sequences of one or more decimal digits in which each digit appears at most once.  For example, "0152" is in L, and "520" is in L, but "9525" is not in L  (because 5 is repeated).

Is L a regular language?  If it is not regular, why not? If L is regular, how many states are in the smallest DFA that recognizes L?

Sample grammar question from a previous midterm

Here's a question I asked on the midterm in 2006.  It's probably a pretty good indication of the sort of thing you should be able to do on the midterm this year. 

Consider the following grammar. (The terminal symbols are $ (end-of-file), i , “+”, and “;”.  "epsilon"  is used to mark an empty right-hand-side.)

Pgm ::= Block $
Block ::= Block E Sep
Block ::= E Sep
E ::= E "+" i
E ::= i
Sep ::= ";"
Sep ::= epsilon

Part a (5 points): Which of the following strings are accepted by the grammar?
i + i ; i + i
i i i ; i i
; i ; i
i + + i ;
i + i + i ;

Part b (15 points): Show that the grammar is not LR(0), but an LR(0) conflict is resolved using LALR(1) lookahead.  (Just show enouggh states to show how one conflict in the LR(0) machine is resolved in the LALR(1) machine.)

Lecture slides on CUP

Here is a PDF version of my notes on dealing with CUP errors:
http://www.cs.uoregon.edu/classes/10W/cis461/lecnotes/CUPguide.pdf

Thursday, January 14, 2010

Parser starter kit

Next assignment is to build a parser for Cool.   A starter kit (parts of the parser, plus a driver to call it) is at http://www.cs.uoregon.edu/classes/10W/cis461/handouts/parserKit.zip

A few notes on this:
- While in theory we got all the keywords and punctuation in the scanner, as I was finishing up my version of this I discovered I had missed a few ... so that's something to check when parsing fails.
- The driver accepts -d to mean "parse in debug mode", which is quite noisy but helps you see what tokens the parser is receiving and what it is doing with them. Unfortunately it prints them as numbers, so you need to look in sym.java to make sense of it.  (This is pretty stupid ... CUP could easily have translated those integer codes into their symbolic names, but it doesn't.) 
- I've filled in a lot, but left you a few things to figure out ... including how to make the comparison operations <, =, <= non-associative.   Note that you could use precedence declarations in CUP and not factor the grammar down as far as I have to get precedence ... feel free to do it that way if you prefer.
- In the test files, watch out for things that are in Aiken's version of Cool and not our version ---- e.g., one of the tests has loop ... pool instead of do ... od. 
- While my version of this (before I chopped stuff out for  you to fill back in) worked on one example, I do not guarantee it is correct.  You should write several small programs to test it.
- Small is beautiful, especially when you are debugging.  If your parser fails on a program of 30 lines, the first thing you should do is cut it down to a program of 5-10 lines with the same failure.

When you start getting "shift/reduce conflict" and "reduce/reduce conflict" error messages from CUP, you will need to understand the LR parsing theory that we will start talking about tomorrow (Friday the 15th).

Wednesday, January 13, 2010

Study session 10-11 Thursday?

Aran Clauson has proposed to host a study session Thursday during the same hour as class (10-11) in room 260.  Sounds like a good idea to me.  I will also try to be available in that time.

Saturday, January 9, 2010

The ID (identifier) token and what it represents

I was asked whether the scanner needs to recognize bad identifiers like foo.bar.baz .  The short answer is "no, that's a job for the parser", but the question indicates a need to be a little clearer about exactly what the identifier (ID) token represents.

foo.bar.baz is 5 tokens:  ID foo, DOT, ID bar, DOT, ID baz.  A scanner should in general not try to match anything with internal structure, like foo.bar(); it is returning the atoms of a program, to be assembled into molecules by the parser.    (I know the STRINGLIT token may seem like an exception, but from the parser's point of view it has no internal structure, even if the scanner has to do some work to interpret things like \n and \" inside the quoted string literal.)

Friday, January 8, 2010

Building compilers: Pedagogic vs real projects

The order we're tackling the Cool compiler is to build a lexical analyzer for the whole language, then a parser for the whole language, then a static checker for the whole language, then a code generator for the whole language.  We're forced to do that because it gives us some kind of order for studying the different parts of the compiler and their underlying theory, instead of studying everything at once.  But, in case it's not obvious, let me just mention that no sane person would build a real compiler this way.

How do you build a real compiler?

First you build a compiler for the teeniest tiniest subset of the language that you can possibly test ... maybe it can compile the "hello world" program and nothing else.  Probably it can't compile the "hello world" program because that would involve string processing and IO ... but it might compile a procedure that can add two integers.  Maybe you make it an interpreter instead of a compiler, and then you add a code generator as a second step.

And then you add some small feature, adding and fixing what you need in every phase of the compiler, from lexical analysis to code generation.

And then another feature.   And so on.  Add, test, revise, add, test, revise, until you have a complete compiler for the whole language.   It doesn't work as a class project in a compilers course, but it's much better than what we are doing for a real compiler, whether it's for a full programming language like Java or for some itsy bitsy language you invent as an interface to some application you are building.

[Thanks Dan for prompting this thought in our after-class discussion.]

Thursday, January 7, 2010

Two more NFA => DFA problems for the board

1.  From the winter 2005 midterm, a language for binary or trinary literals.  A binary literal is
(0|1)+b2
and a trinary literal is
(0|1|2)b3
So for example 01110101b2 is a binary literal, 0110101b3 is a trinary literal and so is 01002201b3, but 010020101b2 is neither a binary literal nor a trinary literal.   Given an NFA for this, we'll construct the DFA.

2.  From the Spring 2006 midterm, a simplified quoted string problem.  A quoted string (string literal) starts with a quotation mark and ends with a quotation mark.  Within the string, we can have alphabetic characters.  To put a quotation mark within a quoted string, we type two quotation marks together, like this:
"this is a ""string with a quoted substring"" up to here"
If we let 'a' stand for alphabetic characters and Q stand for a quotation mark, the regular expression might be something like
Q(a|(QQ))*Q
We'll use the subset construction to derive a DFA from the NFA.

Regexp => NFA => DFA problem for tomorrow's class

The main things I want to do in class Friday are:
  • work a few examples of translating regular expressions to non-deterministic finite-state acceptors
  • discuss a few practical complications that aren't apparent in the theory, like how the "maximum munch" rule and matching a lot of different patterns (with different actions) go together
  • discuss the limitations of lexical analysis (the pumping lemma, for those of you who took automata theory)
Here's a small example we can do on the board tomorrow, for the first two items above.  Imagine your language has integer constants and floating point constants.  Integer constants are a sequence of one or more integer digits.  It might be specified as
[0-9]+
or equivalently as
[0-9][0-9]+
Floating point constants consist of zero or more digits, followed by a decimal point, followed by one or more digits.  (So .00 is a floating point constant, but 0. is not, and neither is . )  This might be specified as
[0-9]*[.][0-9][0-9]*

We could carefully follow Thompson's construction to get the NFA for each of these and then combine them, but it's easier and less messy to just eyeball the pattern for integer constant and the pattern for floating point constant and create an automaton for each of them, then use Thompson's construction just to tie them together as
    ( integer constant ) |  (floating point constant )
and then we can go through the subset construction to get a single deterministic finite-state acceptor that is looking for both of them and succeeds if it matches either one.  You might want to try that in advance (but you don't have to).  If you do, consider what should happen with the following input:
998
99.foo
.998

Tuesday, January 5, 2010

Scanner assignment up

Grab http://www.cs.uoregon.edu/classes/10W/cis461/handouts/Cool.tgz to get started on the scanner (lexical analyzer) assignment.

I have filled in a lot of trivial grungy stuff and the stuff that doesn't really have anything to do with lexical analysis ... I think what's left for you to fill in should be pretty quick.   Keyword and punctuation patterns are certainly trivial ... you'll see the pattern in Cup.jflex Cool.jflex  and just fill in the few I removed.  Two patterns might take a bit more work: comments and strings.  There is a pattern for comments there already, and it *might* be right, but I don't promise.  There is a pattern for string literals, and I'd be really surprised if it is correct.   It's really ugly, too ... like a lot of complex regular expressions.  Consider using the lexical state facility of JFlex to break it down into simpler patterns that you can read, understand, and fix.

Java will complain that the generated scanner uses unsafe operations.  That's because the scanner skeleton file is written in the old, pre-generics style.   I'm using one of the optional skeletons because I threw in the ability to #include just for fun and to demo how that works ... it's not part of Cool, but it's something you'll want to do in another scanner some day. 

Due: Monday of next week.  The parser assignment will come out Monday or Wednesday.

The README.txt file says a bit more about what you'll find and how to get going.  Although the amount of work here should not be large, it's a good idea to tackle it soon, so that you have a chance to ask questions when things break.

Sunday, January 3, 2010

Schedule: Two midterms and no final?

I will attend a workshop in Germany during finals week.  In principle I could ask someone to proctor a regular final exam and scan and email the exams to me, and I could grade them from Germany ... but it would be a rush job, and too much could go wrong (e.g., some huge blunder in an exam question and me not there to explain what I meant).  So ... what to do?

The best I can think of is two midterms instead of a midterm and a final --- and then put a bit of space between the second midterm and the final project due date, so they don't interfere too much.  I'm thinking final project due Monday of dead week, second midterm on Wednesday or Friday.  Comments?  Better ideas?

Revise Cool language manual posted

I've revised the Cool language manual for this year's class.  Most of the changes are really small an cosmetic, e.g., making the assignment symbol be ":=" instead of "<-"  ("=" is a comparison in Cool).  I added section 13 at the end with notes on differences between Cool and Java (and to some extent C++).  Those aren't essential but might be helpful.

The link from the course web site should work, or follow it here:
http://www.cs.uoregon.edu/classes/10W/cis461/handouts/cool-manual.pdf