Parser Hints

Download Report

Transcript Parser Hints

Parser Hints
26-Jul-16
The Stack




To turn a “Recognizer” into a “Parser,” we need the use
of a Stack
All boolean Recognizer methods should continue to
return boolean values, but in addition, if they succeed
they should leave a Tree on the stack
The stack should be an instance variable of the Parser
Here’s one easy way to do it:

Create a new Parser(String s) for each String you want to
use, and call some parsing method (term, command, ...) for
that particular String
Recognizer helper methods




private boolean number() {
return nextTokenMatches(Token.NUMBER);
}
private boolean name() {
return nextTokenMatches(Token.NAME);
}
private boolean keyword(String expectedKeyword) {
return nextTokenMatches(Token.KEYWORD, expectedKeyword);
}
private boolean symbol(String expectedSymbol) {
return nextTokenMatches(Token.SYMBOL, expectedSymbol);
}
nextTokenMatches


private boolean nextTokenMatches(int type) {
Token t = tokenizer.next();
if (t.getType() == type) {
return true;
}
else tokenizer.pushBack(t);
return false;
}
private boolean nextTokenMatches(int type, String value) {
Token t = tokenizer.next();
if (type == t.getType() && value.equals(t.getValue())) {
return true;
}
else tokenizer.pushBack(t);
return false;
}
Revised nextTokenMatches


private boolean nextTokenMatches(int type) {
Token t = tokenizer.next();
if (t.getType() == type) {
stack.push(new Tree(t));
return true;
}
else tokenizer.pushBack(t);
return false;
}
private boolean nextTokenMatches(int type, String value) {
Token t = tokenizer.next();
if (type == t.getType() && value.equals(t.getValue())) {
stack.push(new Tree(t));
return true;
}
else tokenizer.pushBack(t);
return false;
}
comparator




<comparator> ::= "<" | "=" | ">“
public boolean comparator() {
if (symbol("<")) return true;
if (symbol("=")) return true;
if (symbol(">")) return true;
return false;
}
Whatever a comparator is found, one Tree node (with the Token
representing that comparator as its value) is left on the stack
Since we recognized one thing, and we leave one thing on the
stack, this method does not need to be changed in any way
while command

public boolean whileCommand() { We want to change this:
if (keyword("while")) {
if (condition()) {
block
if (block()) {
condition
makeTree(3, 2, 1);
while
return true;
}
}
Into this:
error("Error in \"while\" statement");
}
return false;
}
command
The makeTree method will take three things
off the stack and replace them with one thing
Counting



I like to count this way:
1
2
3
block
while condition block
condition
This way is easier to implement:
while
2
1
0
while condition block
I prefer the first way because, although it means
trickier arithmetic in makeTree, it simplifies counting
everywhere else
Accessing the Stack



A stack, as a stack, has no methods for accessing the nth thing
from the top, but...
class Stack extends Vector
...and Vector has an elementAt(int index) operator
0
1
2
3
4
5
6
7
a b c d e



This represents a stack with five things in it
The “e” is at the top of the stack
This means that, with some annoying arithmetic, you can
access any element of the stack you like, counting
elementAt(vector.size() - 1) as the top
Recursion in BNF

<term> ::= <factor> | <term> “*” <factor>
is bad, because of the left recursion


<term> ::= <factor> | <factor> “*” <term>
has another problem


Implemented in the obvious way, it would cause our program
to go into an infinite recursion
Implemented in the obvious way, it will build a tree of the
wrong shape
<term> ::= <factor> { “*” <factor> }
works well

Implemented in the obvious way—iteratively, not
recursively—it builds a tree of the correct shape
term()

public boolean term() {
if (!factor()) return false;
while (multiplyOperator()) {
if (!factor()) error("No term after '*' or '/'");
makeTree(2, 3, 1);
}
return true;
}
The End