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_ = 0uwyde = 1utetra = 2uocta = 3uchar_ = 4ustring = 5u
 18     }
 19 
 20     public enum Modifier : byte
 21     {
 22         none = 0usigned = 1uhex = 2u
 23     }
 24 
 25     public enum Operator : byte
 26     {
 27         unaryPlusunaryMinuscomplementderefmuldivmodshiftLeftshiftRightand_addsubor_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* debuggerconst 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(line0u);
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(strvalue);
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(str0u);
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(valuesize);
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 }