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 | ||