Q1: How do I get the line numbers for each AST node? CUP gives ClassCastExceptions/NullPointerException etc.
A1: The problem is that CUP returns the value field of Token; not the Token itself. Really the best solution is to modify your scanner so that it stores the Token in the value field of Symbol. Here is approximate code in IC.lex:

"class" {: return new Symbol(...new Token(..line..)...) :}.

Then, in IC.cup you write something like:

terminal Token CLASS;
CLASS_DECL ::= CLASS:cl ID...
{: RESULT = new ICCLass(...cl.getLine(); :}


However, if you give approximate line numbers or information about the construct where the program occurred (e.g., "Error in class A"), that is fine too.

Here is another way, suggested by Eli Romm (last year):
note that in class symbol there are 2 fields "left" and "right" that can be used to pass data to the cup. So, by adding this line to the Token constructor we can save the line number in the symbol this.left=line;. Then, if in the cup we have a rule like rule::=ID:data RP RP , we can access the line number of the ID token by dataleft. For example, rule::=ID:data RP RP: {: System.out.println(dataleft); :}

Q2: How should we handle the Library class in libic.sig?
A2: You should read and parse the file when the -L option is specified. The result is (expected to be) a class named Library. You should add that class to the list of classes under the Program AST node.