So lets say I have the following grammar:
let_stat = "let" iden [ "=" expr ];
if_stat = "if" expr "->" stat;
stat = let_stat | if_stat;
This would be the following psuedo-ish code:
let_stat parseLetStat() {
if token is "let" {
consume token
if token is identifier {
char *value = consumetoken.value
let_stat let = new let_stat;
let.name = value;
if token is "=" {
let.value = parseExpression;
}
return let
}
}
}
if_stat parseIfStat() {
if token is "if" {
consume token
expression expr = parseExpression;
block block = parseBlock;
if_stat ifstmt = new if_stat
ifstmt.expr = expr
ifstmt.block = block
return ifstmt
}
}
stat parseStatement() {
}
What would the parseStatement
function do? How would it choose which function to call, the if_stat function, or the let_stat function? Or would I throw all the code into one function? I don't quite understand, any help would be great since I'm confused.
The key issue for your specific problem is that when there is alternation in an EBNF rule, the parser for the nonterminal must call all the alternatives and ask each if it recognizes the construct; each subparser has to return a flag indicating yes or no.
What you probably need are general principles for writing a recursive descent parser.