我在用C#写一个PLC语言解释器。该PLC语言包含20多种数据类型和25种左右的指令。只要我开始生成代码,我就平衡了两种不同的写指令的方式:用C#编写解释器:实现指令的最佳方式是什么?
1)为了选择数据类型,每种类型的指令都在一个类中表示,其中包含大的switch
。示例:
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 desing模式(Exec()
)来编写指令。我认为第二选择是更好的,因为避免了大开关,但是这个选择涉及写超过400条指令。
请务必记住,在这种情况下,执行性能比翻译中的性能更重要。
所以,我的确切问题如下:是否有任何其他方式来分解指令和数据类型?我正在寻找写入较少数量的指令而不惩罚性能。
编辑:
这张照片显示我的类型层次:
这是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));
}
我希望这个信息有帮助。谢谢。
我想每个非终结符一类走在语言,然后分而治之,找到解决方案。 – Alex 2012-03-29 11:31:41
你完成了这个项目并且是你的代码开源吗? – 2014-08-24 05:15:26