#include "config.h" #include "parser.h" #include "lexer.h" #include "number.h" #include "datafiles.h" #include #include Parser::Parser( Lexer &lex, Bu::Stream &rOut ) : lex( lex ), rOut( rOut ) { } Parser::~Parser() { } void Parser::parse() { for(;;) { lex.nextToken(); if( lex[0].eType == Token::tEndOfInput ) break; exprR(); reduce(); printState("Final"); tsParse.clear(); tsScript.clear(); } } void Parser::exprR() { exprP(); expr(); } void Parser::expr() { Bu::sio << "::expr " << lex[0] << Bu::sio.nl; if( lex[0].eType == Token::tEndOfInput ) return; switch( lex[0].eType ) { case Token::tEquals: throw Bu::ExceptionBase("misplaced equals."); break; case Token::tPlus: case Token::tMinus: case Token::tMultiply: case Token::tDivide: case Token::tModulus: Token t = lex[0]; lex.nextToken(); Bu::sio << "->expr " << t << " " << lex[0] << Bu::sio.nl; if( lex[0].eType == Token::tOpenParen ) { exprP(); shift( t ); reduce(); expr(); } else { if( lex[0].eType == Token::tNumber || lex[0].eType == Token::tVariable ) { Bu::sio << "->expr " << t << " " << lex[0] << " " << lex[1] << Bu::sio.nl; shift( lex[0] ); if( lex[1].eType&Token::mMetaOperator ) { if( getPriority(lex[1].eType) <= getPriority(t.eType) ) { shift( t ); reduce(); printState("reduce"); lex.nextToken(); expr(); } else { printState("no reduce"); lex.nextToken(); expr(); if( !tsParse.isEmpty() && tsParse.peek().eType != Token::tComputedValue ) { reduce(); printState("no reduce reduce"); } shift( t ); printState("post no reduce"); } } else { shift( t ); lex.nextToken(); printState("no next op"); } } else if( lex[0].eType == Token::tMinus ) { // This is negation Bu::sio << "next token: " << lex[0] << Bu::sio.nl; printState("inline-negate"); exprP(); printState("inline-negate-post"); shift( t ); printState("inline-negate-post2"); Bu::sio << "??? " << lex[0] << Bu::sio.nl; } } break; } } void Parser::exprP() { if( lex[0].eType == Token::tVariable && lex[1].eType == Token::tEquals ) { Token t = lex[0]; lex.nextToken( 2 ); exprR(); reduce(); printState("pre-equals"); shift( t ); shift( Token( Token::tEquals ) ); printState("post-equals"); reduce(); printState("post-equals-reduce"); return; } switch( lex[0].eType ) { case Token::tNumber: case Token::tVariable: shift( lex[0] ); lex.nextToken(); break; case Token::tOpenParen: shift( lex[0] ); lex.nextToken(); exprR(); if( lex[0].eType != Token::tCloseParen ) { Bu::sio << "::exprP " << lex[0] << Bu::sio.nl; throw Bu::ExceptionBase("Expected close paren"); } shift( lex[0] ); printState("closeParen"); reduce(); lex.nextToken(); printState("post closeParen"); break; case Token::tMinus: lex.nextToken(); exprP(); shift( Token( Token::tNegate ) ); reduce(); break; } } /* case Token::tCommand: lex.setMode( Lexer::modeCommand ); 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::tString ) { int32_t i = strtol( t2.sVal->getStr(), 0, 10 ); 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() ); for( VarHash::iterator i = hVars.begin(); i; i++ ) (*i).setScale( lex.getScale() ); nZero = Number( lex.getScale(), lex.getRadix() ); } } 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::tString ) { int32_t i = strtol( t2.sVal->getStr(), 0, 10 ); 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() ); hVars.clear(); nZero = Number( lex.getScale(), lex.getRadix() ); } } else { Bu::println( rOut, "You must provide a number as " "the parameter to radix."); } } else if( *t.sVal == "vars" ) { Bu::println( rOut, "Declared variables:"); for( VarHash::iterator i = hVars.begin(); i; i++ ) { Bu::println( rOut, " - %1 = %2"). arg( i.getKey() ).arg( *i ); } Bu::println( rOut, ""); } else if( *t.sVal == "help" || *t.sVal == "h" || *t.sVal == "?" ) { Bu::println( rOut, Datafiles::getString("parserhelp.txt") ); } else { Bu::println( rOut, "ERROR: Unknown command '%1'"). arg( *t.sVal ); } lex.setMode( Lexer::modeNormal ); break; */ void Parser::shift( const Token &t ) { tsParse.push( t ); } void Parser::reduce() { if( tsParse.isEmpty() || tsParse.peek().eType == Token::tOpenParen ) return; Token tOp = tsParse.peekPop(); switch( tOp.eType ) { case Token::tNumber: case Token::tVariable: tsScript.append( tOp ); tsParse.push( Token( Token::tComputedValue ) ); break; case Token::tComputedValue: tsParse.push( Token( Token::tComputedValue ) ); break; case Token::tPlus: case Token::tMinus: case Token::tDivide: case Token::tMultiply: case Token::tModulus: case Token::tEquals: for(int j = 0; j < 2; j++ ) { Token t = tsParse.peekPop(); if( t.eType == Token::tNumber || t.eType == Token::tVariable ) { tsScript.append( t ); } else if( t.eType == Token::tComputedValue ) { // Nope, we don't care } } tsScript.append( tOp ); shift( Token( Token::tComputedValue ) ); break; case Token::tNegate: { Token t = tsParse.peekPop(); if( t.eType != Token::tComputedValue ) tsScript.append( t ); tsScript.append( tOp ); shift( Token( Token::tComputedValue ) ); } break; case Token::tCloseParen: if( tsParse.peek().eType != Token::tComputedValue ) { printState("paren-innerReduce-pre"); reduce(); printState("paren-innerReduce-post"); } tsParse.pop(); if( tsParse.peek().eType == Token::tOpenParen ) { tsParse.pop(); shift( Token( Token::tComputedValue ) ); } else { throw Bu::ExceptionBase("Error?"); } break; } } int Parser::reqTokens( Token::Type eType ) { switch( eType ) { case Token::tPlus: case Token::tMinus: case Token::tDivide: case Token::tMultiply: case Token::tModulus: case Token::tEquals: 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::tVariable: case Token::tCommand: return 0; case Token::tPlus: case Token::tMinus: return 1; case Token::tDivide: case Token::tMultiply: case Token::tModulus: return 2; case Token::tOpenParen: case Token::tCloseParen: return 3; case Token::tEndOfLine: case Token::tEndOfInput: case Token::tEquals: return -1; default: throw Bu::ExceptionBase("Invalid type in getPriority"); } } void Parser::printState( const Bu::String &sTag ) { Bu::sio << "----------------" << Bu::sio.nl; Bu::sio << sTag << " stack:"; for( TokenStack::iterator i = tsParse.begin(); i; i++ ) { Bu::sio << " " << (*i); } Bu::sio << Bu::sio.nl; Bu::sio << sTag << " script:"; for( TokenStack::iterator i = tsScript.begin(); i; i++ ) { Bu::sio << " " << (*i); } Bu::sio << Bu::sio.nl; Bu::sio << "----------------" << Bu::sio.nl; }