.net 设计这个循环的更好方法?
我正在为我自己的定制风格的汇编构建一个简单的汇编编译器,我有这样的东西作为编译的实际代码:.net 设计这个循环的更好方法?,.net,.net,我正在为我自己的定制风格的汇编构建一个简单的汇编编译器,我有这样的东西作为编译的实际代码: foreach (KeyValuePair<short, string> kvp in newCommandSet) { string fullCommandString = kvp.Value; string instruction = fullCommandString.Split(new char[] { Convert.ToChar("
foreach (KeyValuePair<short, string> kvp in newCommandSet)
{
string fullCommandString = kvp.Value;
string instruction = fullCommandString.Split(new char[] { Convert.ToChar(" ") })[0];
string[] parameters = fullCommandString.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries);
// this is to remove the instruction part from the first parameter. Gonna have to ensure a well formed command at some point...
parameters[0] = parameters[0].Substring(instruction.Length + 1);
Command currentCommand = new Command();
switch (instruction)
{
case "load":
short value = Convert.ToInt16(instruction[0]);
byte register = Convert.ToByte(parameters[1]);
currentCommand = CommandFactory.CreateLoadCommand(register, value);
break;
case "input":
byte channel = Convert.ToByte(parameters[0]);
register = Convert.ToByte(parameters[1]);
currentCommand = CommandFactory.CreateInputCommand(register, channel);
break;
case "output":
channel = Convert.ToByte(parameters[0]);
register = Convert.ToByte(parameters[1]);
currentCommand = CommandFactory.CreateInputCommand(register, channel);
break;
...
}
...
}
foreach(newCommandSet中的KeyValuePair kvp)
{
string fullCommandString=kvp.Value;
string指令=fullCommandString.Split(新字符[]{Convert.ToChar(“”})[0];
string[]参数=fullCommandString.Split(新字符串[]{,“},StringSplitOptions.RemoveEmptyEntries);
//这是从第一个参数中删除指令部分。必须确保在某个点上有一个格式良好的命令。。。
参数[0]=参数[0]。子字符串(指令.Length+1);
Command currentCommand=新命令();
开关(指令)
{
案例“荷载”:
短值=转换为16(指令[0]);
字节寄存器=Convert.ToByte(参数[1]);
currentCommand=CommandFactory.CreateLoadCommand(寄存器,值);
打破
案例“输入”:
字节通道=Convert.ToByte(参数[0]);
寄存器=Convert.ToByte(参数[1]);
currentCommand=CommandFactory.CreateInputCommand(寄存器,通道);
打破
案例“输出”:
channel=Convert.ToByte(参数[0]);
寄存器=Convert.ToByte(参数[1]);
currentCommand=CommandFactory.CreateInputCommand(寄存器,通道);
打破
...
}
...
}
我觉得我在这里打破了大约六条设计规则(重用变量和期望格式良好的输入是我唯一能发现的,但我打赌还有更多),但我不知道如何更好地构建它。想法? < P>你可以考虑像一个记录器一样扔一些东西,把你的程序返回为一个符号串(你的分配器是这样做的)。然后将其传递给解析器以创建解析树和符号表。为什么?因为在不知道你的汇编风格的情况下,在某个时候你会想要跳转到一个标签(子例程),我假设。或者您希望跳转指令返回到循环的开始处,等等
如果您已经设置了解析树和符号表,那么您将拥有所有的地址,便于插入到输出文件中。我已经很久没有编写编译器了,所以请原谅我的小示例中的任何偏差…考虑将用于解释参数的逻辑推送到CommandFactory中。switch语句如下所示:
switch(instruction)
{
case "load":
currentCommand = CommandFactory.CreateLoadCommand(parameters);
break;
case "input":
currentCommand = CommandFactory.CreateInputCommand(parameters);
break;
case "output":
currentCommand = CommandFactory.CreateOutputCommand(parameters);
break;
}
将说明信息移动到类/属性包中。创建一些实用的转换方法,使您的生活更轻松。然后使用string->delegate字典将指令名映射到命令的创建。这只是一个开始,您可以将其重构为更简单的结构 大概是这样的:
public class InstructionData
{
public InstructionData(string fullCommandString)
{
string[] commandParts = fullCommandString.Split(new char[] {' ', ','}, StringSplitOptions.RemoveEmptyEntries);
this.InstructionName = commandParts[0];
this.parameters = commandParts.Skip(1).ToArray();
}
public string InstructionName { get; private set; }
public short InstructionInt { get { return Convert.ToInt16(InstructionName[0]); } }
private string[] parameters;
public string GetParameter(int paramNum)
{
return parameters[paramNum];
}
public byte GetParameterAsByte(int paramNum)
{
return Convert.ToByte(parameters[paramNum]);
}
}
public class SomeClass
{
// ...
private Dictionary<string, Func<InstructionData, Command>> commandTranslator = new Dictionary<string, Func<InstructionData, Command>>();
private static void InitializeCommandTranslator()
{
commandTranslator["load"] = ins => CommandFactory.CreateLoadCommand(ins);
commandTranslator["input"] = ins => CommandFactory.CreateInputCommand(ins);
commandTranslator["output"] = ins => CommandFactory.CreateOutputCommand(ins);
}
public void SomeMethod()
{
// ...
foreach (KeyValuePair<short, string> kvp in newCommandSet)
{
InstructionData currentInstruction = new InstructionData(kvp.Value);
if(commandTranslator.ContainsKey(currentInstruction.InstructionName))
{
currentCommand = commandTranslator[currentInstruction.InstructionName](currentInstruction);
}
}
}
// ...
}
公共类指令数据
{
公共指令数据(字符串fullCommandString)
{
string[]commandParts=fullCommandString.Split(新字符[]{',','},StringSplitOptions.RemoveEmptyEntries);
this.InstructionName=commandParts[0];
this.parameters=commandParts.Skip(1).ToArray();
}
公共字符串指令名{get;private set;}
公共短指令int{get{return Convert.ToInt16(指令名[0]);}
私有字符串[]参数;
公共字符串GetParameter(int-paramNum)
{
返回参数[paramNum];
}
公共字节GetParameterAsByte(int-paramNum)
{
返回Convert.ToByte(参数[paramNum]);
}
}
公共类
{
// ...
private Dictionary commandTranslator=新字典();
私有静态void InitializeCommandTranslator()
{
commandTranslator[“load”]=ins=>CommandFactory.CreateLoadCommand(ins);
commandTranslator[“输入”]=ins=>CommandFactory.CreateInputCommand(ins);
commandTranslator[“输出”]=ins=>CommandFactory.CreateOutputCommand(ins);
}
公共方法()
{
// ...
foreach(newCommandSet中的KeyValuePair kvp)
{
指令数据当前指令=新指令数据(kvp.值);
if(commandTranslator.ContainsKey(currentInstruction.InstructionName))
{
currentCommand=commandTranslator[currentInstruction.InstructionName](currentInstruction);
}
}
}
// ...
}
在这之前,我实际上想出了一个聪明的小代码,它生成了一个“跳转映射”,这样我就可以将跳转地址发送到字节码中,而不是当前的标签。不过,如果你能为我指出一些库/资源(标记器、解析器),那就太好了……对不起,不太熟悉.net。既然你在这里写的是一个相当原始的程序,没有理由你不能自己做。类似这样的事情:将循环拉入一个“Tokenizer”类,从case语句中拉出所有内部代码,并返回一个常量作为“token”,当然,显式定义您的常量。解析器:每次取1中的令牌。跟踪您的各种状态(启动循环、循环中、启动子例程、子例程中)您应该有一个简单的语法,即使对于您的汇编语言也是如此,所以只需在解析器中写出每个大小写和组。我来试一试。谢谢你的帮助!你是说还提供了可以解析字符串参数的CommandFactory函数重载?我喜欢。。。。