From 04f56c12e82ea5228b2b65e68c46ed7f4563182b Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 23 Apr 2013 11:47:01 -0600 Subject: Variables work. --- src/lexer.cpp | 40 ++++++++++---------- src/parser.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/parser.h | 6 +++ src/token.cpp | 5 ++- src/token.h | 3 +- 5 files changed, 138 insertions(+), 30 deletions(-) diff --git a/src/lexer.cpp b/src/lexer.cpp index 3ebb0cf..46686c8 100644 --- a/src/lexer.cpp +++ b/src/lexer.cpp @@ -63,6 +63,26 @@ Token Lexer::nextToken() } 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] != ')'; + iBufPos++ ) + { + sTmp->append( sBuf[iBufPos] ); + } + return Token( Token::tVariable, sTmp ); + } + break; + + case '=': + iBufPos++; + return Token( Token::tEquals ); + case '+': iBufPos++; return Token( Token::tPlus ); @@ -115,26 +135,6 @@ Token Lexer::nextToken() delete sTmp; return Token( Token::tNumber, n ); } - else if( (sBuf[iBufPos]>=(ascRangeTop+1) && sBuf[iBufPos]<='z') || - (sBuf[iBufPos]>='A' && sBuf[iBufPos]<='Z') || - sBuf[iBufPos] == '_' ) - { - for( ; iBufPos < sBuf.getSize(); iBufPos++ ) - { - if( (sBuf[iBufPos]>='a' && sBuf[iBufPos]<='z') || - (sBuf[iBufPos]>='A' && sBuf[iBufPos]<='Z') || - (sBuf[iBufPos]>='0' && sBuf[iBufPos]<='9') || - sBuf[iBufPos] == '_' ) - { - sTmp->append( sBuf[iBufPos] ); - } - else - { - break; - } - } - return Token( Token::tString, sTmp ); - } else { sBuf.clear(); diff --git a/src/parser.cpp b/src/parser.cpp index 21ccc11..5bb0aa6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -28,7 +28,7 @@ void Parser::parse() unwind(); if( !tsTerminal.isEmpty() ) { - Bu::println( rOut, "%1").arg( *tsTerminal.peek().nVal ); + Bu::println( rOut, "%1").arg( deref( tsTerminal.peek() ) ); } tsTerminal.clear(); break; @@ -58,6 +58,9 @@ void Parser::parse() { 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 @@ -85,6 +88,8 @@ void Parser::parse() lex.setRadix( i ); Bu::println( rOut, "Radix changed to: %1"). arg( lex.getRadix() ); + hVars.clear(); + nZero = Number( lex.getScale(), lex.getRadix() ); } } else @@ -93,6 +98,47 @@ void Parser::parse() "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, + "All commands start with a '\\'. The following commands are defined:\n" + " \\help, \\h, \\? - This help\n" + " \\exit, \\quit - Exit the program\n" + " \\radix - Display the current radix (base)\n" + " \\radix - Set the radix to anything between 2 and 36 (inclusive)\n" + " \\scale - Display the current scale\n" + " \\scale - Set the current scale\n" + " \\vars - List all defined variables\n" + "\n" + "All variables must prefixed with a $ but otherwise can be used anywhere a\n" + "number can be used. To assign a variable use =, i.e.:\n" + " $amnt = $rate * 144000.09\n" + "\n" + "When using a radix greater than 10 all extended digits are lowercase letters\n" + "starting with 'a'. Upper case is not currently supported.\n" + "\n" + "All numbers are interpreted in the current radix, this means that you need to\n" + "set the radix using the current radix, even though the current value is aways\n" + "displayed in decimal. That is, to go to base 8 and back to base 10 you would:\n" + " \\radix 8\n" + " Radix changed to: 8\n" + " \\radix 12\n" + " Radix changed to: 10\n" + "\n" + "Changing the radix always clears all variables.\n" + ); + + } else { Bu::println( rOut, "ERROR: Unknown command '%1'"). @@ -101,6 +147,7 @@ void Parser::parse() break; case Token::tNumber: + case Token::tVariable: tsTerminal.push( t ); break; @@ -150,7 +197,9 @@ void Parser::unwind() Token b = tsTerminal.peekPop(); Token a = tsTerminal.peekPop(); tsTerminal.push( - Token( Token::tNumber, new Number( *a.nVal + *b.nVal ) ) + Token( Token::tNumber, + new Number( deref(a) + deref(b) ) + ) ); } break; @@ -160,7 +209,9 @@ void Parser::unwind() Token b = tsTerminal.peekPop(); Token a = tsTerminal.peekPop(); tsTerminal.push( - Token( Token::tNumber, new Number( *a.nVal - *b.nVal ) ) + Token( Token::tNumber, + new Number( deref(a) - deref(b) ) + ) ); } break; @@ -170,7 +221,9 @@ void Parser::unwind() Token b = tsTerminal.peekPop(); Token a = tsTerminal.peekPop(); tsTerminal.push( - Token( Token::tNumber, new Number( *a.nVal * *b.nVal ) ) + Token( Token::tNumber, + new Number( deref(a) * deref(b) ) + ) ); } break; @@ -180,7 +233,9 @@ void Parser::unwind() Token b = tsTerminal.peekPop(); Token a = tsTerminal.peekPop(); tsTerminal.push( - Token( Token::tNumber, new Number( *a.nVal / *b.nVal ) ) + Token( Token::tNumber, + new Number( deref(a) / deref(b) ) + ) ); } break; @@ -202,8 +257,28 @@ void Parser::unwind() } break; + case Token::tEquals: + { + Token b = tsTerminal.peekPop(); + Token a = tsTerminal.peekPop(); + if( a.eType != Token::tVariable ) + { + Bu::println("The left hand side of a = must be a variable."); + tsTerminal.clear(); + tsNonTerminal.clear(); + return; + } + hVars.insert( *a.sVal, deref( b ) ); + tsTerminal.push( + Token( Token::tNumber, + new Number( deref( b ) ) + ) + ); + } + break; + case Token::tNumber: - case Token::tString: + case Token::tVariable: case Token::tCommand: case Token::tEndOfLine: case Token::tEndOfInput: @@ -221,6 +296,7 @@ int Parser::reqTokens( Token::Type eType ) case Token::tMinus: case Token::tDivide: case Token::tMultiply: + case Token::tEquals: return 2; case Token::tOpenParen: @@ -239,8 +315,9 @@ int Parser::getPriority( Token::Type eType ) switch( eType ) { case Token::tNumber: - case Token::tString: + case Token::tVariable: case Token::tCommand: + case Token::tEquals: return 0; case Token::tPlus: @@ -264,3 +341,26 @@ int Parser::getPriority( Token::Type eType ) } } +Number &Parser::deref( Token &t ) +{ + if( t.eType == Token::tNumber ) + { + return *t.nVal; + } + else if( t.eType == Token::tVariable ) + { + try + { + return hVars.get( *t.sVal ); + } + catch(...) + { + return nZero; + } + } + else + { + throw Bu::ExceptionBase("Element was not a number or variable."); + } +} + diff --git a/src/parser.h b/src/parser.h index 5563613..2b1a4af 100644 --- a/src/parser.h +++ b/src/parser.h @@ -2,7 +2,9 @@ #define PARSER_H #include +#include #include "token.h" +#include "number.h" namespace Bu { @@ -23,13 +25,17 @@ private: void unwind(); int reqTokens( Token::Type eType ); int getPriority( Token::Type eType ); + Number &deref( Token &t ); private: Lexer &lex; Bu::Stream &rOut; typedef Bu::List TokenStack; + typedef Bu::Hash VarHash; TokenStack tsTerminal; TokenStack tsNonTerminal; + Number nZero; + VarHash hVars; }; #endif diff --git a/src/token.cpp b/src/token.cpp index d7fbe88..019e54d 100644 --- a/src/token.cpp +++ b/src/token.cpp @@ -38,7 +38,7 @@ Token::~Token() delete nVal; break; - case tString: + case tVariable: case tCommand: delete sVal; break; @@ -53,7 +53,7 @@ Bu::Formatter &operator<<( Bu::Formatter &f, Token::Type eType ) switch( eType ) { case Token::tNumber: return f << "num"; - case Token::tString: return f << "str"; + case Token::tVariable: return f << "var"; case Token::tCommand: return f << "cmd"; case Token::tPlus: return f << "+"; case Token::tMinus: return f << "-"; @@ -61,6 +61,7 @@ Bu::Formatter &operator<<( Bu::Formatter &f, Token::Type eType ) case Token::tMultiply: return f << "*"; case Token::tOpenParen: return f << "("; case Token::tCloseParen: return f << ")"; + case Token::tEquals: return f << "="; case Token::tEndOfLine: return f << "eol"; case Token::tEndOfInput: return f << "eoi"; diff --git a/src/token.h b/src/token.h index 3b5caff..05a610a 100644 --- a/src/token.h +++ b/src/token.h @@ -14,7 +14,7 @@ public: enum Type { tNumber, - tString, + tVariable, tCommand, tPlus, tMinus, @@ -22,6 +22,7 @@ public: tMultiply, tOpenParen, tCloseParen, + tEquals, tEndOfLine, -- cgit v1.2.3