Write a PREDICTIVE (no backtracking), recursive descent parser for the grammar below. EBNF is used, so be careful to note whether a symbol is a metasymbol or not. The six valid metasymbols are the following: {, }, [, ], (, and ). A symbol is NOT a metasymbol if it is in single quotes (e.g., '[' and '}'). All the tokens are single characters, so the scanner is trivial. NAME your scanner function "getToken" (see Required Functions below).
In a comment above EVERY parsing method, show the rewritten GRAMMAR RULE that it parses. Use the STANDARD techniques we studied to remove left recursion and perform left factoring.
M → { S } '$' S → I | W | A | P | C | G I → '[' E ? { S } : { S } ']' | '[' E ? { S } ']' W → '{' E ? { S } '}' A → id = E ; P → < E ; C → < ( 'B' | 'T' | 'N' ) ; G → > id ; E → E + T | E - T | T T → T * U | T / U | T % U | U U → F ^ U | F F → '(' E ')' | id | num id → a | b | ... | z num → 0 | 1 | ... | 9
Non-terminal | Meaning |
---|---|
M | Main Function |
S | Statement |
I | If-Then-[Else] |
W | While |
A | Assignment |
P | Print Integer |
C | Print Character |
G | Get Integer |
E | Expression |
T | Term |
U | Up-raised Term |
F | Factor |
Terminals B, T, and N, stand for blank, tab, and newline, respectively. An identifier (id) must be a SINGLE LOWERCASE letter. A number (num) must be a SINGLE DIGIT. A valid program must end in '$'.
Input a string from the user (one character at a time). Use whitespace as a delimiter (" \t\r\n").
Indicate whether the string is valid or not. Detect an error and output an error message indicating ALL of the following:
Error in "<function>" on line <lineNum>: expected '<expectedToken>' but got '<currentToken>'.
If the string is valid output "Valid!".
Sample Input/Output 1[ a ? b = 5 ; ] $ Valid!Sample Input/Output 2
> x; > y; < (x * y) + 3 % (y ^ 2); { x & x = x - 1; } $ Error in "W" on line 8: expected '?' but got '&'.
// Read and return a character token. // Skip whitespace and keep track of line number. char getToken (); // Check if the current token matches "expectedToken". // If so, update the current token. // If not, call the "error" function. // "function" is the function which called "match". void match (const string& function, char expectedToken); // Output an error message using the appropriate format. // "function" is the function in which the error occurred. void error (const string& function, const string& expected);
Submit your parser file.
The part of the grammar involving "{ S }" means "zero or more statements". In handling such a construct, you need to know when to stop calling function S, the one that handles a statement. There are two methods to do this: call S as long as the next token is one that can start a statement. The other (equivalent) method is to keep calling S until the next token is one that may end a sequence of statements.
See the RecursiveDescent directory for examples and some test cases.