예제 #1
0
파일: Assembler.cs 프로젝트: arlm/MixEmul
        public static InstructionInstanceBase Assemble(string instructionLine, int locationCounter, out ParsedSourceLine parsedLine, SymbolCollection symbols, out AssemblyFindingCollection findings)
        {
            var status = new ParsingStatus(symbols)
            {
                LocationCounter = locationCounter,
                LineNumber      = 0
            };

            parsedLine = Parser.ParseInstructionLine(instructionLine, status);
            findings   = status.Findings;

            // if errors were found while parsing, abort assembly
            if (status.Findings.ContainsErrors)
            {
                return(null);
            }

            if (!parsedLine.IsDefined)
            {
                status.Findings.Add(new AssemblyError(0, LineSection.EntireLine, 0, 0, new ValidationError("line is not an instruction")));
                return(null);
            }

            status.LocationCounter = locationCounter;
            status.LineNumber      = 0;
            var instructionInstance = parsedLine.CreateInstance(status);

            // if errors were found while assembling, don't return the instruction instance: it would be useless anyway
            if (status.Findings.ContainsErrors)
            {
                return(null);
            }

            return(instructionInstance);
        }
예제 #2
0
파일: Parser.cs 프로젝트: arlm/MixEmul
        static SymbolBase ParseLocField(string locField, ParsingStatus status)
        {
            if (locField == "")
            {
                return(null);
            }

            status.LineSection = LineSection.LocationField;

            var symbol = ValueSymbol.ParseDefinition(locField, 0, status);

            if (symbol == null)
            {
                status.ReportParsingError(0, locField.Length, "invalid symbol name");
                return(null);
            }

            if (status.Symbols.Contains(symbol))
            {
                symbol = status.Symbols[symbol.Name];

                if (symbol.IsSymbolDefined && !symbol.IsMultiValuedSymbol)
                {
                    status.ReportParsingError(0, locField.Length, "symbol already defined");
                    return(null);
                }

                return(symbol);
            }

            status.Symbols.Add(symbol);
            return(symbol);
        }
예제 #3
0
파일: Parser.cs 프로젝트: arlm/MixEmul
        public static PreInstruction[] ParseSource(string[] sourceLines, ParsingStatus status)
        {
            status.LocationCounter = 0;
            int endLineNumber   = -1;
            var preInstructions = new List <PreInstruction>();

            for (int lineNumber = 0; lineNumber < sourceLines.Length; lineNumber++)
            {
                status.LineNumber = lineNumber;

                if (endLineNumber != -1 && !IsCommentLine(sourceLines[lineNumber]))
                {
                    status.ReportParsingWarning(LineSection.CommentField, 0, sourceLines[lineNumber].Length, "END has been parsed; line will be treated as comment");
                    preInstructions.Add(new ParsedSourceLine(lineNumber, sourceLines[lineNumber]));
                }
                else
                {
                    var parsedLine = ParseLine(sourceLines[lineNumber], status);
                    preInstructions.Add(parsedLine);
                    if (parsedLine.OpField == "END")
                    {
                        endLineNumber = preInstructions.Count - 1;
                    }
                }
            }

            if (endLineNumber == -1)
            {
                status.Findings.Add(new AssemblyError(int.MinValue, LineSection.CommentField, 0, 0, new ParsingError("END operation is mandatory but not included")));
            }
            else
            {
                // all symbols that are not yet defined at the end of the parsing process are treated as if "<symbolname> CON *" instructions were included just before the END instruction
                foreach (SymbolBase symbol in status.Symbols)
                {
                    if (!symbol.IsSymbolDefined)
                    {
                        symbol.SetValue(status.LocationCounter);

                        var parameters  = new LoaderInstructionParameters(new NumberValue(symbol.MemoryWordSign, symbol.MemoryWordMagnitude), 0);
                        var instruction = new PreInstruction(mLoaderInstructions["CON"], parameters);

                        preInstructions.Insert(endLineNumber, instruction);
                        status.LocationCounter++;
                        endLineNumber++;
                    }
                }
            }

            return(preInstructions.ToArray());
        }
