summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2013-04-23 11:47:01 -0600
committerMike Buland <mike@xagasoft.com>2013-04-23 11:47:01 -0600
commit04f56c12e82ea5228b2b65e68c46ed7f4563182b (patch)
tree89a8db02dae8aaafd70f91bb15f21209cd1fa0ed
parent9f138260dafeb5a1b541fff8dd577422439feb0b (diff)
downloadclic-04f56c12e82ea5228b2b65e68c46ed7f4563182b.tar.gz
clic-04f56c12e82ea5228b2b65e68c46ed7f4563182b.tar.bz2
clic-04f56c12e82ea5228b2b65e68c46ed7f4563182b.tar.xz
clic-04f56c12e82ea5228b2b65e68c46ed7f4563182b.zip
Variables work.
-rw-r--r--src/lexer.cpp40
-rw-r--r--src/parser.cpp114
-rw-r--r--src/parser.h6
-rw-r--r--src/token.cpp5
-rw-r--r--src/token.h3
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
344Number &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
7namespace Bu 9namespace 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
27private: 30private:
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