1 using System;
2 using Span = System.Lex.Span;
3 using ParsingException = System.Lex.ParsingException;
4
5 namespace cmsx.debug
6 {
7 public class EvaluationException : Exception
8 {
9 public nothrow EvaluationException(const string& message_, const Span& span_) : base(message_), span(span_)
10 {
11 }
12 public Span span;
13 }
14
15 public enum Type : byte
16 {
17 byte_ = 0u, wyde = 1u, tetra = 2u, octa = 3u, char_ = 4u, string = 5u
18 }
19
20 public enum Modifier : byte
21 {
22 none = 0u, signed = 1u, hex = 2u
23 }
24
25 public enum Operator : byte
26 {
27 unaryPlus, unaryMinus, complement, deref, mul, div, mod, shiftLeft, shiftRight, and_, add, sub, or_, xor_
28 }
29
30 public ustring OperatorStr(Operator op)
31 {
32 switch (op)
33 {
34 case Operator.unaryPlus: return u"+";
35 case Operator.unaryMinus: return u"-";
36 case Operator.complement: return u"~";
37 case Operator.deref: return u"*";
38 case Operator.mul: return u"*";
39 case Operator.div: return u"/";
40 case Operator.mod: return u"%";
41 case Operator.shiftLeft: return u"<<";
42 case Operator.shiftRight: return u">>";
43 case Operator.and_: return u"&";
44 case Operator.add: return u"+";
45 case Operator.sub: return u"-";
46 case Operator.or_: return u"|";
47 case Operator.xor_: return u"^";
48 }
49 return ustring();
50 }
51
52 public class ResultFormat
53 {
54 public nothrow ResultFormat() : type(Type.octa), modifier(Modifier.none)
55 {
56 }
57 public Type type;
58 public Modifier modifier;
59 }
60
61 public ustring TypeStr(Type type)
62 {
63 switch (type)
64 {
65 case Type.byte_: return u"b";
66 case Type.wyde: return u"w";
67 case Type.tetra: return u"t";
68 case Type.octa: return u"o";
69 case Type.char_: return u"c";
70 case Type.string: return u"s";
71 }
72 return ustring();
73 }
74
75 public ustring ModifierStr(Modifier modifier)
76 {
77 switch (modifier)
78 {
79 case Modifier.none: return ustring();
80 case Modifier.signed: return u"s";
81 case Modifier.hex: return u"x";
82 }
83 return ustring();
84 }
85
86 public ustring FormatStr(ResultFormat format)
87 {
88 return TypeStr(format.type) + ModifierStr(format.modifier);
89 }
90
91 public abstract class Node
92 {
93 public nothrow Node(const Span& span_) : span(span_)
94 {
95 }
96 public virtual default ~Node();
97 public abstract void Accept(Visitor& visitor);
98 public Span span;
99 }
100
101 public abstract class UnaryNode : Node
102 {
103 public nothrow UnaryNode(const Span& span_, Node* child_) : base(span_), child(child_)
104 {
105 }
106 public UniquePtr<Node> child;
107 }
108
109 public abstract class BinaryNode : Node
110 {
111 public nothrow BinaryNode(const Span& span_, Node* left_, Node* right_) : base(span_), left(left_), right(right_)
112 {
113 }
114 public UniquePtr<Node> left;
115 public UniquePtr<Node> right;
116 }
117
118 public class SegmentNode : Node
119 {
120 public nothrow SegmentNode(const Span& span_, byte segmentIndex_) : base(span_), segmentIndex(segmentIndex_)
121 {
122 }
123 public override void Accept(Visitor& visitor)
124 {
125 visitor.Visit(*this);
126 }
127 public byte segmentIndex;
128 }
129
130 public class RegNumberNode : Node
131 {
132 public nothrow RegNumberNode(const Span& span_, byte reg_) : base(span_), reg(reg_)
133 {
134 }
135 public override void Accept(Visitor& visitor)
136 {
137 visitor.Visit(*this);
138 }
139 public byte reg;
140 }
141
142 public class DecNumberNode : Node
143 {
144 public nothrow DecNumberNode(const Span& span_, ulong value_) : base(span_), value(value_)
145 {
146 }
147 public override void Accept(Visitor& visitor)
148 {
149 visitor.Visit(*this);
150 }
151 public ulong value;
152 }
153
154 public class HexNumberNode : Node
155 {
156 public nothrow HexNumberNode(const Span& span_, ulong value_) : base(span_), value(value_)
157 {
158 }
159 public override void Accept(Visitor& visitor)
160 {
161 visitor.Visit(*this);
162 }
163 public ulong value;
164 }
165
166 public class SymbolNode : Node
167 {
168 public nothrow SymbolNode(const Span& span_, const ustring& id_) : base(span_), id(id_)
169 {
170 }
171 public override void Accept(Visitor& visitor)
172 {
173 visitor.Visit(*this);
174 }
175 public ustring id;
176 }
177
178 public class ParenthesizedExpressionNode : UnaryNode
179 {
180 public nothrow ParenthesizedExpressionNode(const Span& span_, Node* child_) : base(span_, child_)
181 {
182 }
183 public override void Accept(Visitor& visitor)
184 {
185 visitor.Visit(*this);
186 }
187 }
188
189 public class UnaryExpressionNode : UnaryNode
190 {
191 public nothrow UnaryExpressionNode(const Span& span_, Node* child_, Operator op_) : base(span_, child_), op(op_)
192 {
193 }
194 public override void Accept(Visitor& visitor)
195 {
196 visitor.Visit(*this);
197 }
198 public Operator op;
199 }
200
201 public class BinaryExpressionNode : BinaryNode
202 {
203 public nothrow BinaryExpressionNode(const Span& span_, Node* left_, Node* right_, Operator op_) : base(span_, left_, right_), op(op_)
204 {
205 }
206 public override void Accept(Visitor& visitor)
207 {
208 visitor.Visit(*this);
209 }
210 public Operator op;
211 }
212
213 public class FormatExpressionNode : UnaryNode
214 {
215 public nothrow FormatExpressionNode(const Span& span_, Node* child_, ResultFormat format_) : base(span_, child_), format(format_)
216 {
217 }
218 public override void Accept(Visitor& visitor)
219 {
220 visitor.Visit(*this);
221 }
222 public ResultFormat format;
223 }
224
225 public class PrintStatementNode : Node
226 {
227 public nothrow PrintStatementNode(const Span& span_, Node* expression_) : base(span_), expression(expression_)
228 {
229 }
230 public override void Accept(Visitor& visitor)
231 {
232 visitor.Visit(*this);
233 }
234 public UniquePtr<Node> expression;
235 }
236
237 public class TraceStatementNode : Node
238 {
239 public nothrow TraceStatementNode(const Span& span_, Node* expression_) : base(span_), expression(expression_)
240 {
241 }
242 public override void Accept(Visitor& visitor)
243 {
244 visitor.Visit(*this);
245 }
246 public UniquePtr<Node> expression;
247 }
248
249 public void Evaluate(Debugger* debugger, const ustring& line)
250 {
251 try
252 {
253 MdbLexer lexer(line, "<line>", 0);
254 UniquePtr<Node> node = StatementParser.Parse(lexer);
255 Evaluator evaluator(debugger);
256 node->Accept(evaluator);
257 }
258 catch (const ParsingException& ex)
259 {
260 string error = "error: " + ex.Message();
261 debugger->AddOutputLine(ToUtf32(error), 0u);
262 }
263 catch (const EvaluationException& ex)
264 {
265 string error = "error: " + ex.Message();
266 debugger->AddOutputLine(ToUtf32(error), 0u);
267 debugger->AddOutputLine(line, 0u);
268 debugger->AddOutputLine(ustring(' ', ex.span.start) + u"^", 0u);
269 }
270 catch (const Exception& ex)
271 {
272 string error = "error: " + ex.Message();
273 debugger->AddOutputLine(ToUtf32(error), 0u);
274 }
275 }
276
277 public class Visitor
278 {
279 public virtual void Visit(SegmentNode& node)
280 {
281 }
282 public virtual void Visit(RegNumberNode& node)
283 {
284 }
285 public virtual void Visit(DecNumberNode& node)
286 {
287 }
288 public virtual void Visit(HexNumberNode& node)
289 {
290 }
291 public virtual void Visit(SymbolNode& node)
292 {
293 }
294 public virtual void Visit(ParenthesizedExpressionNode& node)
295 {
296 }
297 public virtual void Visit(UnaryExpressionNode& node)
298 {
299 }
300 public virtual void Visit(BinaryExpressionNode& node)
301 {
302 }
303 public virtual void Visit(FormatExpressionNode& node)
304 {
305 }
306 public virtual void Visit(PrintStatementNode& node)
307 {
308 }
309 public virtual void Visit(TraceStatementNode& node)
310 {
311 }
312 }
313
314 public class Evaluator : Visitor
315 {
316 public nothrow Evaluator(Debugger* debugger_) : debugger(debugger_)
317 {
318 }
319 public override void Visit(PrintStatementNode& node)
320 {
321 node.expression->Accept(*this);
322 str.Append(u" = ");
323 switch (format.modifier)
324 {
325 case Modifier.none:
326 {
327 switch (format.type)
328 {
329 case Type.byte_: str.Append(ToUtf32(ToString(cast<byte>(value)))); break;
330 case Type.wyde: str.Append(ToUtf32(ToString(cast<ushort>(value)))); break;
331 case Type.tetra: str.Append(ToUtf32(ToString(cast<uint>(value)))); break;
332 case Type.octa: str.Append(ToUtf32(ToString(cast<ulong>(value)))); break;
333 case Type.char_: str.Append(u'\'').Append(ToUtf32(ToString(cast<char>(value)))).Append(u'\''); break;
334 case Type.string: str.Append(u"\"").Append(debugger->ReadStringFromMemory(value)).Append(u"\""); break;
335 }
336 break;
337 }
338 case Modifier.signed:
339 {
340 switch (format.type)
341 {
342 case Type.byte_: str.Append(ToUtf32(ToString(cast<sbyte>(value)))); break;
343 case Type.wyde: str.Append(ToUtf32(ToString(cast<short>(value)))); break;
344 case Type.tetra: str.Append(ToUtf32(ToString(cast<int>(value)))); break;
345 case Type.octa: str.Append(ToUtf32(ToString(cast<long>(value)))); break;
346 }
347 break;
348 }
349 case Modifier.hex:
350 {
351 switch (format.type)
352 {
353 case Type.byte_: str.Append(u"#" + ToUtf32(ToHexString(cast<byte>(value)))); break;
354 case Type.wyde: str.Append(u"#" + ToUtf32(ToHexString(cast<ushort>(value)))); break;
355 case Type.tetra: str.Append(u"#" + ToUtf32(ToHexString(cast<uint>(value)))); break;
356 case Type.octa: str.Append(u"#" + ToUtf32(ToHexString(cast<ulong>(value)))); break;
357 }
358 break;
359 }
360 }
361 debugger->AddOutputLine(str, value);
362 }
363 public override void Visit(TraceStatementNode& node)
364 {
365 str = u"trace";
366 if (node.expression.Get() != null)
367 {
368 str.Append(u" ");
369 node.expression->Accept(*this);
370 }
371 else
372 {
373 value = 10u;
374 }
375 str.Append(u":");
376 debugger->AddOutputLine(str, 0u);
377 debugger->Trace(value);
378 }
379 public override void Visit(FormatExpressionNode& node)
380 {
381 format = node.format;
382 node.child->Accept(*this);
383 ustring formatStr;
384 formatStr = FormatStr(format);
385 if (!formatStr.IsEmpty())
386 {
387 str.Append('.').Append(formatStr);
388 }
389 }
390 public override void Visit(BinaryExpressionNode& node)
391 {
392 node.left->Accept(*this);
393 ulong left = value;
394 str.Append(u" ").Append(OperatorStr(node.op)).Append(u" ");
395 node.right->Accept(*this);
396 ulong right = value;
397 bool error = false;
398 switch (node.op)
399 {
400 case Operator.mul: value = left * right; break;
401 case Operator.div: value = left / right; break;
402 case Operator.mod: value = left % right; break;
403 case Operator.shiftLeft: value = left << right; break;
404 case Operator.shiftRight: value = left >> right; break;
405 case Operator.and_: value = left & right; break;
406 case Operator.add: value = left + right; break;
407 case Operator.sub: value = left - right; break;
408 case Operator.or_: value = left | right; break;
409 case Operator.xor_: value = left ^ right; break;
410 default: error = true; break;
411 }
412 if (error)
413 {
414 throw EvaluationException("unknown binary operator", node.span);
415 }
416 }
417 public override void Visit(UnaryExpressionNode& node)
418 {
419 bool error = false;
420 try
421 {
422 str.Append(OperatorStr(node.op));
423 node.child->Accept(*this);
424 switch (node.op)
425 {
426 case Operator.unaryPlus: break;
427 case Operator.unaryMinus: value = -value; break;
428 case Operator.complement: value = ~value; break;
429 case Operator.deref:
430 {
431 byte size = 8u;
432 switch (format.type)
433 {
434 case Type.byte_: size = 1u; break;
435 case Type.wyde: size = 2u; break;
436 case Type.tetra: size = 4u; break;
437 case Type.octa: size = 8u; break;
438 case Type.char_: size = 1u; break;
439 }
440 value = debugger->ReadMemoryContent(value, size);
441 break;
442 }
443 default: error = true; break;
444 }
445 }
446 catch (const Exception& ex)
447 {
448 throw EvaluationException(ex.Message(), node.span);
449 }
450 if (error)
451 {
452 throw EvaluationException("unknown unary operator", node.span);
453 }
454 }
455 public override void Visit(ParenthesizedExpressionNode& node)
456 {
457 str.Append(u"(");
458 node.child->Accept(*this);
459 str.Append(u")");
460 }
461 public override void Visit(SymbolNode& node)
462 {
463 try
464 {
465 str.Append(node.id);
466 value = debugger->GetSymbolValue(ToUtf8(node.id));
467 }
468 catch (const Exception& ex)
469 {
470 throw EvaluationException(ex.Message(), node.span);
471 }
472 }
473 public override void Visit(DecNumberNode& node)
474 {
475 str.Append(ToUtf32(ToString(node.value)));
476 value = node.value;
477 }
478 public override void Visit(HexNumberNode& node)
479 {
480 str.Append(u"#" + ToUtf32(ToHexString(node.value)));
481 value = node.value;
482 }
483 public override void Visit(RegNumberNode& node)
484 {
485 str.Append(u"$").Append(ToUtf32(ToString(node.reg)));
486 value = debugger->GetRegisterValue(node.reg);
487 }
488 public override void Visit(SegmentNode& node)
489 {
490 bool error = false;
491 switch (node.segmentIndex)
492 {
493 case cmsx.machine.textSegmentIndex: str.Append(u"$t"); value = cmsx.machine.textSegmentBaseAddress; break;
494 case cmsx.machine.dataSegmentIndex: str.Append(u"$d"); value = cmsx.machine.dataSegmentBaseAddress; break;
495 case cmsx.machine.poolSegmentIndex: str.Append(u"$p"); value = cmsx.machine.poolSegmentBaseAddress; break;
496 case cmsx.machine.stackSegmentIndex: str.Append(u"$s"); value = cmsx.machine.stackSegmentBaseAddress; break;
497 case cmsx.machine.numSegments: str.Append(u"$k"); value = cmsx.machine.kernelBaseAddress; break;
498 default: error = true; break;
499 }
500 if (error)
501 {
502 throw EvaluationException("invalid segment index " + ToString(node.segmentIndex), node.span);
503 }
504 }
505 private Debugger* debugger;
506 private ulong value;
507 private ResultFormat format;
508 private ustring str;
509 }
510 }