/* Parse.cpp * Solution for Assignment #1, COMP322 Introduction to C++, Winter 2010 * * Written by Robert Vincent * * Demonstrates a recursive-descent parser for a simple language * consisting mostly of infix expressions. */ #include #include using namespace std; #include "Lex.h" using namespace Lex; namespace Parse { /* Forward declarations of our parsing functions. */ extern bool statement(istream &); extern bool expression(istream &); extern bool term(istream &); extern bool factor(istream &); /* Function to parse a statement using a simple recursive-descent method. * * The sole input argument is the stream from which to read. * The return value is a boolean, 'true' if the parse was successful, * 'false' otherwise. */ bool statement(istream &in) { if (cur_tok() != '\n') { /* Do we have a statement of the form "SET \n"? */ if (cur_tok() == SET_KW) { get_next(in); // Get next token if (cur_tok() != SYMBOL) { cerr << "Expected a symbol after 'set'\n"; return false; } string tmp(cur_sym()); // Copy into safe location get_next(in); // Get next token expression(in); // Parse an expression cout << tmp << " = "; // Print the symbol and assignment for postfix } /* Perhaps we have just an expression statement. */ else if ( !expression(in) ) { return false; } /* Now require that we see and end-of-line character. * Anything else means there was unparsed junk after the * expression. */ if (cur_tok() != '\n') { cerr << "Expected end of line.\n"; return false; } } cout << endl; return true; } /* Parse an expression using a simple recursive descent approach. * Arguments and return value are as with the statement() function. */ bool expression(istream &in) { int op; if (!term(in)) { // Try to parse an initial term return false; } /* While we see either '+' or '-' as the input token, we treat * these as operators and attempt to gather another term. */ while ((op = cur_tok()) == '+' || op == '-') { get_next(in); // Consume operator token if (!term(in)) { // Get next term return false; } cout << (char)op << ' '; // Print operator for postfix } return true; } /* Parse a term using a simple recursive descent approach. * Arguments and return value are as with the statement() function. */ bool term(istream &in) { int op; if (!factor(in)) { // Try to parse an initial factor return false; } /* While we see either a '*' or '/' as the input token, we treat * these as multiplicative operators and attempt to gather another * factor. */ while ((op = cur_tok()) == '*' || op == '/') { get_next(in); // Consume operator token if (!factor(in)) { // Parse next factor return false; } cout << (char)op << ' '; // Print operator for postfix } return true; } /* Parse a factor using a simple recursive descent approach. * Arguments and return value are as with the statement() function. */ bool factor(istream &in) { if (cur_tok() == '(') { // An expression in parentheses? get_next(in); // Consume the left parenthesis if (!expression(in)) { // Try to get the expression return (false); } if (cur_tok() != ')') { // Require a right parenthesis cerr << "Unmatched parentheses" << endl; return (false); } get_next(in); } else if (cur_tok() == SYMBOL) { // A symbol. cout << cur_sym() << ' '; // Print immediately for postfix get_next(in); } else if (cur_tok() == NUMBER) { // A numeric constant. cout << cur_val() << ' '; // Print immediately for postfix get_next(in); } else if (cur_tok() == '-') { // Unary minus get_next(in); if (!factor(in)) { // Parse the next factor return false; } cout << "NEG "; // Print operator for postfix } else { cerr << "Syntax error.\n" << endl; return (false); } return (true); } } /* The main function for the parser. */ int main() { /* Keep reading while there are no errors, and the next token is * not an "end of file" token. */ while (cin.good() && get_next(cin) != ENDOFFILE) { /* Attempt to parse a statement. */ if (!Parse::statement(cin)) { cout << "Error!\n"; /* Error recovery. Search forward through the input * until we encounter the next newline. */ while (cin.good() && cur_tok() != '\n') { get_next(cin); } } else { cout << "OK\n"; } } }