Final Project: FAQ
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
- 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 and its test (in the opposite order -- first the test case, then 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 thenextToken
aboutttype
and in thettype
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 thenextToken
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
'sparseTokens
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 theStreamTokenizer
sees thex
inx-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
anda=floor(x)
. Write appropriate JUnit tests for each step.- 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 this specially separately. You have all of this 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.
Continuing with the above examples, what should happen when the user enters
a
ora/x
? Write tests for these statements too.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
imageWrap
andimageClip
work? -
First, refer to the examples for
imageWrap
andimageClip
on the intrinsics page and look at 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 (that also works for all of your teammates and me!), or add an image directory in your image code to say where to look for images.
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.
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
andequals
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.