diff options
author | Mike Buland <mike@xagasoft.com> | 2013-04-22 13:05:22 -0600 |
---|---|---|
committer | Mike Buland <mike@xagasoft.com> | 2013-04-22 13:05:22 -0600 |
commit | 2909f50d008920568f0e50da760b266388ccc124 (patch) | |
tree | 6789c162a2b950c2006c944e9d21e6ed9bda7069 /src/parser.cpp | |
parent | d7ccd9c4d8e5a5bb4f12b36b3e4ad3105c5a9317 (diff) | |
download | clic-2909f50d008920568f0e50da760b266388ccc124.tar.gz clic-2909f50d008920568f0e50da760b266388ccc124.tar.bz2 clic-2909f50d008920568f0e50da760b266388ccc124.tar.xz clic-2909f50d008920568f0e50da760b266388ccc124.zip |
There is now a parser & calculator interface.
Diffstat (limited to 'src/parser.cpp')
-rw-r--r-- | src/parser.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/src/parser.cpp b/src/parser.cpp new file mode 100644 index 0000000..21ccc11 --- /dev/null +++ b/src/parser.cpp | |||
@@ -0,0 +1,266 @@ | |||
1 | #include "parser.h" | ||
2 | #include "lexer.h" | ||
3 | #include "number.h" | ||
4 | |||
5 | #include <bu/sio.h> | ||
6 | |||
7 | Parser::Parser( Lexer &lex, Bu::Stream &rOut ) : | ||
8 | lex( lex ), | ||
9 | rOut( rOut ) | ||
10 | { | ||
11 | } | ||
12 | |||
13 | Parser::~Parser() | ||
14 | { | ||
15 | } | ||
16 | |||
17 | void Parser::parse() | ||
18 | { | ||
19 | for(;;) | ||
20 | { | ||
21 | Token t = lex.nextToken(); | ||
22 | switch( t.eType ) | ||
23 | { | ||
24 | case Token::tEndOfInput: | ||
25 | return; | ||
26 | |||
27 | case Token::tEndOfLine: | ||
28 | unwind(); | ||
29 | if( !tsTerminal.isEmpty() ) | ||
30 | { | ||
31 | Bu::println( rOut, "%1").arg( *tsTerminal.peek().nVal ); | ||
32 | } | ||
33 | tsTerminal.clear(); | ||
34 | break; | ||
35 | |||
36 | case Token::tCommand: | ||
37 | if( *t.sVal == "exit" || *t.sVal == "quit" ) | ||
38 | return; | ||
39 | else if( *t.sVal == "scale" ) | ||
40 | { | ||
41 | Token t2 = lex.nextToken(); | ||
42 | if( t2.eType == Token::tEndOfLine ) | ||
43 | { | ||
44 | Bu::println( rOut, "Current scale: %1"). | ||
45 | arg( lex.getScale() ); | ||
46 | } | ||
47 | else if( t2.eType == Token::tNumber ) | ||
48 | { | ||
49 | int32_t i = t2.nVal->toInt32(); | ||
50 | lex.setScale( i ); | ||
51 | if( i < 0 ) | ||
52 | { | ||
53 | Bu::println( rOut, "ERROR: You must provide a " | ||
54 | "positive integer or zero as the parameter " | ||
55 | "to scale."); | ||
56 | } | ||
57 | else | ||
58 | { | ||
59 | Bu::println( rOut, "Scale changed to: %1"). | ||
60 | arg( lex.getScale() ); | ||
61 | } | ||
62 | } | ||
63 | else | ||
64 | { | ||
65 | Bu::println( rOut, "ERROR: You must provide a number " | ||
66 | "as the parameter to scale."); | ||
67 | } | ||
68 | } | ||
69 | else if( *t.sVal == "radix" ) | ||
70 | { | ||
71 | Token t2 = lex.nextToken(); | ||
72 | if( t2.eType == Token::tEndOfLine ) | ||
73 | { | ||
74 | Bu::println( rOut, "Current radix: %1"). | ||
75 | arg( lex.getRadix() ); | ||
76 | } | ||
77 | else if( t2.eType == Token::tNumber ) | ||
78 | { | ||
79 | int32_t i = t2.nVal->toInt32(); | ||
80 | if( i < 2 || i > 36 ) | ||
81 | Bu::println( rOut, "ERROR: Radix must be between " | ||
82 | "2 and 36 inclusive"); | ||
83 | else | ||
84 | { | ||
85 | lex.setRadix( i ); | ||
86 | Bu::println( rOut, "Radix changed to: %1"). | ||
87 | arg( lex.getRadix() ); | ||
88 | } | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | Bu::println( rOut, "You must provide a number as " | ||
93 | "the parameter to radix."); | ||
94 | } | ||
95 | } | ||
96 | else | ||
97 | { | ||
98 | Bu::println( rOut, "ERROR: Unknown command '%1'"). | ||
99 | arg( *t.sVal ); | ||
100 | } | ||
101 | break; | ||
102 | |||
103 | case Token::tNumber: | ||
104 | tsTerminal.push( t ); | ||
105 | break; | ||
106 | |||
107 | default: | ||
108 | if( tsNonTerminal.getSize() == 0 || | ||
109 | getPriority( tsNonTerminal.peek().eType ) <= | ||
110 | getPriority( t.eType ) ) | ||
111 | { | ||
112 | // Bu::println("Pushing non-terminal: %1").arg( t.eType ); | ||
113 | tsNonTerminal.push( t ); | ||
114 | |||
115 | // for( TokenStack::iterator i = tsTerminal.begin(); i; i++ ) Bu::print(" [%1]").arg( *(*i).nVal ); Bu::println(""); | ||
116 | // for( TokenStack::iterator i = tsNonTerminal.begin(); i; i++ ) Bu::print(" <%1>").arg( (*i).eType ); Bu::println(""); | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | // Bu::println("Unwinding stack before pushing: %1").arg( t.eType ); | ||
121 | unwind(); | ||
122 | tsNonTerminal.push( t ); | ||
123 | // for( TokenStack::iterator i = tsTerminal.begin(); i; i++ ) Bu::print(" [%1]").arg( *(*i).nVal ); Bu::println(""); | ||
124 | // for( TokenStack::iterator i = tsNonTerminal.begin(); i; i++ ) Bu::print(" <%1>").arg( (*i).eType ); Bu::println(""); | ||
125 | } | ||
126 | break; | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | void Parser::unwind() | ||
132 | { | ||
133 | for(;;) | ||
134 | { | ||
135 | // for( TokenStack::iterator i = tsTerminal.begin(); i; i++ ) Bu::print(" [%1]").arg( *(*i).nVal ); Bu::println(""); | ||
136 | // for( TokenStack::iterator i = tsNonTerminal.begin(); i; i++ ) Bu::print(" <%1>").arg( (*i).eType ); Bu::println(""); | ||
137 | if( tsNonTerminal.isEmpty() ) | ||
138 | return; | ||
139 | |||
140 | if( tsTerminal.getSize() < reqTokens( tsNonTerminal.peek().eType ) ) | ||
141 | { | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | Token t = tsNonTerminal.peekPop(); | ||
146 | switch( t.eType ) | ||
147 | { | ||
148 | case Token::tPlus: | ||
149 | { | ||
150 | Token b = tsTerminal.peekPop(); | ||
151 | Token a = tsTerminal.peekPop(); | ||
152 | tsTerminal.push( | ||
153 | Token( Token::tNumber, new Number( *a.nVal + *b.nVal ) ) | ||
154 | ); | ||
155 | } | ||
156 | break; | ||
157 | |||
158 | case Token::tMinus: | ||
159 | { | ||
160 | Token b = tsTerminal.peekPop(); | ||
161 | Token a = tsTerminal.peekPop(); | ||
162 | tsTerminal.push( | ||
163 | Token( Token::tNumber, new Number( *a.nVal - *b.nVal ) ) | ||
164 | ); | ||
165 | } | ||
166 | break; | ||
167 | |||
168 | case Token::tMultiply: | ||
169 | { | ||
170 | Token b = tsTerminal.peekPop(); | ||
171 | Token a = tsTerminal.peekPop(); | ||
172 | tsTerminal.push( | ||
173 | Token( Token::tNumber, new Number( *a.nVal * *b.nVal ) ) | ||
174 | ); | ||
175 | } | ||
176 | break; | ||
177 | |||
178 | case Token::tDivide: | ||
179 | { | ||
180 | Token b = tsTerminal.peekPop(); | ||
181 | Token a = tsTerminal.peekPop(); | ||
182 | tsTerminal.push( | ||
183 | Token( Token::tNumber, new Number( *a.nVal / *b.nVal ) ) | ||
184 | ); | ||
185 | } | ||
186 | break; | ||
187 | |||
188 | case Token::tOpenParen: | ||
189 | tsNonTerminal.push( t ); | ||
190 | return; | ||
191 | |||
192 | case Token::tCloseParen: | ||
193 | unwind(); | ||
194 | if( tsNonTerminal.peek().eType == Token::tOpenParen ) | ||
195 | { | ||
196 | |||
197 | tsNonTerminal.pop(); | ||
198 | } | ||
199 | else | ||
200 | { | ||
201 | throw Bu::ExceptionBase("Close paren found without open paren."); | ||
202 | } | ||
203 | break; | ||
204 | |||
205 | case Token::tNumber: | ||
206 | case Token::tString: | ||
207 | case Token::tCommand: | ||
208 | case Token::tEndOfLine: | ||
209 | case Token::tEndOfInput: | ||
210 | // These should never show up at all | ||
211 | break; | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | |||
216 | int Parser::reqTokens( Token::Type eType ) | ||
217 | { | ||
218 | switch( eType ) | ||
219 | { | ||
220 | case Token::tPlus: | ||
221 | case Token::tMinus: | ||
222 | case Token::tDivide: | ||
223 | case Token::tMultiply: | ||
224 | return 2; | ||
225 | |||
226 | case Token::tOpenParen: | ||
227 | return 0; | ||
228 | |||
229 | case Token::tCloseParen: | ||
230 | return 1; | ||
231 | |||
232 | default: | ||
233 | return 0; | ||
234 | } | ||
235 | } | ||
236 | |||
237 | int Parser::getPriority( Token::Type eType ) | ||
238 | { | ||
239 | switch( eType ) | ||
240 | { | ||
241 | case Token::tNumber: | ||
242 | case Token::tString: | ||
243 | case Token::tCommand: | ||
244 | return 0; | ||
245 | |||
246 | case Token::tPlus: | ||
247 | case Token::tMinus: | ||
248 | return 1; | ||
249 | |||
250 | case Token::tDivide: | ||
251 | case Token::tMultiply: | ||
252 | return 2; | ||
253 | |||
254 | case Token::tOpenParen: | ||
255 | case Token::tCloseParen: | ||
256 | return 3; | ||
257 | |||
258 | case Token::tEndOfLine: | ||
259 | case Token::tEndOfInput: | ||
260 | return -1; | ||
261 | |||
262 | default: | ||
263 | throw Bu::ExceptionBase("Invalid type in getPriority"); | ||
264 | } | ||
265 | } | ||
266 | |||