Example #1
0
        public static List <string> Parse(List <string> unchecked_assembly, string InstructionSetName = DefaultInstructionSetName)
        {
            // Get Instruction Set
            InstructionSet iset = OpCodeLoader.GetSet(InstructionSetName);

            // *********************************************************************
            // Sanitize                                                            *
            // *********************************************************************

            // Remove Blank Lines
            unchecked_assembly.RemoveAll(s => s == null);
            unchecked_assembly.RemoveAll(s => Regex.IsMatch(s, "^\\s*$"));

            // Remove Newline Comments
            unchecked_assembly.RemoveAll(s => s[0] == '#');

            for (int i = 0; i < unchecked_assembly.Count; i++)
            {
                // *******************************
                // Trim Whitespace               *
                // *******************************

                // Outter Whitespace
                unchecked_assembly[i] = unchecked_assembly[i].Trim();

                // Inner Whitspace
                unchecked_assembly[i] = Regex.Replace(unchecked_assembly[i], "\\s{2,}", " ");
                // *******************************

                // *******************************
                // Remove Inline Comments
                // *******************************
                unchecked_assembly[i] = Regex.Replace(unchecked_assembly[i], "\\s*#.*$", "");
                // *******************************
            }
            // *********************************************************************

            // *********************************************************************
            // Validate
            // *********************************************************************

            //if is not valid, will throw execptions for CLI to catch and display to user
            _ = IsValid(unchecked_assembly, iset);
            // *********************************************************************

            // *********************************************************************
            // Assemble
            // *********************************************************************
            List <string> binary = new List <string>();

            int lines_of_asm = unchecked_assembly.Count;

            int current_line_number = 0;

            foreach (string line in unchecked_assembly)
            {
                if (line == "...")
                {
                    int nop_count = 16 - lines_of_asm + 1;
                    for (int i = 0; i < nop_count; i++)
                    {
                        binary.Add("00000000");
                    }
                }
                else
                {
                    string upper_nibble_asm = line.Split(" ", 2)[0];
                    string lower_nibble_asm = line.Split(" ", 2)[1];
                    string upper_nibble_bin = "";
                    string lower_nibble_bin = "";

                    // Convert Upper Nibble
                    if (InstructionValidator.IsValidInstruction(upper_nibble_asm, iset))     // Is instruction
                    {
                        upper_nibble_bin = InstructionValidator.GetUpperNibble(line.Substring(0, 3), iset);
                    }
                    else if (Regex.IsMatch(upper_nibble_asm, "^0[xX][0-9a-fA-F]$"))                    // Is Data
                    {
                        int value_upper = (int)(Convert.ToUInt32(upper_nibble_asm, 16));
                        upper_nibble_bin = BinConverter.IntToBin4(value_upper);
                    }

                    // Convert Lower Nibble
                    int value_lower = (int)(Convert.ToUInt32(lower_nibble_asm, 16));
                    lower_nibble_bin = BinConverter.IntToBin4(value_lower);

                    binary.Add(upper_nibble_bin + lower_nibble_bin);
                }

                current_line_number++;
            }
            // *********************************************************************

            //If a program was executed, but didnt fill in every line of RAM then throw an exception. Must have 16 elements!
            if (binary.Count != 16)
            {
                throw new ParseException($"SAP1ASM: Program must have 16 lines.", new ParseException("Use \"NOP 0x0\" for a no-operation command or the \"...\" macro to fill in the rest with NOP 0x0."));
            }

            return(binary);
        }
Example #2
0
        private static bool IsValid(List <string> unchecked_assembly, InstructionSet iset)
        {
            bool dot_macro_used = false;
            bool contains_hlt   = false;

            int line_number = 1;

            foreach (string line in unchecked_assembly)
            {
                if (line != "...")
                {
                    string[] nibbles = line.Split(' ', 2);

                    if (nibbles.Length == 0)
                    {
                        throw new ParseException($"SAP1ASM: Line cannot be blank (line: {line_number}).", new ParseException("Use \"NOP 0x0\" for a no-operation command"));
                    }

                    string instruction = nibbles[0];
                    if (instruction.ToUpper() == "HLT")
                    {
                        contains_hlt = true;
                    }
                    if (nibbles.Length < 2)
                    {
                        throw new ParseException($"SAP1ASM: No lower nibble detected (line: {line_number}).", new ParseException($"\"{instruction}\" must be paired with a valid address in the range of 0x0 - 0xF"));
                    }
                    string addr = nibbles[1];

                    // Check Intruction
                    if (instruction.Length != 3)
                    {
                        throw new ParseException($"SAP1ASM: invalid intruction on line {line_number}.", new ParseException($"\"{instruction}\" is not a recognized instruction"));
                    }

                    if (!InstructionValidator.IsValidInstruction(instruction.ToUpper(), iset)) // Check if is valid instruction
                    {
                        if (!Regex.IsMatch(instruction, "^0[xX][0-9a-fA-F]$"))                 // Make sure it isnt data
                        {
                            throw new ParseException($"SAP1ASM: invalid intruction on line {line_number}.", new ParseException($"\"{instruction}\" is not a recognized instruction or valid data"));
                        }
                    }

                    // Check Address
                    if (addr.Length != 3)                                               // should be no more than 3
                    {
                        throw new ParseException($"SAP1ASM: invalid address on line {line_number}.", new ParseException($"\"{addr}\" is not of the form \"0xX\""));
                    }
                    if (!Regex.IsMatch(addr, "^0[xX][0-9a-fA-F]$"))     // should be of the form 0xX
                    {
                        throw new ParseException($"SAP1ASM: invalid address on line {line_number}.", new ParseException($"\"{addr}\" is not of the form \"0xX\""));
                    }
                    int hex_addr = (int)(Convert.ToUInt32(addr.Substring(2, 1), 16));
                    if (hex_addr < 0 || hex_addr >= 16)                                // must tbe between 0-15
                    {
                        throw new ParseException($"SAP1ASM: address out of range on line {line_number}.", new ParseException($"\"{addr}\" must be betweeen 0x0 and 0xF"));
                    }

                    if (line.Contains("..."))
                    {
                        throw new ParseException($"SAP1ASM: invalid use of \"...\" on line {line_number}.", new ParseException($"\"{line}\" must only contain \"...\" with no extra charecters or spaces"));
                    }
                }
                else
                {
                    if (!dot_macro_used)
                    {
                        dot_macro_used = true;
                    }
                    else
                    {
                        throw new ParseException($"SAP1ASM: invalid use of \"...\" {line_number}.", new ParseException($"\"{line}\" must only contain once instance of \"...\" in the program"));
                    }
                }

                line_number++;
            }

            // If the code does not contain a HLT instruction
            if (!contains_hlt)
            {
                throw new ParseException($"SAP1ASM: program does not contain an endpoint.", new ParseException($"\"HLT\" must be present in the program at least once"));
            }

            return(true);
        }