gpt4 book ai didi

c# - 用 C# : Best way to implement instructions? 编写解释器

转载 作者:行者123 更新时间:2023-11-30 19:30:08 25 4
gpt4 key购买 nike

我正在使用 C# 编写 PLC 语言解释器。该 PLC 语言包含 20 多种数据类型和 25 条左右的指令。一旦我开始生成代码,我就会平衡两种不同的方式来编写指令:

1) 每一种指令都在一个类中表示,该类包含一个大的开关 以选择数据类型。示例:

public class ADD : Instruction
{
private string type;

public ADD(string type)
{
this.type = type;
}

public bool Exec(Context c)
{
switch (type)
{
case "INT":
short valor2 = c.PopINT();
short valor = c.PopINT();
short result = (short)(valor + valor2);
c.PushINT(result);
break;
case "DINT":
int valor4 = c.PopDINT();
int valor3 = c.PopDINT();
int result2 = (int)(valor4 + valor3);
c.PushDINT(result2);
break;
case "BOOL":
// Implement BOOL
break;
// Implement other types...
default:
break;
}

c.IP++;
return false; ;
}

}

2) 每个类代表具有单一数据类型的单一指令。这样就避免了大的 switch。示例:

public class ADDi : Instruction
{
public bool Exec(Context c)
{
short valor = c.PopINT();
short valor2 = c.PopINT();
short result = (short)(valor + valor2);
c.PushINT(result);
c.IP++;
return false;
}
}

我正在使用 COMMAND 设计模式 (Exec()) 来编写指令。我认为第二种选择更好,因为它避免了大切换,但该选择涉及编写超过 400 条指令。

请始终牢记,在这种情况下,执行性能比翻译性能更重要。

所以,我的确切问题如下:还有其他方法可以分解指令和数据类型吗?我希望在不影响性能的情况下编写更少的指令。

编辑:

这张图片显示了我的类型层次结构:

Type hierarchy

这是 INT 类实现:

public class INT : ANY_INT
{

public override string DefaultInitValue()
{
return "0";
}

public override int GetBytes()
{
return 2;
}

public override string GetLastType()
{
return this.ToString();
}

public override string ToString()
{
return "INT";
}

}

有些类更复杂(结构、数组……)。

Push 和 Pop 操作定义如下:

public void PushINT(short value)
{
//SP -> Stack Pointer
resMem.WriteINT(SP, value);
SP += 2;
}

public short PopINT()
{
SP -= 2;
short value = resMem.ReadINT(SP);
return value;
}

最后,内存读写操作。

public void WriteINT(int index, short entero)
{
SetCapacity(index + 2); // Memory grows up dinamically
memory[index] = (sbyte)((ushort)entero >> 8 & 0x00FF);
memory[index + 1] = (sbyte)((ushort)entero >> 0 & 0x00FF);
}

public short ReadINT(int index)
{
return (short)(((short)(memory[index]) << 8 & 0xFF00) |
((short)(memory[index + 1]) & 0x00FF));
}

希望这些信息对您有所帮助。谢谢。

最佳答案

如果您可以更改 Context 的实现以支持泛型类型(例如,Pop<int> 而不是 PopINT()),您可以使用委托(delegate)来简化实现。

添加:

var addInt = new MathInstruction<int>((a, b) => a + b));
var addDouble = new MathInstruction<double>((a, b) => a + b));
var addDecimal = new MathInstruction<decimal>((a, b) => a + b));

减法:

var subtractInt = new MathInstruction<int>((a, b) => a - b));
var subtractDouble = new MathInstruction<double>((a, b) => a - b));
var subtractDecimal = new MathInstruction<decimal>((a, b) => a - b));

部门:

var divideIntAsDouble = new MathInstruction<int, double>((a, b) => a / b));
var divideDouble = new MathInstruction<double>((a, b) => a / b));
var divideDecimal = new MathInstruction<decimal>((a, b) => a / b));

以及类型之间的转换:

var addIntAndDouble = new MathInstruction<int, double, double>((a, b) => a + b));

它会像这样实现:

class MathInstruction<TA, TB, TResult> : Instruction
{
private Func<TA, TB, TResult> callback;

public MathInstruction(Func<TA, TB, TResult> callback)
{
this.callback = callback;
}

public bool Exec(Context c)
{
var a = c.Pop<TA>();
var b = c.Pop<TB>();
var result = callback(a, b);
c.Push<TResult>(result);
return false;
}
}

// Convenience
class MathInstruction<T, TResult> : MathInstruction<T, T, TResult>
class MathInstruction<T> : MathInstruction<T, T, T>

我想你的上下文只有一个 Stack<object>PopINT , PopBOOL等。只需弹出参数并进行转换。在那种情况下,您可能只需使用:

public T Pop<T>()
{
var o = stack.Pop();
return Convert.ChangeType(o, typeof(T));
}

public void Push<T>(T item)
{
stack.Push(item);
}

请注意,这也可以处理您的逻辑运算符 - 例如:

var logicalAnd = new MathInstruction<bool>((a, b) => a && b);
var logicalOr = new MathInstruction<bool>((a, b) => a || b);

关于c# - 用 C# : Best way to implement instructions? 编写解释器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9924396/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com