在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));
}
}
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
