More issues have arisen with static and instance fields sharing names. To simplify things as much as possible at this late date, we clarify the semantics as follows:
We realize this contradicts a previous clarification, and that this is a late date. In light of that, we will not be testing cases that mix static and instance fields / methods of the same name incorrectly; any tests we do on conflicting names will have clear semantics according to the original handout. Also note that in spite of these naming restrictions, static fields and methods are still not inherited, as seen in the following example:
class A { static int x; }
class B extends A {
static void m() {
x = 3; // ILLEGAL
A.x = 3; // LEGAL
}
}
Sorry again for the late clarifications.
An updated PA3solution.jar has been posted with a bug fix. This is not critical, but if you've been having problems with the parser and multiple classes, download it and give it a try. UPDATE (12/1): We just fixed another bug; please re-download. Sorry about that.
A bug has been found in the PA4 solution type checker. The visit(InfixExpression) method of the TypeChecker class should be changed to the following (updated 11/29):
public boolean visit(InfixExpression e) {
e.getLeftOperand().accept(this);
Type leftType = (Type) e.getLeftOperand().getProperty(DecafProperties.TYPE);
e.getRightOperand().accept(this);
Type rightType = (Type) e.getRightOperand().getProperty(DecafProperties.TYPE);
InfixExpression.Operator o = e.getOperator();
if (o == InfixExpression.Operator.CONDITIONAL_AND || o == InfixExpression.Operator.CONDITIONAL_OR) {
e.setProperty(DecafProperties.TYPE, checkTwoTypes(boolType, leftType, rightType));
} else if (o == InfixExpression.Operator.EQUALS
|| o == InfixExpression.Operator.NOT_EQUALS
|| o == InfixExpression.Operator.LESS
|| o == InfixExpression.Operator.LESS_EQUALS
|| o == InfixExpression.Operator.GREATER
|| o == InfixExpression.Operator.GREATER_EQUALS) {
// check that operands are integers
Object ret = checkTwoTypes(intType, leftType, rightType);
// allow booleans for EQUALS and NOT_EQUALS
if (ret == null
&& (o == InfixExpression.Operator.EQUALS
|| o == InfixExpression.Operator.NOT_EQUALS)) {
ret = checkTwoTypes(boolType, leftType, rightType);
}
e.setProperty(DecafProperties.TYPE, ret == null ? null : boolType);
} else {
// expecting ints
e.setProperty(DecafProperties.TYPE, checkTwoTypes(intType, leftType, rightType));
}
return false;
}
Note that you are responsible for fixing this bug if you are using our
solution.
Questions have arisen regarding accessing static fields or methods through subclasses; both are in fact illegal. So, if static field x and static method m() are declared in class A, and B extends A, then B.x and B.m() are both illegal (assuming B does not have a static field x or static method m()).
Also note that semantic checks 8 and 9 do not apply to static fields and methods. So, in the above case, class B is allowed to declare both a static field x of any type and a static method m() with any signature. UPDATE: this is no longer correct; see the 11/29 correction above.
Finally, for semantic check 2, check (a) takes precedence over check (b). So, if you have both a class A and a local variable A, then A.x refers to the instance field x of local variable A, not the static field x in class A. If the local variable A does not have an instance field x, this is an error, even if the class A has a static field x. To summarize, if the expression to the left of a dot is a resolvable name in the scope, then the field reference is to the instance field of the name. If the name is not resolvable as a variable or field, only then should it be resolved as a class name.
If two functions are declared with the same name, it should be an error until semantic check #1. If a function call refers to a non-existent function, it should be an error under semantic check #2. You do not need to check that all methods are static (fields too), but you can assume that all inputs that we expect to compile will have this property.
You should not modify any of the classes in the edu.berkeley.cs164.checker package in your PA4 solution.
We have the following three important clarifications on SkimDecaf and the assignment.
On page 4 of the handout, the required method in the Program class should be main, not Main.
We have two clarifications on the semantics of Skim Decaf.
void foo(int x) { boolean x; { String x; x = "bar"; } }
The handout is at times unclear about the following point on associativity; only the AST eventually constructed by the actions must be left-associative. The parse tree need not be. See the top of page 10 in the handout for the clearest explanation.
A student spotted out an error in the UNARYEXPR production in decaf.dpar:
UNARYEXPR -> <MINUS> TERMEXPR | <NOT> TERMEXPR | TERMEXPR ;To see the error, try to parse --3 (there is no -- operator in Decaf, so this is the same as writing -(-3)), which is allowed by the grammar in the handout. The fix shouldn't be too hard to figure out (you only need to change this production), and we leave it to you.
Also, another small clarification on decaf.dpar. You should only need to change productions between the //----- comments, and you need to fix one other problem besides fixing the productions ending in 2 and the above problem with UNARYEXPR. Test carefully!
We forgot to update the LexerCode class in the PA2 solution to be in synch with the fixed decaf.dlex file. Here it is. You can also regenerate the file from decaf.dlex by running the runPart4() method in edu.berkeley.cs164.lexer.Main and then refreshing in Eclipse.
In decaf-with-actions.dpar, the PROGRAM production should have another action on the end, as follows:
PROGRAM -> _ [| push(new ArrayList()); |] CLASSDECLLIST <EOF> [| push(peek(-1)); |] ;Also, the final action for CLASSDECL should be push(peek(-7)) instead of push(peek(-6)).
We have an important clarification and some fixes for the assignment. The clarification is for the decaf.dpar file. We unintentionally put a version of the file in the starter kit that already has some of the disambiguation and left-factoring completed. While this file has more of the solution than we intended, it is still incorrect. The structure of handling precedence is correct, but all productions that end in 2 (eg. BOOLEXPR2) are obviously incorrect. You will have to fix these productions so they are left-factored as suggested in the handout, lecture notes, and section notes (so that when actions are added, the AST will be left-associative). Sorry about this mistake.
Additionally, we have fixed versions of some files:
getToken() should be nextToken().
Sample PARTNERS file:
cs164-tb
cs164-ta
int x = 3; is not legal in
Skim Decaf. Programs can use any variable name at any time. It is as
if all possible variables are declared as global ints.x = 3,
this does not generate a warning.=. You do not need to implement any of the compound
assignments such as +=.
print(x = 3);
print where an integer is required, the interpreter
throws a VoidValueException. Compilers normally include a semantic
check phase which would detect this problem when the program is
compiled. However, interpreters, such as the one in PA1, often do not
detect these errors until the program actually does something
illegal.else
clause.Block
AST nodes.Class1 and method
name Method1 is printed like this:
public class Class1 {
public static void Method1() {
}
}
public class Cls {
public static void main() {
while (1) {
if (x + 2) {
while (x - y) {
y = 9;
}
} else {
if (x + 23) {
y = 32;
} else {
y = 24;
}
y = y - 9;
}
print(y);
}
}
}
print(3 + 4);
print((3 + 4));
The important thing is that the pretty-printed program have the same
order of operations as the input program.
Block is a list of
Statements. Since MethodDeclarations are not
statements in this AST, a TypeDeclaration does not
contain a block.
Main as much as you want.
IntValue class in the starter
kit. The only requirements on Interpreter are that it
extends GenericVisitor and that it correctly interprets
ASTs when used to visit them.x = -3. You can get the same effect with
x = 0 - 3.
while (...) {
if (...) {
...
} else {
if (...) {
...
}
}
}
MethodInvocation AST node is always
a print expression. The name of the "method" is always $print. The
name $print was selected in order to emphasize that this
is not a real method, but rather a special operator that we are encoding
using the MethodInvocation node type.
public class CLASSNAME {
public static void METHODNAME() {
// statements go here
}
}
- The main goals of having you write the 3 "hard-coded" test cases
are:
1. Practice creating ASTs with code. Now you know it can be
done and how to do it in Eclipse. This will help on PA3.
2. Learn by experience that entering ASTs is not as nice
as using source text, which is exactly why there is such
a thing as source text (see also Lisp).
- We haven't taught about testing yet, so we don't expect you to be
experts on testing methodology. But it's great if you're thinking
about it anyway.
- So, the key is to write some "decent"-sized test cases. But
don't spend 20 hours hand-translating test cases. The purpose
of PA1 is learning about programming language tools, not pointless
suffering.
- This would be sufficient for full credit:
- Each Simple Decaf statement and operator appears in at least
one test.
- Two test cases test for some likely bug (e.g., failing to
throw VoidValueException). They can be short.
- The other one tests for a likely bug, or is a big case to
cover the rest of the statements and operators.
Last modified: Friday, September 5, 2003 4:14 PM