예제 #1
0
        private ParsedPragma ParseFor(List <List <Token> > lines, int startAddr, int currentLoopNum)
        {
            ParsedPragma result = new ParsedPragma();

            List <ParsedInstruction> firstPassInstrs = new List <ParsedInstruction>();
            int addr = startAddr;

            for (int ln = 0; ln < lines.Count; ln++)
            {
                List <Token> line = lines[ln];
                Token        op   = line[0];
                if (op.Type == TokenType.OpCode)
                {
                    if (mnemonicFormat.ContainsKey(op.Value))
                    {
                        MnemonicFormat instrFormat = mnemonicFormat[op.Value];
                        // Check if the number of operands is correct, remembering to
                        // account for the fact that the first token in the line was our
                        // opcode token
                        if (line.Count == instrFormat.OperandCount + 1)
                        {
                            ParsedInstruction parsedInstr = new ParsedInstruction(op.Value, op.LineNumber);
                            for (int i = 0; i < instrFormat.OperandCount; i++)
                            {
                                Token operand = line[i + 1];
                                if ((instrFormat.OperandTypes[i] & operand.Type) == operand.Type)
                                {
                                    Operand o = new Operand(operand.Value, EnumConv.TokenToOperandType(operand.Type));
                                    parsedInstr.Operands.Add(o);
                                }
                            }
                            firstPassInstrs.Add(parsedInstr);
                            addr += instrFormat.IWCount;
                        }
                    }
                }
                else if (op.Type == TokenType.Label)
                {
                    labelLocations.Add(op.Value, addr);
                }
                else if (op.Type == TokenType.Pragma)
                {
                    // We'll hardcode this for now but come back and make it general later
                    if (op.Value == "for" && line.Count == 5)
                    {
                        ParsedInstruction subInstr = new ParsedInstruction("sub", 0);
                        Token             loopReg  = line[1];
                        if (loopReg.Type != TokenType.RegName)
                        {
                            // Throw an error
                            throw new Exception("FOR loop token type mismatch - first argument not a register.");
                        }
                        // Subtract the register from itself to clear it
                        subInstr.Operands.Add(new Operand(loopReg.Value, OperandType.Register));
                        subInstr.Operands.Add(new Operand(loopReg.Value, OperandType.Register));
                        addr++; // SUB is one word long

                        ParsedInstruction addcInstr = new ParsedInstruction("addc", 0);
                        Token             startVal  = line[2];
                        if (startVal.Type != TokenType.Label && startVal.Type != TokenType.Constant)
                        {
                            if (startVal.Type == TokenType.RegName)
                            {
                                addcInstr = new ParsedInstruction("add", 0);
                            }
                            else
                            {
                                throw new Exception("FOR loop token type mismatch - second argument not a constant or label.");
                            }
                        }
                        addcInstr.Operands.Add(new Operand(loopReg.Value, OperandType.Register));
                        addcInstr.Operands.Add(new Operand(startVal.Value, EnumConv.TokenToOperandType(startVal.Type)));
                        addr++;

                        firstPassInstrs.Add(subInstr);
                        firstPassInstrs.Add(addcInstr);

                        int thisLoopNum = forLoopNum;
                        labelLocations.Add($"@@@FOR_LOOP_NUM_{thisLoopNum}", addr);
                        forLoopNum++;
                        List <List <Token> > restOfLines = new List <List <Token> >();
                        restOfLines.AddRange(lines.Skip(ln + 1));
                        ParsedPragma parsedFor = ParseFor(restOfLines, addr, thisLoopNum);

                        firstPassInstrs.AddRange(parsedFor.ParsedInstructions);
                        addr = parsedFor.NewAddrOffset;
                        ln  += parsedFor.LinesParsed;

                        Operand regOp   = new Operand(line[1].Value, EnumConv.TokenToOperandType(line[1].Type));
                        Operand startOp = new Operand(line[2].Value, EnumConv.TokenToOperandType(line[2].Type));
                        Operand loopOp  = new Operand(line[3].Value, EnumConv.TokenToOperandType(line[3].Type));
                        Operand incOp   = new Operand(line[4].Value, EnumConv.TokenToOperandType(line[4].Type));

                        List <ParsedInstruction> forInstrs = GenerateForCode(regOp, loopOp, incOp, thisLoopNum);
                        firstPassInstrs.AddRange(forInstrs);
                        addr += 10;

                        labelLocations.Add($"@@@END_FOR_LOOP_NUM_{thisLoopNum}", addr);
                    }
                    else if (op.Value == "endfor")
                    {
                        result.ParsedInstructions = firstPassInstrs;
                        result.NewAddrOffset      = addr;
                        result.LinesParsed        = ln + 1;
                        return(result);
                    }
                }
            }

            throw new Exception("Error: endfor not detected to match start of FOR loop");

            // throw new NotImplementedException();
        }