예제 #4
0
파일: Parser.cs 프로젝트: arlm/MixEmul
        static ParsedSourceLine ParseLine(string sourceLine, ParsingStatus status)
        {
            if (IsCommentLine(sourceLine))
            {
                return(new ParsedSourceLine(status.LineNumber, sourceLine));
            }

            var lineFields = SplitLine(sourceLine);

            lineFields[locFieldIndex]     = lineFields[locFieldIndex].ToUpper();
            lineFields[opFieldIndex]      = lineFields[opFieldIndex].ToUpper();
            lineFields[addressFieldIndex] = lineFields[addressFieldIndex].ToUpper();

            if (lineFields[opFieldIndex] == "")
            {
                status.ReportParsingError(LineSection.LocationField, 0, sourceLine.Length, "op and address fields are missing");

                return(new ParsedSourceLine(status.LineNumber, lineFields[0], "", "", "", null, null));
            }

            var symbol = ParseLocField(lineFields[locFieldIndex], status);

            // if the location field contains a symbol name, set its value to the location counter
            symbol?.SetValue(status.LocationCounter);

            GetMixOrLoaderInstructionAndParameters(lineFields[opFieldIndex], lineFields[addressFieldIndex], status, out InstructionBase instruction, out IInstructionParameters instructionParameters);

            // the following call must be made even if a MIX or loader instruction was found, as some loader instructions require the assembler to act, as well
            var assemblyInstructionHandled = HandleAssemblyInstruction(lineFields[opFieldIndex], lineFields[addressFieldIndex], symbol, status);

            // if the line isn't a comment or a MIX or loader instruction, it must be an assembler instruction. If not, we don't know the mnemonic
            if (instruction == null && !assemblyInstructionHandled)
            {
                status.ReportParsingError(LineSection.OpField, 0, lineFields[opFieldIndex].Length, "operation mnemonic unknown");
            }

            return(new ParsedSourceLine(status.LineNumber, lineFields[locFieldIndex], lineFields[opFieldIndex], lineFields[addressFieldIndex], lineFields[commentFieldIndex], instruction, instructionParameters));
        }
예제 #5
0
파일: Assembler.cs 프로젝트: arlm/MixEmul
        public static InstructionInstanceBase[] Assemble(string[] sourceLines, out PreInstruction[] preInstructions, out SymbolCollection symbols, out AssemblyFindingCollection findings)
        {
            var list   = new List <InstructionInstanceBase>();
            var status = new ParsingStatus();

            preInstructions = Parser.ParseSource(sourceLines, status);
            findings        = status.Findings;
            symbols         = null;

            // if errors were found during parsing, abort assembly
            if (status.Findings.ContainsErrors)
            {
                return(null);
            }

            status.LocationCounter = 0;
            status.LineNumber      = 0;

            // compose the instruction instances based on the preinstructions returned by the parser
            foreach (PreInstruction instruction in preInstructions)
            {
                if (instruction.IsDefined)
                {
                    var parsedSourceLine = instruction as ParsedSourceLine;

                    status.LineNumber = parsedSourceLine != null ? parsedSourceLine.LineNumber : sourceLines.Length;
                    var instructionInstance = instruction.CreateInstance(status);

                    if (parsedSourceLine != null && instructionInstance != null)
                    {
                        string sourceLineText = parsedSourceLine.LocationField + new string(' ', Math.Max(Parser.MinLocLength - parsedSourceLine.LocationField.Length, 0) + Parser.FieldSpacing);
                        sourceLineText += parsedSourceLine.OpField + new string(' ', Math.Max(Parser.MinOpLength - parsedSourceLine.OpField.Length, 0) + Parser.FieldSpacing);
                        sourceLineText += parsedSourceLine.AddressField + new string(' ', Math.Max(Parser.MinAddressLength - parsedSourceLine.AddressField.Length, 0) + Parser.FieldSpacing);
                        sourceLineText += parsedSourceLine.Comment;

                        instructionInstance.SourceLine = sourceLineText;
                    }

                    list.Add(instructionInstance);

                    if (instructionInstance != null && instructionInstance.Instruction is LoaderInstruction)
                    {
                        var loaderInstruction = (LoaderInstruction)instructionInstance.Instruction;

                        if (loaderInstruction.Operation == LoaderInstruction.Operations.SetLocationCounter)
                        {
                            status.LocationCounter = (int)((LoaderInstruction.Instance)instructionInstance).Value.LongValue;
                            continue;
                        }

                        // in case the PC is set by this instruction instance, prevent the location counter from being increased
                        if (loaderInstruction.Operation == LoaderInstruction.Operations.SetProgramCounter)
                        {
                            continue;
                        }
                    }

                    status.LocationCounter++;
                }
            }

            // if errors were found during assembly, don't return the instruction instances: they would be useless anyway
            if (status.Findings.ContainsErrors)
            {
                return(null);
            }

            symbols = new SymbolCollection();
            foreach (SymbolBase symbol in status.Symbols)
            {
                if (symbol is ValueSymbol)
                {
                    symbols.Add(symbol);
                }
            }

            status.Findings.Add(new AssemblyInfo("assembly completed successfully", int.MinValue, LineSection.EntireLine, 0, 0));
            return(list.ToArray());
        }
