#include "lexer.h" #include "token.h" #include "number.h" #include Lexer::Lexer( Bu::Stream &rIn ) : rIn( rIn ), iBufPos( -1 ), iScale( 0 ), iRadix( 10 ), numRangeTop('9'), ascRangeTop('a'-1), eMode( modeNormal ), iLookAheadSize( 2 ), iLookAheadUsed( 0 ), iLookAheadStart( 0 ), aLookAhead( 0 ) { aLookAhead = new Token[iLookAheadSize]; } Lexer::~Lexer() { } void Lexer::nextToken( int iCount ) { if( iLookAheadUsed-iCount <= 0 ) { iLookAheadUsed = 0; iLookAheadStart = 0; } else { iLookAheadStart = (iLookAheadStart+iCount)%iLookAheadSize; iLookAheadUsed -= iCount; } } void Lexer::fillToken() { switch( eMode ) { case modeNormal: aLookAhead[(iLookAheadUsed+iLookAheadStart)%iLookAheadSize] = nextTokenNormal(); break; case modeCommand: aLookAhead[(iLookAheadUsed+iLookAheadStart)%iLookAheadSize] = nextTokenCommand(); break; default: throw Bu::ExceptionBase("Invalid mode."); } } Token Lexer::nextTokenNormal() { for(;;) { if( iBufPos < 0 ) { if( rIn.isEos() ) return Token( Token::tEndOfInput ); sBuf = rIn.readLine(); if( sBuf.getSize() == 0 ) { iBufPos = -1; continue; } iBufPos = 0; } if( iBufPos >= sBuf.getSize() ) { iBufPos = -1; return Token( Token::tEndOfLine ); } switch( sBuf[iBufPos] ) { case ' ': case '\t': iBufPos++; break; case '\\': { Bu::String *sTmp = new Bu::String(); for( iBufPos++; iBufPos < sBuf.getSize() && sBuf[iBufPos] != ' ' && sBuf[iBufPos] != '\t'; iBufPos++ ) { sTmp->append( sBuf[iBufPos] ); } if( *sTmp == "quit" || *sTmp == "exit" ) return Token( Token::tCmdExit ); else if( *sTmp == "scale" ) return Token( Token::tCmdScale ); else if( *sTmp == "radix" ) return Token( Token::tCmdRadix ); return Token( Token::tCmdExtended, sTmp ); } break; case '$': { Bu::String *sTmp = new Bu::String(); for( iBufPos++; iBufPos < sBuf.getSize() && sBuf[iBufPos] != ' ' && sBuf[iBufPos] != '\t' && sBuf[iBufPos] != '+' && sBuf[iBufPos] != '-' && sBuf[iBufPos] != '*' && sBuf[iBufPos] != '/' && sBuf[iBufPos] != '%' && sBuf[iBufPos] != '=' && sBuf[iBufPos] != '(' && sBuf[iBufPos] != ')'; iBufPos++ ) { sTmp->append( sBuf[iBufPos] ); } return Token( Token::tVariable, sTmp ); } break; case '=': iBufPos++; return Token( Token::tEquals ); case '+': iBufPos++; return Token( Token::tPlus ); case '-': iBufPos++; return Token( Token::tMinus ); case '*': iBufPos++; return Token( Token::tMultiply ); case '/': iBufPos++; return Token( Token::tDivide ); case '%': iBufPos++; return Token( Token::tModulus ); case '(': iBufPos++; return Token( Token::tOpenParen ); case ')': iBufPos++; return Token( Token::tCloseParen ); default: { Bu::String *sTmp = new Bu::String(); if( (sBuf[iBufPos] >= '0' && sBuf[iBufPos] <= numRangeTop) || (sBuf[iBufPos] >= 'a' && sBuf[iBufPos] <= ascRangeTop) || sBuf[iBufPos] == '.' ) { for( ; iBufPos < sBuf.getSize() ; iBufPos++ ) { if( (sBuf[iBufPos] >= '0' && sBuf[iBufPos] <= numRangeTop) || (sBuf[iBufPos] >= 'a' && sBuf[iBufPos] <= ascRangeTop) || sBuf[iBufPos] == '.' ) { sTmp->append( sBuf[iBufPos] ); } else { break; } } Number *n = new Number( *sTmp, iScale, iRadix ); delete sTmp; return Token( Token::tNumber, n ); } else { sBuf.clear(); throw Bu::ExceptionBase( "Invalid character discovered!"); } } break; } } } Token Lexer::nextTokenCommand() { for(;;) { if( iBufPos >= sBuf.getSize() ) { iBufPos = -1; return Token( Token::tCmdEndParams ); } if( iBufPos < 0 ) { if( rIn.isEos() ) return Token( Token::tCmdEndParams ); sBuf = rIn.readLine(); if( sBuf.getSize() == 0 ) { iBufPos = -1; continue; } iBufPos = 0; } //Bu::println("Testing char '%1' at %2").arg( sBuf[iBufPos] ).arg( iBufPos ); switch( sBuf[iBufPos] ) { case ' ': case '\t': iBufPos++; break; default: { Bu::String *sTmp = new Bu::String(); for( ; iBufPos < sBuf.getSize() ; iBufPos++ ) { if( sBuf[iBufPos] == ' ' || sBuf[iBufPos] == '\t' ) break; sTmp->append( sBuf[iBufPos] ); } return Token( Token::tCmdParam, sTmp ); } break; } } } void Lexer::setRadix( int i ) { iRadix = i; if( iRadix <= 10 ) { numRangeTop = '0'+iRadix-1; ascRangeTop = 'a'-1; } else { numRangeTop = '9'; ascRangeTop = 'a'+iRadix-11; } } Token &Lexer::operator[]( int iIdx ) { while( iIdx >= iLookAheadUsed ) { fillToken(); iLookAheadUsed++; } return aLookAhead[(iLookAheadStart+iIdx)%iLookAheadSize]; }