From 89eeeff54f0b3ce30be5b046fc3899fdeb5ebb40 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sat, 17 Feb 2007 16:31:55 +0000 Subject: Tweaked the stream classes, added an example, and the begining of a formula parser. --- src/formula.cpp | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/formula.h | 62 ++++++++++++++++++++ src/sbuffer.cpp | 5 ++ src/sbuffer.h | 1 + src/sfile.cpp | 5 ++ src/sfile.h | 1 + src/stream.cpp | 1 + src/stream.h | 1 + src/tests/formula.cpp | 13 +++++ 9 files changed, 246 insertions(+) create mode 100644 src/formula.cpp create mode 100644 src/formula.h create mode 100644 src/tests/formula.cpp (limited to 'src') diff --git a/src/formula.cpp b/src/formula.cpp new file mode 100644 index 0000000..7cc1804 --- /dev/null +++ b/src/formula.cpp @@ -0,0 +1,157 @@ +#include "formula.h" + +subExceptionDef( ParseException ); + +Formula::Formula() +{ +} + +Formula::~Formula() +{ +} + +double Formula::run( const char *sFormula ) +{ + sBuf.write( sFormula, strlen( sFormula ) ); + sBuf.setPos( 0 ); + + nState = 0; + for(;;) + { + tLook = nextToken(); + if( tLook.nSym == symEOS ) + break; + state(); + } + printf("\n"); + return 0.0; +} + +void Formula::state() +{ + switch( nState ) + { + case 0: // initial expr + switch( tLook.nSym ) + { + case symNumber: + push(); + nState = 1; + break; + } + break; + + case 1: // binary operator + switch( tLook.nSym ) + { + case symAdd: + case symSubtract: + push(); + nState = 2; + break; + + case symMultiply: + case symDivide: + push(); + nState = 3; + break; + } + break; + + case 2: // add/subtract + break; + } +} + +void Formula::push() +{ + printToken( tLook ); + sToken.push( tLook ); +} + +Formula::Token Formula::nextToken() +{ + char cbuf; + for(;;) + { + if( sBuf.isEOS() ) + return Token( symEOS ); + + sBuf.read( &cbuf, 1 ); + switch( cbuf ) + { + case '+': + return Token( symAdd ); + + case '-': + return Token( symSubtract ); + + case '*': + return Token( symMultiply ); + + case '/': + return Token( symDivide ); + + case '(': + return Token( symOpenParen ); + + case ')': + return Token( symCloseParen ); + + case ' ': + case '\t': + case '\n': + case '\r': + break; + + default: + if( cbuf == '.' || (cbuf >= '0' && cbuf <= '9') ) + { + char num[50]; + int nPos = 0; + bool bDot = false; + + for(;;) + { + num[nPos++] = cbuf; + if( cbuf == '.' ) + { + if( bDot == false ) + bDot = true; + else + throw ParseException( + "Numbers cannot have more than one " + ". in them." + ); + } + sBuf.read( &cbuf, 1 ); + if( (cbuf != '.' && (cbuf < '0' || cbuf > '9')) || + sBuf.isEOS() ) + { + if( !sBuf.isEOS() ) sBuf.seek( -1 ); + num[nPos] = '\0'; + return Token( symNumber, strtod( num, NULL ) ); + } + } + } + break; + } + } +} + +void Formula::printToken( Token &tok ) +{ + switch( tok.nSym ) + { + case symEOS: printf("[EOS] "); break; + case symAdd: printf("+ "); break; + case symSubtract: printf("- "); break; + case symMultiply: printf("* "); break; + case symDivide: printf("/ "); break; + case symOpenParen: printf("( "); break; + case symCloseParen: printf(") "); break; + case symNumber: printf("%f ", tok.val.num ); break; + default: printf("??? "); break; + } +} + diff --git a/src/formula.h b/src/formula.h new file mode 100644 index 0000000..1eccd36 --- /dev/null +++ b/src/formula.h @@ -0,0 +1,62 @@ +#ifndef FORMULA_H +#define FORMULA_H + +#include + +#include +#include "sbuffer.h" + +#include "exceptionbase.h" + +subExceptionDecl( ParseException ); + +/** + * + */ +class Formula +{ +public: + Formula(); + virtual ~Formula(); + + double run( const char *sFormula ); + +private: + enum + { + symEOS, + symAdd, + symSubtract, + symMultiply, + symDivide, + symOpenParen, + symCloseParen, + symNumber, + symVariable + }; + + typedef struct Token + { + Token() {} + Token( uint8_t nSym ) : nSym( nSym ) { } + Token( uint8_t nSym, double dNum ) : nSym( nSym ) { val.num = dNum; } + uint8_t nSym; + union + { + double num; + } val; + } Token; + + std::stack sToken; + Token tLook; + int nState; + SBuffer sBuf; + +private: + void push(); + void state(); + Token nextToken(); + void printToken( Token &tok ); +}; + +#endif diff --git a/src/sbuffer.cpp b/src/sbuffer.cpp index 0ed0f47..f84f8a3 100644 --- a/src/sbuffer.cpp +++ b/src/sbuffer.cpp @@ -60,3 +60,8 @@ void SBuffer::setPosEnd( long pos ) nPos = fbData.getLength() - pos; } +bool SBuffer::isEOS() +{ + return nPos == fbData.getLength(); +} + diff --git a/src/sbuffer.h b/src/sbuffer.h index 5352bda..65feb71 100644 --- a/src/sbuffer.h +++ b/src/sbuffer.h @@ -24,6 +24,7 @@ public: virtual void seek( long offset ); virtual void setPos( long pos ); virtual void setPosEnd( long pos ); + virtual bool isEOS(); FlexBuf &getBuffer() { diff --git a/src/sfile.cpp b/src/sfile.cpp index 3f5144d..f1de03c 100644 --- a/src/sfile.cpp +++ b/src/sfile.cpp @@ -67,3 +67,8 @@ void SFile::setPosEnd( long pos ) fseek( fh, pos, SEEK_END ); } +bool SFile::isEOS() +{ + return feof( fh ); +} + diff --git a/src/sfile.h b/src/sfile.h index f276ad2..b51e5bc 100644 --- a/src/sfile.h +++ b/src/sfile.h @@ -19,6 +19,7 @@ public: virtual void seek( long offset ); virtual void setPos( long pos ); virtual void setPosEnd( long pos ); + virtual bool isEOS(); private: FILE *fh; diff --git a/src/stream.cpp b/src/stream.cpp index 99c25f2..856a58d 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -7,3 +7,4 @@ Stream::Stream() Stream::~Stream() { } + diff --git a/src/stream.h b/src/stream.h index 32e5432..e086e28 100644 --- a/src/stream.h +++ b/src/stream.h @@ -18,6 +18,7 @@ public: virtual void seek( long offset ) = 0; virtual void setPos( long pos ) = 0; virtual void setPosEnd( long pos ) = 0; + virtual bool isEOS() = 0; private: diff --git a/src/tests/formula.cpp b/src/tests/formula.cpp new file mode 100644 index 0000000..599a264 --- /dev/null +++ b/src/tests/formula.cpp @@ -0,0 +1,13 @@ +#include "formula.h" + +int main( int argc, char *argv[] ) +{ + if( argc < 2 ) return 0; + + Formula f; + double dOut = f.run( argv[1] ); + printf("Final: %f\n", dOut ); + + return 0; +} + -- cgit v1.2.3