在C#中使用运算符时构造自定义表达式树
这个问题是使用C#(或任何其他语言)中的运算符在.NET中构造自定义表达式树.我提供了一些背景信息.
对于我的managed 2-phase 64-bit assembler,我需要表达式的支持.例如,人们可能想要组装: mystring: DB 'hello,world' TIMES 64-$+mystring DB ' ' 表达式64- $mystring不能是一个字符串,而是一个实际的有效表达式,具有语法和类型检查以及VS中的IntelliSense功能,其特点如下: 64 - Reference.CurrentOffset + new Reference("mystring"); 构建此表达式时不进行评估.相反,它将在我的汇编器的上下文中(当它确定符号偏移量等等时)进行评估. .NET框架(自.NET 3.5以来)提供了对表达式树的支持,在我看来,它对于稍后或其他地方进行评估的这种表达式是理想的. 但是我不知道如何确保我可以使用C#语法(使用<<%等等)来构造表达式树.我想防止像: var expression = AssemblerExpression.Subtract(64,AssemblerExpression.Add(AssemblerExpression.CurrentOffset(),AssemblerExpression.Reference("mystring"))) 你会怎么样呢? 注意:我需要一个表达式树,以便将表达式转换为可接受的自定义字符串表示形式,同时可以在不同于其定义的时间点对其进行评估. 对我的例子的解释:64- $mystring. $是当前的偏移量,因此它是一个预先未知的特定数字(但在评估时已知).哨子是在评估时间可能或可能不知道的符号(例如,当尚未被定义时).从符号S中减去常数C与S-C相同.减去两个符号S0和S1(S1 – S0)给出两个符号值之间的整数差. 但是,这个问题并不在于如何评估汇编器表达式,而是更多地关于如何评估其中有自定义类的任何表达式(例如符号和示例中的$)以及如何确保它可以是漂亮的 – 使用一些访客(因此保留树)打印.而且由于.NET框架具有表达式的树和访问者,所以如果可能的话,使用它们是很好的. 解决方法
我不知道你正在瞄准什么,但以下是我认为可以工作的一些粗略的方法.
注意我 >仅演示索引的引用表达式(因此忽略了通过寄存器的间接寻址现在;您可以添加类似于SymbolicReference类的RegisterInderectReference).这也适用于您建议的$(当前偏移)功能.它可能会确定一个注册表(?) . using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Linq; namespace Assembler { internal class State { public readonly IDictionary<string,ulong> SymbolTable = new Dictionary<string,ulong>(); public void Clear() { SymbolTable.Clear(); } } internal interface IReference { ulong EvalAddress(State s); // evaluate reference to address } internal abstract class ReferenceBase : IReference { public static IndexedReference operator+(long directOffset,ReferenceBase baseRef) { return new IndexedReference(baseRef,directOffset); } public static IndexedReference operator+(ReferenceBase baseRef,long directOffset) { return new IndexedReference(baseRef,directOffset); } public abstract ulong EvalAddress(State s); } internal class SymbolicReference : ReferenceBase { public static explicit operator SymbolicReference(string symbol) { return new SymbolicReference(symbol); } public SymbolicReference(string symbol) { _symbol = symbol; } private readonly string _symbol; public override ulong EvalAddress(State s) { return s.SymbolTable[_symbol]; } public override string ToString() { return string.Format("Sym({0})",_symbol); } } internal class IndexedReference : ReferenceBase { public IndexedReference(IReference baseRef,long directOffset) { _baseRef = baseRef; _directOffset = directOffset; } private readonly IReference _baseRef; private readonly long _directOffset; public override ulong EvalAddress(State s) { return (_directOffset<0) ? _baseRef.EvalAddress(s) - (ulong) Math.Abs(_directOffset) : _baseRef.EvalAddress(s) + (ulong) Math.Abs(_directOffset); } public override string ToString() { return string.Format("{0} + {1}",_directOffset,_baseRef); } } } namespace Program { using Assembler; public static class Program { public static void Main(string[] args) { var myBaseRef1 = new SymbolicReference("mystring1"); Expression<Func<IReference>> anyRefExpr = () => 64 + myBaseRef1; Console.WriteLine(anyRefExpr); var myBaseRef2 = (SymbolicReference) "mystring2"; // uses explicit conversion operator Expression<Func<IndexedReference>> indexedRefExpr = () => 64 + myBaseRef2; Console.WriteLine(indexedRefExpr); Console.WriteLine(Console.Out.NewLine + "=== show compiletime types of returned values:"); Console.WriteLine("myBaseRef1 -> {0}",myBaseRef1); Console.WriteLine("myBaseRef2 -> {0}",myBaseRef2); Console.WriteLine("anyRefExpr -> {0}",anyRefExpr.Compile().Method.ReturnType); Console.WriteLine("indexedRefExpr -> {0}",indexedRefExpr.Compile().Method.ReturnType); Console.WriteLine(Console.Out.NewLine + "=== show runtime types of returned values:"); Console.WriteLine("myBaseRef1 -> {0}",anyRefExpr.Compile()()); // compile() returns Func<...> Console.WriteLine("indexedRefExpr -> {0}",indexedRefExpr.Compile()()); Console.WriteLine(Console.Out.NewLine + "=== observe how you could add an evaluation model using some kind of symbol table:"); var compilerState = new State(); compilerState.SymbolTable.Add("mystring1",0xdeadbeef); // raw addresses compilerState.SymbolTable.Add("mystring2",0xfeedface); Console.WriteLine("myBaseRef1 evaluates to 0x{0:x8}",myBaseRef1.EvalAddress(compilerState)); Console.WriteLine("myBaseRef2 evaluates to 0x{0:x8}",myBaseRef2.EvalAddress(compilerState)); Console.WriteLine("anyRefExpr displays as {0:x8}",anyRefExpr.Compile()()); Console.WriteLine("indexedRefExpr displays as {0:x8}",indexedRefExpr.Compile()()); Console.WriteLine("anyRefExpr evaluates to 0x{0:x8}",anyRefExpr.Compile()().EvalAddress(compilerState)); Console.WriteLine("indexedRefExpr evaluates to 0x{0:x8}",indexedRefExpr.Compile()().EvalAddress(compilerState)); } } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |