The best way to create this loop?

I am creating a simple assembly compiler for my own assembly taste and I have something like this as the actual code that does the compilation:

    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;
            ...
        }
        ...
    }

      

I feel like I'm breaking about half a dozen design rules (reusing variables and waiting for correct input are the only ones I can spot, but I'm sure there is more) but have no idea how to build it better, Ideas?

+2


source to share


3 answers


Consider outputting logic to interpret parameters in the CommandFactory. The switch statement looks like this:



switch(instruction)
{
    case "load":
        currentCommand = CommandFactory.CreateLoadCommand(parameters);
        break;
    case "input":
        currentCommand = CommandFactory.CreateInputCommand(parameters);
        break;
    case "output":
        currentCommand = CommandFactory.CreateOutputCommand(parameters);
        break;
}

      

+5


source


You might consider tossing a couple of things like a tokenizer that returns your program as a string of tokens (your splitter does this). Then pass that to the parser to create the parse tree and symbol table. What for? because without knowing your assembly taste, at some point you will want to jump to the label (subroutine) which I would assume. or do you want your jump command to go back to the beginning of the loop, etc.



If you have the parse tree and symbol table installed, you will have all the addresses so they can be easily inserted into your output file. It's been a long time since I wrote the compiler, so please forgive any deviations in my little example ...

+4


source


Move the instruction information to the class / property package. Create some useful conversion techniques to make your life easier. Then use the string -> delegate dictionary to map the command name to command creation. This is just the beginning, you can refactor this much easier.

Something along these lines, perhaps:

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);
            }
        }
    }

    // ...
}

      

0


source







All Articles