diff options
| -rw-r--r-- | src/lexer.cpp | 40 | ||||
| -rw-r--r-- | src/parser.cpp | 114 | ||||
| -rw-r--r-- | src/parser.h | 6 | ||||
| -rw-r--r-- | src/token.cpp | 5 | ||||
| -rw-r--r-- | 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() | |||
| 63 | } | 63 | } |
| 64 | break; | 64 | break; |
| 65 | 65 | ||
| 66 | case '$': | ||
| 67 | { | ||
| 68 | Bu::String *sTmp = new Bu::String(); | ||
| 69 | for( iBufPos++; iBufPos < sBuf.getSize() && | ||
| 70 | sBuf[iBufPos] != ' ' && sBuf[iBufPos] != '\t' && | ||
| 71 | sBuf[iBufPos] != '+' && sBuf[iBufPos] != '-' && | ||
| 72 | sBuf[iBufPos] != '*' && sBuf[iBufPos] != '/' && | ||
| 73 | sBuf[iBufPos] != '(' && sBuf[iBufPos] != ')'; | ||
| 74 | iBufPos++ ) | ||
| 75 | { | ||
| 76 | sTmp->append( sBuf[iBufPos] ); | ||
| 77 | } | ||
| 78 | return Token( Token::tVariable, sTmp ); | ||
| 79 | } | ||
| 80 | break; | ||
| 81 | |||
| 82 | case '=': | ||
| 83 | iBufPos++; | ||
| 84 | return Token( Token::tEquals ); | ||
| 85 | |||
| 66 | case '+': | 86 | case '+': |
| 67 | iBufPos++; | 87 | iBufPos++; |
| 68 | return Token( Token::tPlus ); | 88 | return Token( Token::tPlus ); |
| @@ -115,26 +135,6 @@ Token Lexer::nextToken() | |||
| 115 | delete sTmp; | 135 | delete sTmp; |
| 116 | return Token( Token::tNumber, n ); | 136 | return Token( Token::tNumber, n ); |
| 117 | } | 137 | } |
| 118 | else if( (sBuf[iBufPos]>=(ascRangeTop+1) && sBuf[iBufPos]<='z') || | ||
| 119 | (sBuf[iBufPos]>='A' && sBuf[iBufPos]<='Z') || | ||
| 120 | sBuf[iBufPos] == '_' ) | ||
| 121 | { | ||
| 122 | for( ; iBufPos < sBuf.getSize(); iBufPos++ ) | ||
| 123 | { | ||
| 124 | if( (sBuf[iBufPos]>='a' && sBuf[iBufPos]<='z') || | ||
| 125 | (sBuf[iBufPos]>='A' && sBuf[iBufPos]<='Z') || | ||
| 126 | (sBuf[iBufPos]>='0' && sBuf[iBufPos]<='9') || | ||
| 127 | sBuf[iBufPos] == '_' ) | ||
| 128 | { | ||
| 129 | sTmp->append( sBuf[iBufPos] ); | ||
| 130 | } | ||
| 131 | else | ||
| 132 | { | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | return Token( Token::tString, sTmp ); | ||
| 137 | } | ||
| 138 | else | 138 | else |
| 139 | { | 139 | { |
| 140 | sBuf.clear(); | 140 | 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() | |||
| 28 | unwind(); | 28 | unwind(); |
| 29 | if( !tsTerminal.isEmpty() ) | 29 | if( !tsTerminal.isEmpty() ) |
| 30 | { | 30 | { |
| 31 | Bu::println( rOut, "%1").arg( *tsTerminal.peek().nVal ); | 31 | Bu::println( rOut, "%1").arg( deref( tsTerminal.peek() ) ); |
| 32 | } | 32 | } |
| 33 | tsTerminal.clear(); | 33 | tsTerminal.clear(); |
| 34 | break; | 34 | break; |
| @@ -58,6 +58,9 @@ void Parser::parse() | |||
| 58 | { | 58 | { |
| 59 | Bu::println( rOut, "Scale changed to: %1"). | 59 | Bu::println( rOut, "Scale changed to: %1"). |
| 60 | arg( lex.getScale() ); | 60 | arg( lex.getScale() ); |
| 61 | for( VarHash::iterator i = hVars.begin(); i; i++ ) | ||
| 62 | (*i).setScale( lex.getScale() ); | ||
| 63 | nZero = Number( lex.getScale(), lex.getRadix() ); | ||
| 61 | } | 64 | } |
| 62 | } | 65 | } |
| 63 | else | 66 | else |
| @@ -85,6 +88,8 @@ void Parser::parse() | |||
| 85 | lex.setRadix( i ); | 88 | lex.setRadix( i ); |
| 86 | Bu::println( rOut, "Radix changed to: %1"). | 89 | Bu::println( rOut, "Radix changed to: %1"). |
| 87 | arg( lex.getRadix() ); | 90 | arg( lex.getRadix() ); |
| 91 | hVars.clear(); | ||
| 92 | nZero = Number( lex.getScale(), lex.getRadix() ); | ||
| 88 | } | 93 | } |
| 89 | } | 94 | } |
| 90 | else | 95 | else |
| @@ -93,6 +98,47 @@ void Parser::parse() | |||
| 93 | "the parameter to radix."); | 98 | "the parameter to radix."); |
| 94 | } | 99 | } |
| 95 | } | 100 | } |
| 101 | else if( *t.sVal == "vars" ) | ||
| 102 | { | ||
| 103 | Bu::println( rOut, "Declared variables:"); | ||
| 104 | for( VarHash::iterator i = hVars.begin(); i; i++ ) | ||
| 105 | { | ||
| 106 | Bu::println( rOut, " - %1 = %2"). | ||
| 107 | arg( i.getKey() ).arg( *i ); | ||
| 108 | } | ||
| 109 | Bu::println( rOut, ""); | ||
| 110 | } | ||
| 111 | else if( *t.sVal == "help" || *t.sVal == "h" || *t.sVal == "?" ) | ||
| 112 | { | ||
| 113 | Bu::println( rOut, | ||
| 114 | "All commands start with a '\\'. The following commands are defined:\n" | ||
| 115 | " \\help, \\h, \\? - This help\n" | ||
| 116 | " \\exit, \\quit - Exit the program\n" | ||
| 117 | " \\radix - Display the current radix (base)\n" | ||
| 118 | " \\radix <num> - Set the radix to anything between 2 and 36 (inclusive)\n" | ||
| 119 | " \\scale - Display the current scale\n" | ||
| 120 | " \\scale <num> - Set the current scale\n" | ||
| 121 | " \\vars - List all defined variables\n" | ||
| 122 | "\n" | ||
| 123 | "All variables must prefixed with a $ but otherwise can be used anywhere a\n" | ||
| 124 | "number can be used. To assign a variable use =, i.e.:\n" | ||
| 125 | " $amnt = $rate * 144000.09\n" | ||
| 126 | "\n" | ||
| 127 | "When using a radix greater than 10 all extended digits are lowercase letters\n" | ||
| 128 | "starting with 'a'. Upper case is not currently supported.\n" | ||
| 129 | "\n" | ||
| 130 | "All numbers are interpreted in the current radix, this means that you need to\n" | ||
| 131 | "set the radix using the current radix, even though the current value is aways\n" | ||
| 132 | "displayed in decimal. That is, to go to base 8 and back to base 10 you would:\n" | ||
| 133 | " \\radix 8\n" | ||
| 134 | " Radix changed to: 8\n" | ||
| 135 | " \\radix 12\n" | ||
| 136 | " Radix changed to: 10\n" | ||
| 137 | "\n" | ||
| 138 | "Changing the radix always clears all variables.\n" | ||
| 139 | ); | ||
| 140 | |||
| 141 | } | ||
| 96 | else | 142 | else |
| 97 | { | 143 | { |
| 98 | Bu::println( rOut, "ERROR: Unknown command '%1'"). | 144 | Bu::println( rOut, "ERROR: Unknown command '%1'"). |
| @@ -101,6 +147,7 @@ void Parser::parse() | |||
| 101 | break; | 147 | break; |
| 102 | 148 | ||
| 103 | case Token::tNumber: | 149 | case Token::tNumber: |
| 150 | case Token::tVariable: | ||
| 104 | tsTerminal.push( t ); | 151 | tsTerminal.push( t ); |
| 105 | break; | 152 | break; |
| 106 | 153 | ||
| @@ -150,7 +197,9 @@ void Parser::unwind() | |||
| 150 | Token b = tsTerminal.peekPop(); | 197 | Token b = tsTerminal.peekPop(); |
| 151 | Token a = tsTerminal.peekPop(); | 198 | Token a = tsTerminal.peekPop(); |
| 152 | tsTerminal.push( | 199 | tsTerminal.push( |
| 153 | Token( Token::tNumber, new Number( *a.nVal + *b.nVal ) ) | 200 | Token( Token::tNumber, |
| 201 | new Number( deref(a) + deref(b) ) | ||
| 202 | ) | ||
| 154 | ); | 203 | ); |
| 155 | } | 204 | } |
| 156 | break; | 205 | break; |
| @@ -160,7 +209,9 @@ void Parser::unwind() | |||
| 160 | Token b = tsTerminal.peekPop(); | 209 | Token b = tsTerminal.peekPop(); |
| 161 | Token a = tsTerminal.peekPop(); | 210 | Token a = tsTerminal.peekPop(); |
| 162 | tsTerminal.push( | 211 | tsTerminal.push( |
| 163 | Token( Token::tNumber, new Number( *a.nVal - *b.nVal ) ) | 212 | Token( Token::tNumber, |
| 213 | new Number( deref(a) - deref(b) ) | ||
| 214 | ) | ||
| 164 | ); | 215 | ); |
| 165 | } | 216 | } |
| 166 | break; | 217 | break; |
| @@ -170,7 +221,9 @@ void Parser::unwind() | |||
| 170 | Token b = tsTerminal.peekPop(); | 221 | Token b = tsTerminal.peekPop(); |
| 171 | Token a = tsTerminal.peekPop(); | 222 | Token a = tsTerminal.peekPop(); |
| 172 | tsTerminal.push( | 223 | tsTerminal.push( |
| 173 | Token( Token::tNumber, new Number( *a.nVal * *b.nVal ) ) | 224 | Token( Token::tNumber, |
| 225 | new Number( deref(a) * deref(b) ) | ||
| 226 | ) | ||
| 174 | ); | 227 | ); |
| 175 | } | 228 | } |
| 176 | break; | 229 | break; |
| @@ -180,7 +233,9 @@ void Parser::unwind() | |||
| 180 | Token b = tsTerminal.peekPop(); | 233 | Token b = tsTerminal.peekPop(); |
| 181 | Token a = tsTerminal.peekPop(); | 234 | Token a = tsTerminal.peekPop(); |
| 182 | tsTerminal.push( | 235 | tsTerminal.push( |
| 183 | Token( Token::tNumber, new Number( *a.nVal / *b.nVal ) ) | 236 | Token( Token::tNumber, |
| 237 | new Number( deref(a) / deref(b) ) | ||
| 238 | ) | ||
| 184 | ); | 239 | ); |
| 185 | } | 240 | } |
| 186 | break; | 241 | break; |
| @@ -202,8 +257,28 @@ void Parser::unwind() | |||
| 202 | } | 257 | } |
| 203 | break; | 258 | break; |
| 204 | 259 | ||
| 260 | case Token::tEquals: | ||
| 261 | { | ||
| 262 | Token b = tsTerminal.peekPop(); | ||
| 263 | Token a = tsTerminal.peekPop(); | ||
| 264 | if( a.eType != Token::tVariable ) | ||
| 265 | { | ||
| 266 | Bu::println("The left hand side of a = must be a variable."); | ||
| 267 | tsTerminal.clear(); | ||
| 268 | tsNonTerminal.clear(); | ||
| 269 | return; | ||
| 270 | } | ||
| 271 | hVars.insert( *a.sVal, deref( b ) ); | ||
| 272 | tsTerminal.push( | ||
| 273 | Token( Token::tNumber, | ||
| 274 | new Number( deref( b ) ) | ||
| 275 | ) | ||
| 276 | ); | ||
| 277 | } | ||
| 278 | break; | ||
| 279 | |||
| 205 | case Token::tNumber: | 280 | case Token::tNumber: |
| 206 | case Token::tString: | 281 | case Token::tVariable: |
| 207 | case Token::tCommand: | 282 | case Token::tCommand: |
| 208 | case Token::tEndOfLine: | 283 | case Token::tEndOfLine: |
| 209 | case Token::tEndOfInput: | 284 | case Token::tEndOfInput: |
| @@ -221,6 +296,7 @@ int Parser::reqTokens( Token::Type eType ) | |||
| 221 | case Token::tMinus: | 296 | case Token::tMinus: |
| 222 | case Token::tDivide: | 297 | case Token::tDivide: |
| 223 | case Token::tMultiply: | 298 | case Token::tMultiply: |
| 299 | case Token::tEquals: | ||
| 224 | return 2; | 300 | return 2; |
| 225 | 301 | ||
| 226 | case Token::tOpenParen: | 302 | case Token::tOpenParen: |
| @@ -239,8 +315,9 @@ int Parser::getPriority( Token::Type eType ) | |||
| 239 | switch( eType ) | 315 | switch( eType ) |
| 240 | { | 316 | { |
| 241 | case Token::tNumber: | 317 | case Token::tNumber: |
| 242 | case Token::tString: | 318 | case Token::tVariable: |
| 243 | case Token::tCommand: | 319 | case Token::tCommand: |
| 320 | case Token::tEquals: | ||
| 244 | return 0; | 321 | return 0; |
| 245 | 322 | ||
| 246 | case Token::tPlus: | 323 | case Token::tPlus: |
| @@ -264,3 +341,26 @@ int Parser::getPriority( Token::Type eType ) | |||
| 264 | } | 341 | } |
| 265 | } | 342 | } |
| 266 | 343 | ||
| 344 | Number &Parser::deref( Token &t ) | ||
| 345 | { | ||
| 346 | if( t.eType == Token::tNumber ) | ||
| 347 | { | ||
| 348 | return *t.nVal; | ||
| 349 | } | ||
| 350 | else if( t.eType == Token::tVariable ) | ||
| 351 | { | ||
| 352 | try | ||
| 353 | { | ||
| 354 | return hVars.get( *t.sVal ); | ||
| 355 | } | ||
| 356 | catch(...) | ||
| 357 | { | ||
| 358 | return nZero; | ||
| 359 | } | ||
| 360 | } | ||
| 361 | else | ||
| 362 | { | ||
| 363 | throw Bu::ExceptionBase("Element was not a number or variable."); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
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 @@ | |||
| 2 | #define PARSER_H | 2 | #define PARSER_H |
| 3 | 3 | ||
| 4 | #include <bu/list.h> | 4 | #include <bu/list.h> |
| 5 | #include <bu/hash.h> | ||
| 5 | #include "token.h" | 6 | #include "token.h" |
| 7 | #include "number.h" | ||
| 6 | 8 | ||
| 7 | namespace Bu | 9 | namespace Bu |
| 8 | { | 10 | { |
| @@ -23,13 +25,17 @@ private: | |||
| 23 | void unwind(); | 25 | void unwind(); |
| 24 | int reqTokens( Token::Type eType ); | 26 | int reqTokens( Token::Type eType ); |
| 25 | int getPriority( Token::Type eType ); | 27 | int getPriority( Token::Type eType ); |
| 28 | Number &deref( Token &t ); | ||
| 26 | 29 | ||
| 27 | private: | 30 | private: |
| 28 | Lexer &lex; | 31 | Lexer &lex; |
| 29 | Bu::Stream &rOut; | 32 | Bu::Stream &rOut; |
| 30 | typedef Bu::List<Token> TokenStack; | 33 | typedef Bu::List<Token> TokenStack; |
| 34 | typedef Bu::Hash<Bu::String, Number> VarHash; | ||
| 31 | TokenStack tsTerminal; | 35 | TokenStack tsTerminal; |
| 32 | TokenStack tsNonTerminal; | 36 | TokenStack tsNonTerminal; |
| 37 | Number nZero; | ||
| 38 | VarHash hVars; | ||
| 33 | }; | 39 | }; |
| 34 | 40 | ||
| 35 | #endif | 41 | #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() | |||
| 38 | delete nVal; | 38 | delete nVal; |
| 39 | break; | 39 | break; |
| 40 | 40 | ||
| 41 | case tString: | 41 | case tVariable: |
| 42 | case tCommand: | 42 | case tCommand: |
| 43 | delete sVal; | 43 | delete sVal; |
| 44 | break; | 44 | break; |
| @@ -53,7 +53,7 @@ Bu::Formatter &operator<<( Bu::Formatter &f, Token::Type eType ) | |||
| 53 | switch( eType ) | 53 | switch( eType ) |
| 54 | { | 54 | { |
| 55 | case Token::tNumber: return f << "num"; | 55 | case Token::tNumber: return f << "num"; |
| 56 | case Token::tString: return f << "str"; | 56 | case Token::tVariable: return f << "var"; |
| 57 | case Token::tCommand: return f << "cmd"; | 57 | case Token::tCommand: return f << "cmd"; |
| 58 | case Token::tPlus: return f << "+"; | 58 | case Token::tPlus: return f << "+"; |
| 59 | case Token::tMinus: return f << "-"; | 59 | case Token::tMinus: return f << "-"; |
| @@ -61,6 +61,7 @@ Bu::Formatter &operator<<( Bu::Formatter &f, Token::Type eType ) | |||
| 61 | case Token::tMultiply: return f << "*"; | 61 | case Token::tMultiply: return f << "*"; |
| 62 | case Token::tOpenParen: return f << "("; | 62 | case Token::tOpenParen: return f << "("; |
| 63 | case Token::tCloseParen: return f << ")"; | 63 | case Token::tCloseParen: return f << ")"; |
| 64 | case Token::tEquals: return f << "="; | ||
| 64 | case Token::tEndOfLine: return f << "eol"; | 65 | case Token::tEndOfLine: return f << "eol"; |
| 65 | case Token::tEndOfInput: return f << "eoi"; | 66 | case Token::tEndOfInput: return f << "eoi"; |
| 66 | 67 | ||
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: | |||
| 14 | enum Type | 14 | enum Type |
| 15 | { | 15 | { |
| 16 | tNumber, | 16 | tNumber, |
| 17 | tString, | 17 | tVariable, |
| 18 | tCommand, | 18 | tCommand, |
| 19 | tPlus, | 19 | tPlus, |
| 20 | tMinus, | 20 | tMinus, |
| @@ -22,6 +22,7 @@ public: | |||
| 22 | tMultiply, | 22 | tMultiply, |
| 23 | tOpenParen, | 23 | tOpenParen, |
| 24 | tCloseParen, | 24 | tCloseParen, |
| 25 | tEquals, | ||
| 25 | 26 | ||
| 26 | tEndOfLine, | 27 | tEndOfLine, |
| 27 | 28 | ||
