csharp/a-downing/MicroVM/MicroVM.Assembler.cs

MicroVM.Assembler.cs
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace MicroVM {
    clast astembler {
        List statements = new List();
        public Dictionary symbols = new Dictionary();
        public List errors = new List();
        public List programData = new List();
        public List instructions = new List();
        public List code = new List();
        public byte[] memory = null;
        public int numInstructions;
        List isrs = new List();

        Regex directiveRegex = new Regex(@"^\.([a-zA-Z_][a-zA-Z0-9_]*)$");
        Regex labelRegex = new Regex(@"^([a-zA-Z_][a-zA-Z0-9_]*):$");
        Regex identifierRegex = new Regex(@"^[a-zA-Z_][a-zA-Z0-9_]*$");
        Regex instructionRegex = new Regex(@"^([a-zA-Z_][a-zA-Z0-9_]*)\.(al|eq|ne|gt|ge|lt|le)$");
        Regex floatRegex = new Regex(@"^[+-]?[0-9]?[\.][0-9]*$");

        Regex decimalRegex = new Regex(@"^[+-]?[0-9]+$");
        Regex hexRegex = new Regex(@"^([+-])?0x([0-9a-zA-Z]+)$");
        Regex binRegex = new Regex( @"^([+-])?0b([01]+)$");

        public void Reset() {
            statements.Clear();
            symbols.Clear();
            errors.Clear();
            programData.Clear();
            instructions.Clear();
            code.Clear();
            memory = null;
            isrs.Clear();
        }

        struct Statement {
            public int lineNum;
            public string[] line;
            public Token[] tokens;
        }

        public struct Variable {
            public CPU.Value32 val32;
            public Type type;
            public int size;

            public enum Type {
                NONE, UNKNOWN, INT, UINT, BYTE, FLOAT
            }
        }

        struct Token {
            public enum Type {
                NONE,
                DIRECTIVE,
                LABEL,
                INSTRUCTION,
                IDENTIFIER,
                INTEGER,
                FLOAT
            }

            public int offset;
            public Type type;
            public string stringValue;
            public Variable var;
            public string cond;
        }

        public struct Symbol {
            public string name;
            public Variable var;
            public int labelInstructionIndex;
            public Type type;

            public enum Type {
                NONE,
                LABEL,
                LITERAL,
                CONSTANT,
                REGISTER
            }
        }

        public void LoadProgramToCPU(CPU cpu) {
            cpu.Reset();
            cpu.instructions = new uint[numInstructions];
            cpu.memory = new byte[memory.Length];
            memory.CopyTo(cpu.memory, 0);
            cpu.registers[(int)CPU.Register.SP] = (uint)programData.Count;
            cpu.pc = symbols["_start"].var.val32.Uint;
            int instructionIndex = 0;

            for(int i = 0; i < instructions.Count; i++) {
                var instruction = instructions[i];
                cpu.instructions[instructionIndex++] = instruction.Create();

                if(instruction.additionalInstructions == null) {
                    continue;
                }

                for(int j = 0; j < instruction.additionalInstructions.Length; j++) {
                    cpu.instructions[instructionIndex++] = instruction.additionalInstructions[j];
                }
            }

            cpu.flags |= (uint)CPU.Flag.READY;
        }

        public struct Instruction {
            public CPU.Opcode opcode;
            public CPU.Cond cond;
            public List operands;
            public Symbol immediate;
            public int address;
            public uint[] additionalInstructions;

            public int AdditionalInstructions(bool ignoreLabelAddresses) {
                if(immediate.type == Symbol.Type.NONE || (immediate.type == Symbol.Type.LABEL && ignoreLabelAddresses)) {
                    return 0;
                }

                if(immediate.var.type == Variable.Type.FLOAT) {
                    return 1;
                } else if(immediate.var.type == Variable.Type.UNKNOWN) {
                    return immediate.var.size / sizeof(uint);
                } else if(immediate.var.type == Variable.Type.INT) {
                    if(immediate.var.val32.Uint >= GetMaxImmediateValue(operands.Count + 1)) {
                        return 1;
                    }
                }

                return 0;
            }

            public uint Create() {
                uint instruction = (uint)cond