예제 #6
0
파일: Parser.cs 프로젝트: arlm/MixEmul
        /// <summary>
        /// This method is used to handle instructions targeted at the assembler itself.
        /// </summary>
        static bool HandleAssemblyInstruction(string opField, string addressField, SymbolBase symbol, ParsingStatus status)
        {
            IValue expression;

            status.LineSection = LineSection.AddressField;
            switch (opField)
            {
            case "EQU":
                // set value of the instruction symbol (first field) to the value of the expression that is in the address field
                if (symbol != null)
                {
                    expression = WValue.ParseValue(addressField, 0, status);

                    if (!expression.IsValueDefined(status.LocationCounter))
                    {
                        status.ReportParsingError(0, addressField.Length, "expression value is undefined");
                        return(true);
                    }

                    symbol.SetValue(expression.GetSign(status.LocationCounter), expression.GetMagnitude(status.LocationCounter));
                }

                return(true);

            case "ORIG":
                // set the location counter to the value of the expression that is in the address field
                expression = WValue.ParseValue(addressField, 0, status);

                if (!expression.IsValueDefined(status.LocationCounter))
                {
                    status.ReportParsingError(0, addressField.Length, "expression value is undefined");
                    return(true);
                }

                status.LocationCounter = (int)expression.GetValue(status.LocationCounter);

                return(true);

            case "CON":
            case "ALF":
                // these instructions set the value of the memory word at the location counter, which is actually a loader instruction.
                // However, during assembly these memory words must be skipped, which is why we increase the location counter.
                status.LocationCounter++;

                return(true);
            }

            return(false);
        }
예제 #7
0
파일: Parser.cs 프로젝트: arlm/MixEmul
 /// <summary>
 /// This method parses an "in-memory" instruction. That is: an instruction without a location field.
 /// </summary>
 public static ParsedSourceLine ParseInstructionLine(string instructionLine, ParsingStatus status) =>
 // add an empty location field, then parse as usual.
 ParseLine(" " + instructionLine, status);
예제 #8
0
파일: Parser.cs 프로젝트: arlm/MixEmul
        static void GetMixOrLoaderInstructionAndParameters(string opField, string addressField, ParsingStatus status, out InstructionBase instruction, out IInstructionParameters instructionParameters)
        {
            status.LineSection    = LineSection.AddressField;
            instructionParameters = null;

            instruction = mLoaderInstructions[opField];

            if (instruction != null)
            {
                instructionParameters = LoaderInstructionParameters.ParseAddressField(instruction, addressField, status);
            }
            else
            {
                instruction = mInstructionSet[opField];

                if (instruction != null)
                {
                    instructionParameters = MixInstructionParameters.ParseAddressField(instruction, addressField, status);
                    status.LocationCounter++;
                }
            }
        }