예제 #2
0
        private List <Operation> ParseCode(int startAddr = 0)
        {
            int addr = startAddr;
            List <ParsedInstruction> firstPassInstrs = new List <ParsedInstruction>();

            for (int ln = 0; ln < code.Count; ln++)
            {
                List <Token> line = code[ln];
                Token        op   = line[0];
                if (op.Type == TokenType.OpCode)
                {
                    if (mnemonicFormat.ContainsKey(op.Value))
                    {
                        MnemonicFormat instrFormat = mnemonicFormat[op.Value];
                        // Check if the number of operands is correct, remembering to
                        // account for the fact that the first token in the line was our
                        // opcode token
                        if (line.Count == instrFormat.OperandCount + 1)
                        {
                            ParsedInstruction parsedInstr = new ParsedInstruction(op.Value, op.LineNumber);
                            for (int i = 0; i < instrFormat.OperandCount; i++)
                            {
                                Token operand = line[i + 1];
                                if ((instrFormat.OperandTypes[i] & operand.Type) == operand.Type)
                                {
                                    Operand o = new Operand(operand.Value, EnumConv.TokenToOperandType(operand.Type));
                                    parsedInstr.Operands.Add(o);
                                }
                            }
                            firstPassInstrs.Add(parsedInstr);
                            addr += instrFormat.IWCount;
                        }
                        else
                        {
                            throw new ParserException($"ERROR: Expected {instrFormat.OperandCount} parameters on line "
                                                      + $"{op.LineNumber} for instruction {op.Value}. {line.Count - 1} parameters found.", op.LineNumber, line.Count);
                        }
                    }
                    else
                    {
                        throw new ParserException($"ERROR: Unknown mnemonic {op.Value} on line {op.LineNumber}.", op.LineNumber, 0);
                    }
                }
                else if (op.Type == TokenType.Label)
                {
                    labelLocations.Add(op.Value, addr);
                }
                else if (op.Type == TokenType.Pragma)
                {
                    // We'll hardcode this for now but come back and make it general later
                    if (op.Value == "for" && line.Count == 5)
                    {
                        ParsedInstruction subInstr = new ParsedInstruction("sub", 0);
                        Token             loopReg  = line[1];
                        if (loopReg.Type != TokenType.RegName)
                        {
                            // Throw an error
                            throw new Exception("FOR loop token type mismatch - first argument not a register.");
                        }
                        // Subtract the register from itself to clear it
                        subInstr.Operands.Add(new Operand(loopReg.Value, OperandType.Register));
                        subInstr.Operands.Add(new Operand(loopReg.Value, OperandType.Register));
                        addr++; // SUB is one word long

                        ParsedInstruction addcInstr = new ParsedInstruction("addc", 0);
                        Token             startVal  = line[2];
                        if (startVal.Type != TokenType.Label && startVal.Type != TokenType.Constant)
                        {
                            if (startVal.Type == TokenType.RegName)
                            {
                                addcInstr = new ParsedInstruction("add", 0);
                            }
                            else
                            {
                                throw new Exception("FOR loop token type mismatch - second argument not a constant or label.");
                            }
                        }
                        addcInstr.Operands.Add(new Operand(loopReg.Value, OperandType.Register));
                        addcInstr.Operands.Add(new Operand(startVal.Value, EnumConv.TokenToOperandType(startVal.Type)));
                        addr++;

                        firstPassInstrs.Add(subInstr);
                        firstPassInstrs.Add(addcInstr);

                        int currentLoopNum = forLoopNum;
                        labelLocations.Add($"@@@FOR_LOOP_NUM_{currentLoopNum}", addr);
                        forLoopNum++;
                        List <List <Token> > restOfLines = new List <List <Token> >();
                        restOfLines.AddRange(code.Skip(ln + 1));
                        ParsedPragma parsedFor = ParseFor(restOfLines, addr, currentLoopNum);

                        firstPassInstrs.AddRange(parsedFor.ParsedInstructions);
                        addr = parsedFor.NewAddrOffset;
                        ln  += parsedFor.LinesParsed;

                        Operand regOp   = new Operand(line[1].Value, EnumConv.TokenToOperandType(line[1].Type));
                        Operand startOp = new Operand(line[2].Value, EnumConv.TokenToOperandType(line[2].Type));
                        Operand loopOp  = new Operand(line[3].Value, EnumConv.TokenToOperandType(line[3].Type));
                        Operand incOp   = new Operand(line[4].Value, EnumConv.TokenToOperandType(line[4].Type));

                        List <ParsedInstruction> forInstrs = GenerateForCode(regOp, loopOp, incOp, currentLoopNum);
                        firstPassInstrs.AddRange(forInstrs);
                        addr += 10;

                        labelLocations.Add($"@@@END_FOR_LOOP_NUM_{currentLoopNum}", addr);
                    }
                    else if (op.Value != "for")
                    {
                        throw new ParserException($"ERROR: Unsupported pragma {op.Value} on line {op.LineNumber}.", op.LineNumber, 0);
                    }
                    else
                    {
                        throw new ParserException($"ERROR: Invalid number of arguments for FOR loop on line " +
                                                  $"{op.LineNumber}. Expected 4 arguments, received {line.Count - 1}.", op.LineNumber, 0);
                    }
                }
                else
                {
                    throw new ParserException($"ERROR: Unsupported token type {op.Type} on line {op.LineNumber}.", op.LineNumber, 0);
                }
            }

            List <Operation> parsedOps = new List <Operation>();

            foreach (ParsedInstruction instr in firstPassInstrs)
            {
                Opcodes opName = EnumConv.StringToOpcode(instr.Name);
                if (Operation.ManipOpcodes.Contains(opName))
                {
                    int Ri = 0;
                    int Rj = 0;
                    // The Ri operand must always be a register, so we'll just
                    // check that and assign Ri easily
                    if (instr.Operands[0].Type != OperandType.Register)
                    {
                        throw new ParserException($"ERROR: Invalid Ri operand type {instr.Operands[0].Type} for instruction {instr.Name}.",
                                                  instr.LineNumber, 1);
                    }
                    Ri = int.Parse(instr.Operands[0].Value);
                    // Next we'll assign Rj, which can have a few types
                    // If Rj doesn't exist, it's fine, we can just keep it as 0.
                    // We have NOT which only takes one operand.
                    if (instr.Operands.Count > 1)
                    {
                        if (instr.Operands[1].Type == OperandType.Register || instr.Operands[1].Type == OperandType.Constant)
                        {
                            Rj = int.Parse(instr.Operands[1].Value);
                        }
                        else if (instr.Operands[1].Type == OperandType.Label)
                        {
                            if (dirDict.ContainsKey(instr.Operands[1].Value))
                            {
                                Rj = int.Parse(dirDict[instr.Operands[1].Value]);
                            }
                            else
                            {
                                throw new ParserException($"ERROR: Invalid label {instr.Operands[1].Value} on line {instr.LineNumber}.", instr.LineNumber, 2);
                            }
                        }
                        else
                        {
                            throw new ParserException($"ERROR: Invalid Rj operand type {instr.Operands[1].Type} for instruction {instr.Name}.",
                                                      instr.LineNumber, 2);
                        }
                    }

                    parsedOps.Add(new ManipulationOperation(Ri, Rj, opName));
                }
                else if (Operation.MemOpcodes.Contains(opName))
                {
                    int Ri     = 0;
                    int Rj     = 0;
                    int offset = 0;
                    // Ri and Rj must be registers
                    Ri = int.Parse(instr.Operands[0].Value);
                    Rj = int.Parse(instr.Operands[1].Value);
                    // Offset can be a hard-coded or labeled constant
                    if (instr.Operands[2].Type == OperandType.Constant)
                    {
                        offset = int.Parse(instr.Operands[2].Value);
                    }
                    else if (instr.Operands[2].Type == OperandType.Label)
                    {
                        if (dirDict.ContainsKey(instr.Operands[2].Value))
                        {
                            offset = int.Parse(dirDict[instr.Operands[2].Value]);
                        }
                        else
                        {
                            throw new ParserException($"ERROR: Invalid label {instr.Operands[2].Value} on line {instr.LineNumber}.", instr.LineNumber, 3);
                        }
                    }
                    else
                    {
                        throw new ParserException($"ERROR: Invalid operand type {instr.Operands[2].Type} for instruction {instr.Name} on line {instr.LineNumber}.",
                                                  instr.LineNumber, 3);
                    }

                    parsedOps.Add(new MemoryOperation(Ri, Rj, offset, opName));
                }
                else if (Operation.MethodOpcodes.Contains(opName))
                {
                    int offset = 0;
                    if (instr.Operands.Count > 0)
                    {
                        if (instr.Operands[0].Type == OperandType.Constant)
                        {
                            offset = int.Parse(instr.Operands[0].Value);
                        }
                        else if (instr.Operands[0].Type == OperandType.Label)
                        {
                            if (labelLocations.ContainsKey(instr.Operands[0].Value))
                            {
                                offset = labelLocations[instr.Operands[0].Value];
                            }
                            else
                            {
                                throw new ParserException($"ERROR: Invalid label {instr.Operands[0].Value} on line {instr.LineNumber}.", instr.LineNumber, 1);
                            }
                        }
                        else
                        {
                            throw new ParserException($"ERROR: Invalid operand type {instr.Operands[0].Type} for instruction {instr.Name} on line {instr.LineNumber}.",
                                                      instr.LineNumber, 1);
                        }
                    }

                    parsedOps.Add(new MethodOperation(offset, opName));
                }
                else if (Operation.StackOpcodes.Contains(opName))
                {
                    int Ri = int.Parse(instr.Operands[0].Value);
                    parsedOps.Add(new StackOperation(Ri, opName));
                }
                else if (opName == Opcodes.JMP)
                {
                    JumpTypes jmpType = EnumConv.StringToJumpType(instr.Name);
                    int       offset  = 0;
                    // This assembler will only allow direct AM, so Ri=0 and
                    // offset can be a constant or label
                    if (instr.Operands[0].Type == OperandType.Constant)
                    {
                        offset = int.Parse(instr.Operands[0].Value);
                    }
                    else if (instr.Operands[0].Type == OperandType.Label)
                    {
                        if (labelLocations.ContainsKey(instr.Operands[0].Value))
                        {
                            offset = labelLocations[instr.Operands[0].Value];
                        }
                        else
                        {
                            throw new ParserException($"ERROR: Invalid label {instr.Operands[0].Value} on line {instr.LineNumber}.", instr.LineNumber, 1);
                        }
                    }
                    else
                    {
                        throw new ParserException($"ERROR: Invalid operand type {instr.Operands[0].Type} for instruction {instr.Name} on line {instr.LineNumber}.",
                                                  instr.LineNumber, 1);
                    }

                    parsedOps.Add(new JumpOperation(0, offset, jmpType));
                }
            }

            return(parsedOps);
        }