There are many places to get this information on the web. I'm going to give you one link which may not be long-lived, but should be good until the due date for PA2 this semester. It's from a work-in-progress manuscript by Bill Venners called Objects and Java found on the artima.com web site. Once you follow the link you should tell your browser to search for the term precedence, and you'll get to the section on Operator Precedence and Associativity.
localList -> localList . local
method --> type ID (formalList) { localList . stmtList RETURN expr ; }
The shift-reduce conflict is on ID, where it doesn't know whether to
reduce by
stmtList --> <eps>(i.e., the RHS is epsilon, the empty string) or to shift ID, to start building the next local declaration. (Note that both local decls and assgt statements can start with ID, but this isn't an inherent problem for us if we write the grammar correctly.) There would be a similar conflict for the rule for mainMethod.
We only want the top-level stmtList to go to epsilon if there are NO statements in the method we are parsing. But both ID and RETURN are in FOLLOW(stmtList), so the parser can reduce on ID, or shift on ID (because a local can start with an ID). We can fix this so that we only use an eps-production if it's actually an empty statement list. We can do this by writing the grammar to distinguish an empty statement list from a non-empty statement list. Then we only use the epsilon production for the statement list if the whole statement list is empty (an empty statement list can only be followed by '}' or RETURN, not ID, so the conflict goes away). There are two possible parts of the grammar you can change to do this:
One solution involves changing the stmtList grammar so that it distinguishes an empty stmtList from a non-empty stmtList. We only use an eps-prod if there is an empty statement list, and we'll have another non-terminal for a sequence of one or more statements. This new non-terminal will have no epsilon-production.
An alternate way to achieve the same effect is to change the rules for method and mainMethod instead, so that each of them distinguish the empty statement list case from non-empty statement list case.
My guess is that for one of your trees you didn't assign anything meaningful for one of the subtrees, then when dump went to print it, it's trying to dereference an invalid or NULL pointer. So, in this scenario crashing from a dump routine doesn't mean dump is broken. Also sometimes run-time errors happen in a different place than what actually caused the error, because if you have overwritten a random part of memory, you can get bad values in places you don't expect. That said, you probably will be able to find where the problem is by running a symbolic debugger: ddd or gdb work with g++-compiled programs. If you run it in the debugger it will show you the source line where it crashed, and you can start examining the call sequence to there, etc.
If you are unfamiliar with the debuggers: you can run gdb from inside emacs
esc-x gdbthen it will prompt for the exe (testparser)
when the gdb prompt comes up in an emacs window type
run Test.esp(or give whatever prog you were trying it on)
then it will crash and point a cursor at the right line number in a
different emacs window. You can then do the
where
command in gdb to see what's on the call stack, and then navigate
around the call stack if necessary using the commands
up and down
E.g., if it was doing dump on a particular type of node when it
crashed, you should focus on your bison code that creates that node.
The command help is how you get help in
gdb. There is also a slightly longer introduction
to debugging in Unix linked in the Documentation section of the web
page.