Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 设计这个循环的更好方法?_.net - Fatal编程技术网

.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函数重载?我喜欢。。。。