#include "config.h" #include "parser.h" #include "lexer.h" #include "number.h" #include "datafiles.h" #include "expression.h" #include #include //#define DEBUG_MODE 1 #ifdef DEBUG_MODE #define DBG( x ) { x; } (void)0 #else #define DBG( x ) (void)0 #endif Parser::Parser( Lexer &lex ) : lex( lex ) { } Parser::~Parser() { } Expression *Parser::parse() { pCurExp = new Expression(); statement(); while( !tsTerminal.isEmpty() ) { reduce(); } printState("Final"); tsTerminal.clear(); tsNonTerminal.clear(); Expression *pTmp = pCurExp; pCurExp = NULL; return pTmp; } void Parser::exprR() { exprP(); for(;;) { expr(); if( !(lex[0].eType & Token::mMetaOperator) ) break; } } void Parser::expr() { DBG( 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(); DBG( 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 ) { DBG( Bu::sio << "->expr " << t << " " << lex[0] << " " << lex[1] << Bu::sio.nl ); shift( lex[0] ); shift( t ); if( lex[1].eType&Token::mMetaOperator ) { if( getPriority(lex[1].eType) < getPriority(t.eType) ) { while( !tsTerminal.isEmpty() ) { reduce(); } printState("reduce"); lex.nextToken(); // expr(); } else { printState("no reduce"); lex.nextToken(); // expr(); /* if( !tsNonTerminal.isEmpty() && tsParse.peek().eType != Token::tComputedValue ) { //reduce(); //printState("no reduce reduce"); }*/ printState("post no reduce"); } } else { lex.nextToken(); printState("no next op"); } } else if( lex[0].eType == Token::tMinus ) { // This is negation DBG( Bu::sio << "next token: " << lex[0] << Bu::sio.nl ); printState("inline-negate"); exprP(); printState("inline-negate-post"); shift( t ); printState("inline-negate-post2"); DBG( 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; } DBG( Bu::sio << "exprP on " << lex[0] << Bu::sio.nl ); 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 ) { DBG( 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; } } void Parser::statement() { if( (lex[0].eType&Token::mMetaCmd) ) { lex.setMode( Lexer::modeCommand ); output( lex[0] ); for(;;) { lex.nextToken(); if( lex[0].eType == Token::tEndOfLine || lex[0].eType == Token::tEndOfInput ) break; output( lex[0] ); } lex.setMode( Lexer::modeNormal ); } else { exprR(); reduce(); } } /* 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 ) { if( (t.eType&(Token::mMetaOperator|Token::mMetaAltOp)) || t.eType==Token::tCloseParen ) tsTerminal.push( t ); else tsNonTerminal.push( t ); } void Parser::reduce() { if( tsTerminal.isEmpty() ) { DBG( Bu::sio << "reduce: terminal stack empty." << Bu::sio.nl ); if( !tsNonTerminal.isEmpty() ) { DBG( Bu::sio << " : non-terminal stack non-empty, pushing item." << Bu::sio.nl ); output( tsNonTerminal.peekPop() ); } return; } if( tsNonTerminal.peek().eType == Token::tOpenParen ) return; Token tOp = tsTerminal.peekPop(); DBG( Bu::sio << "recuding on " << tOp << Bu::sio.nl ); switch( tOp.eType ) { /* case Token::tNumber: case Token::tVariable: output( 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: { Token a = tsNonTerminal.peekPop(); Token b = tsNonTerminal.peekPop(); output( b ); output( a ); } output( tOp ); shift( Token( Token::tComputedValue ) ); break; case Token::tNegate: { Token t = tsNonTerminal.peekPop(); if( t.eType != Token::tComputedValue ) output( t ); output( tOp ); shift( Token( Token::tComputedValue ) ); } break; case Token::tCloseParen: if( tsNonTerminal.peek().eType != Token::tComputedValue ) { printState("paren-innerReduce-pre"); reduce(); printState("paren-innerReduce-post"); } tsNonTerminal.pop(); if( tsNonTerminal.peek().eType == Token::tOpenParen ) { tsNonTerminal.pop(); shift( Token( Token::tComputedValue ) ); } else { throw Bu::ExceptionBase("Error?"); } break; } } void Parser::output( const Token &t ) { if( t.eType == Token::tComputedValue ) return; pCurExp->append( t ); } 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: 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 ) { #ifdef DEBUG_MODE Bu::sio << "----------------" << Bu::sio.nl; Bu::sio << sTag << " non-terminals:"; for( TokenStack::iterator i = tsNonTerminal.begin(); i; i++ ) { Bu::sio << " " << (*i); } Bu::sio << Bu::sio.nl; Bu::sio << sTag << " terminal:"; for( TokenStack::iterator i = tsTerminal.begin(); i; i++ ) { Bu::sio << " " << (*i); } Bu::sio << Bu::sio.nl; Bu::sio << sTag << " script:"; for( TokenStack::iterator i = pCurExp->begin(); i; i++ ) { Bu::sio << " " << (*i); } Bu::sio << Bu::sio.nl; Bu::sio << "----------------" << Bu::sio.nl; #endif }