summaryrefslogtreecommitdiff
path: root/src/parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.cpp')
-rw-r--r--src/parser.cpp266
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
7Parser::Parser( Lexer &lex, Bu::Stream &rOut ) :
8 lex( lex ),
9 rOut( rOut )
10{
11}
12
13Parser::~Parser()
14{
15}
16
17void 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
131void 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
216int 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
237int 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