#include "parser.h" #include "lexer.h" #include "number.h" #include Parser::Parser( Lexer &lex, Bu::Stream &rOut ) : lex( lex ), rOut( rOut ) { } Parser::~Parser() { } void Parser::parse() { for(;;) { Token t = lex.nextToken(); switch( t.eType ) { case Token::tEndOfInput: return; case Token::tEndOfLine: unwind(); if( !tsTerminal.isEmpty() ) { Bu::println( rOut, "%1").arg( *tsTerminal.peek().nVal ); } tsTerminal.clear(); break; case Token::tCommand: if( *t.sVal == "exit" || *t.sVal == "quit" ) return; else if( *t.sVal == "scale" ) { Token t2 = lex.nextToken(); if( t2.eType == Token::tEndOfLine ) { Bu::println( rOut, "Current scale: %1"). arg( lex.getScale() ); } else if( t2.eType == Token::tNumber ) { int32_t i = t2.nVal->toInt32(); lex.setScale( i ); if( i < 0 ) { Bu::println( rOut, "ERROR: You must provide a " "positive integer or zero as the parameter " "to scale."); } else { Bu::println( rOut, "Scale changed to: %1"). arg( lex.getScale() ); } } else { Bu::println( rOut, "ERROR: You must provide a number " "as the parameter to scale."); } } else if( *t.sVal == "radix" ) { Token t2 = lex.nextToken(); if( t2.eType == Token::tEndOfLine ) { Bu::println( rOut, "Current radix: %1"). arg( lex.getRadix() ); } else if( t2.eType == Token::tNumber ) { int32_t i = t2.nVal->toInt32(); if( i < 2 || i > 36 ) Bu::println( rOut, "ERROR: Radix must be between " "2 and 36 inclusive"); else { lex.setRadix( i ); Bu::println( rOut, "Radix changed to: %1"). arg( lex.getRadix() ); } } else { Bu::println( rOut, "You must provide a number as " "the parameter to radix."); } } else { Bu::println( rOut, "ERROR: Unknown command '%1'"). arg( *t.sVal ); } break; case Token::tNumber: tsTerminal.push( t ); break; default: if( tsNonTerminal.getSize() == 0 || getPriority( tsNonTerminal.peek().eType ) <= getPriority( t.eType ) ) { // Bu::println("Pushing non-terminal: %1").arg( t.eType ); tsNonTerminal.push( t ); // for( TokenStack::iterator i = tsTerminal.begin(); i; i++ ) Bu::print(" [%1]").arg( *(*i).nVal ); Bu::println(""); // for( TokenStack::iterator i = tsNonTerminal.begin(); i; i++ ) Bu::print(" <%1>").arg( (*i).eType ); Bu::println(""); } else { // Bu::println("Unwinding stack before pushing: %1").arg( t.eType ); unwind(); tsNonTerminal.push( t ); // for( TokenStack::iterator i = tsTerminal.begin(); i; i++ ) Bu::print(" [%1]").arg( *(*i).nVal ); Bu::println(""); // for( TokenStack::iterator i = tsNonTerminal.begin(); i; i++ ) Bu::print(" <%1>").arg( (*i).eType ); Bu::println(""); } break; } } } void Parser::unwind() { for(;;) { // for( TokenStack::iterator i = tsTerminal.begin(); i; i++ ) Bu::print(" [%1]").arg( *(*i).nVal ); Bu::println(""); // for( TokenStack::iterator i = tsNonTerminal.begin(); i; i++ ) Bu::print(" <%1>").arg( (*i).eType ); Bu::println(""); if( tsNonTerminal.isEmpty() ) return; if( tsTerminal.getSize() < reqTokens( tsNonTerminal.peek().eType ) ) { return; } Token t = tsNonTerminal.peekPop(); switch( t.eType ) { case Token::tPlus: { Token b = tsTerminal.peekPop(); Token a = tsTerminal.peekPop(); tsTerminal.push( Token( Token::tNumber, new Number( *a.nVal + *b.nVal ) ) ); } break; case Token::tMinus: { Token b = tsTerminal.peekPop(); Token a = tsTerminal.peekPop(); tsTerminal.push( Token( Token::tNumber, new Number( *a.nVal - *b.nVal ) ) ); } break; case Token::tMultiply: { Token b = tsTerminal.peekPop(); Token a = tsTerminal.peekPop(); tsTerminal.push( Token( Token::tNumber, new Number( *a.nVal * *b.nVal ) ) ); } break; case Token::tDivide: { Token b = tsTerminal.peekPop(); Token a = tsTerminal.peekPop(); tsTerminal.push( Token( Token::tNumber, new Number( *a.nVal / *b.nVal ) ) ); } break; case Token::tOpenParen: tsNonTerminal.push( t ); return; case Token::tCloseParen: unwind(); if( tsNonTerminal.peek().eType == Token::tOpenParen ) { tsNonTerminal.pop(); } else { throw Bu::ExceptionBase("Close paren found without open paren."); } break; case Token::tNumber: case Token::tString: case Token::tCommand: case Token::tEndOfLine: case Token::tEndOfInput: // These should never show up at all break; } } } int Parser::reqTokens( Token::Type eType ) { switch( eType ) { case Token::tPlus: case Token::tMinus: case Token::tDivide: case Token::tMultiply: return 2; case Token::tOpenParen: return 0; case Token::tCloseParen: return 1; default: return 0; } } int Parser::getPriority( Token::Type eType ) { switch( eType ) { case Token::tNumber: case Token::tString: case Token::tCommand: return 0; case Token::tPlus: case Token::tMinus: return 1; case Token::tDivide: case Token::tMultiply: return 2; case Token::tOpenParen: case Token::tCloseParen: return 3; case Token::tEndOfLine: case Token::tEndOfInput: return -1; default: throw Bu::ExceptionBase("Invalid type in getPriority"); } }