Skip to main content.

Final Project: FAQ

Project Specification

Answers to your commonly asked questions.

General Code Questions

What code can I change?
Any and all of it. Make sure you understand why you are changing it and use branching and commits judiciously so you can roll back if needed.
These variable names/method names/... don't make sense to me,
After you understand their purpose, rename them (using Eclipse's refactoring tool) with a descriptive name that would be more helpful.
There are code smells in this code!
Indeed. You need to understand well-designed code as well as poorly designed code (and why it is poorly designed). You should be able to address the code smells
How does a switch statement work?
Switch statement tutorial
How can I "connect" these two things/have them interact?
Consider the different ways that we can connect things. You need to consider the context/scenario to figure out which is the best way for your code.
  • We can make a (non-private) static method that can be called by other classes.
  • If we have an object of the class, then we can call methods on that object.
  • If we need an object in another class, we can pass it as a parameter to a method or a constructor.

    For example, in the Goblin game, the GamePiece objects had a takeTurn method that took as a parameter a Game object so that the GamePiece could call methods on the Game object.

    As another example, in the Canvas class, the constructors take a Frame as a parameter and then store the Frame as a private instance variable. Then, the Canvas can call methods on its Frame object.

Eclipse is having trouble/I can't run Main/
  • Confirm there aren't any compiler errors in required code.
  • Look at the Problems view (often in Eclipse's bottom panel)
  • In Eclipse's Project menu, select Clean... to delete all the .class files and recompile.
  • If it still doesn't run, delete the Run configuration (under the Run menu, click on Run Configurations and then delete the Java Application Main configuration and then try running again.
Something very weird is happening, e.g., something that seems fundamental or that I copied from other Picasso code or from class slides isn't working.
Check your assumptions. Common sources are
  • You're importing the wrong class. Remember multiple classes can have the same name; make sure you import the class from the appropriate package.
  • java.lang classes are imported by default, but if you name a class with the same name as one of those, you may not know which one is being used. (Eclipse can show you, though.) It's easiest just to avoid naming classes, e.g., String or Error.
I'm overwhelmed. Where should I start?
Check out the test classes. They make it clearer what the various components are supposed to do (what are their inputs, what is their output).

Then, try implementing a unary function: first, write the test cases, then implement the unary function.

Tokenization

I know I need to handle quoted strings for the images, but when I try to get the string, I only get the quote.
This requires understanding a bit about the StreamTokenizer class, which is used by the Tokenizer class and other associated classes. Look what it says in the nextToken about ttype and in the ttype documentation about quoted strings. If you make sure you understand the existing tokenization code first (at least at a high level, e.g., where is the nextToken method called? How does its result get used?), then this step becomes fairly straightforward.
What does tokenNameToToken represent?
First, see where it is updated/used. Right click on the name, then go to References and select Project. One place it's being updated in is the initBuiltinFunctionTokenMappings. That name is probably more descriptive than the map's name. It maps the name of the function to the Token class that represents the function. It is used to distinguish between a known function name and an identifier (a variable).

Check out where else it is being updated/used.

In the Tokenizer class, why is a space added before minus signs?
Otherwise, the minus sign is included in the variable name when you try to evaluate the expression x-y. This isn't a problem with the other operators.

I implemented a terrible hack to solve this. I think this should usually work (and not break something else). In Tokenizer's parseTokens method, this statement (and its comment) is the first line:

       // - is seen as a numeric character. If we try to parse, e.g., x-y, 
       // it is seen as one string "x-y".  See StreamTokenizer documentation about
       // handling words. So, our imperfect solution is to always add
       // a space before a minus sign. Negative numbers will still be
       // seen as numbers, and the space will mark the end of a word.
       s = s.replace("-", " -"); 

Here's what is happening: the StreamTokenizer looks at characters and tries to figure out what to do with them. According to the documentation, "A word token consists of a word constituent followed by zero or more word constituents or number constituents." So, when the StreamTokenizer sees the x in x-y, it grabs every word or numeric constituent that follows. We need the minus character to be a number constituent because we want to be able to parse numbers, e.g., -1. If we try to make the minus sign an "ordinary" character, we can no longer parse negative numbers. So, since this really isn't the focus of the assignment, we'll go with the imperfect solution provided above. (Although I am open to hearing proposals of better solutions.)

Parsing

The order of operations constants don't make sense. GROUPING should have high precedence.
You're learning to try to read someone else's code. Note that GROUPING is not yet used, and this is partial code. I am not sure if it would be used. It seems like it's placed for the parentheses of a function, but I don't know what the original goals of this code were. You can and should change this code to be whatever makes the most sense to you--well, and has good design.

Note that, if you have your automated JUnit tests, you should be able to make changes to this code and confirm that you are getting correct results fairly easily.

How should parsing an assignment statement work?

Consider each part separately for some sample expressions, e.g., a=x and floor_of_x=floor(x). Then consider, what should happen when the user enters a or floor_of_x/x?

Write JUnit tests for each step in the interpreting of the language for these expressions.

  • Tokenizing: What should the tokens be for each example?
  • Parsing: What should the result of infix to postfix be? What analyzers need to be involved? What should the expression tree look like?
  • Evaluating: What is the result of evaluating an assignment statement?

Note that you should not handle assignments specially, separately. You have all of this parsing infrastructure, so add to the parser to handle assignments.

Consider what functionality/classes you can use/leverage. You may need to do some refactoring to make it all work together well.

Finally, what erroneous assignment statements should you handle, i.e., display an error message?

Semantic Analyzer

I am getting an error about not being about to find "=AssignmentToken".
Go to the code where the error occurs by clicking on the stack trace. What is happening in that code? The answer to the next question may be good to reference.
I made my code for the negate/inversion (!) operator and updated all the right files, but my code isn't finding its semantic analyzer.
This one is tricky. ! is a comment for the properties file. You'll need to escape the character (using the escape character: \) in the properties file.

Evaluating

How do I implement evaluate something?
As we discussed in class, make sure you check ReferenceForExpressionEvaluations to see if there is anything helpful there.
How should String's evaluate work?
The description says, "an image of the given file name is read. This should return the nearest color from the image at the current (x, y) values. If the image cannot be read, an error is thrown."

Recall how Evaluator works: it converts the image coordinates (which is an int between 0 and the dimension) to the domain space (-1,1). For String, you'll want to do the opposite: convert from the domain space to image space.

How should imageWrap and imageClip work?

First, refer to the examples for imageWrap and imageClip on the intrinsics page and compare with the original vortex image.

Then, consider this:

Check out Pixmap for its code related to images. (You don't need to use a Pixmap object itself -- that's more than what you need; just copy and adapt the relevant parts in your code.)

Similar to what you've been doing (hopefully), write test cases for each part (tokenizing, parsing, evaluation) before you implement much code. Make a simple test image that will be easy to test.

imageClip is similar, but how the coordinates are kept within the domain is different. (Refer back to the example image.)

I keep getting errors about not being able to find the image file, but the image file is there.
One trick to help with your debugging is to construct a File object using the filename and check what its path is (getAbsolutePath()). Does that path match what you expected?

You can either change the String that you pass in to make it be the appropriate path or add an image directory in your image code to say where to look for images. Make sure that directory works for all of your teammates and me, i.e., not hardcoded for your computer.

Error Handling

Errors can happen throughout the code. Do I need error handling statements everywhere?
First, let's distinguish error handling (which should be everywhere) vs reporting errors to the user via the GUI. Errors should be handled, i.e., the code doesn't crash and is in a stable state. Exceptions (e.g., ParseException) represent the error and can be propagated up to whoever called the method.

Reporting errors to the user, however, should not be throughout the code and it shouldn't happen in non-GUI code. Remember the single responsibility principle, and consider that the interpreter code should be independent of the GUI. For example, consider if we wanted to have another GUI for the interpreter, e.g., one that is designed for children or is web-based. As a project-focused example, when you run the JUnit tests, which are focused on the interpreter and should test error cases, those error test cases shouldn't pop up GUI windows and also shouldn't fail because the GUI hasn't been created. Since the tests are automated, you don't want to have to click the OK button (or similar) whenever there is an expected error.

Consider where the central points or bridges are between the GUI and where the errors occurred: that's where the error reporting code should go. There should only be a few places where the error reporting code is called.

If there is an error when evaluating an expression, the next [valid] expression evaluated doesn't work either. But, if you press the button again, it works.
Add some print statements to try to figure out what's happening. Is there something leftover from the erroroneous expression?

Testing

I wrote my JUnit test, but the test is failing, and the output is a little strange.
Two things that will make testing better and debugging easier: overriding the toString and equals methods in the relevant classes that are being compared.
I can't test method X because it's private
If it's private, is there a method that calls that method that you can test instead?
How can I test evaluating the ExpressionTreeNodes?
This should look similar to what we did in class, where we computed what the resulting RGBColor would be at a specific (x,y) coordinate. For example:
        @Test
	public void testFloorEvaluation() {
		Floor myTree = new Floor(new X());
		
		// some straightforward tests
		assertEquals(new RGBColor(0, 0, 0), myTree.evaluate(.4, -1));
		assertEquals(new RGBColor(0, 0, 0), myTree.evaluate(.999, -1));
		assertEquals(new RGBColor(-1, -1, -1), myTree.evaluate(-.7, -1));
		
		// test the ints; remember that y's value doesn't matter
		for (int i = -1; i <= 1; i++) {
			assertEquals(new RGBColor(i, i, i), myTree.evaluate(i, -i));
			assertEquals(new RGBColor(i, i, i), myTree.evaluate(i, i));
		}
		
		double[] tests = {-.7, -.00001, .000001, .5};
		
		for( double testVal : tests) {
			double floorOfTestVal = Math.floor(testVal);
			assertEquals(new RGBColor(floorOfTestVal, floorOfTestVal, floorOfTestVal), myTree.evaluate(testVal, -1));
			assertEquals(new RGBColor(floorOfTestVal, floorOfTestVal, floorOfTestVal), myTree.evaluate(testVal, testVal));
		}
		
	}

GitHub

Eclipse is saying that there are conflicts in our main branch, and I'm unable to merge my branch.
Yeah, that happens. Try to resolve the conflicts. You'll need to decide if you want to use that version or your version or maybe do a merge. After resolving the conflicts, stage them for commitment and then commit. Eclipse's User Guide

GUI

Wouldn't it be cool if I could press enter on the text box, and evaluation would happen? How do I do that?
Yes, in fact, that is required functionality. This links to a simple example of how to make the text field respond to the user pressing enter.

Configuring Eclipse

Whenever I try to open a .exp file in Eclipse, some other editor opens.
There are a few options:

Every time you open a .exp file, you can right-click on the file and choose "Open With" and then "Text Editor".

Or, when the pop up about the editors comes up, click to set the "Preferences for File Associations". Add .exp as a file type, and then add the associated editor for the .exp files. Search for "text" and select "Text Editor". Apply the changes and then close the window.