Beispiel #1
0
 /**
  * Add a modification record to this object file.
  *
  * @param record The modification record to add
  * @refcode OB
  * @errtest
  *  N/A
  * @errmsg
  *  N/A
  * @author Jacob Peddicord
  * @creation May 10, 2011
  * @modlog
  * @teststandard Andrew Buelow
  * @codestandard Mark Mathis
  */
 private void AddRecord(ModificationRecord record)
 {
     this.modificationRecords.Add(record);
 }
Beispiel #2
0
        /**
         * Scan and the source (pass 2) and generate text and modification
         * records as apporpriate.
         *
         * @refcode OB
         * @errtest
         *  N/A
         * @errmsg
         *  N/A
         * @author Jacob Peddicord
         * @creation May 9, 2011
         * @modlog
         *  - May 10, 2011 - Jacob - Implemented some modification record things
         *  - May 10, 2011 - Jacob - Refactored line iteration a bit
         *  - May 11, 2011 - Jacob - Fix how we determine the type and number of modifications
         *  - May 13, 2011 - Mark  - Implement expression processing
         *  - May 13, 2011 - Mark  - Fix one of the expression cases with modifications
         *  - May 14, 2011 - Mark  - Implement ADC/e!
         *  - May 14, 2011 - Mark  - Adjust error handling code
         * @teststandard Andrew Buelow
         * @codestandard Mark Mathis
         */
        private void GenerateSourceRecords()
        {
            foreach (IntermediateLine line in this.input)
            {
                //Console.WriteLine(this.SourceLine)
                // skip lines that won't be in the object file
                if (line.ProgramCounter == null)
                {
                    // special case: RESET directive should generate a linking record
                    if (line.Directive == "RESET" && line.GetThreeErrors().Count == 0)
                    {
                        var record = new LinkingRecord(this.symb.ProgramName);
                        record.EntryName = line.Label;
                        // set the location to the target of the RESET
                        record.ProgramLocation = line.DirectiveOperand;
                        this.AddRecord(record);
                    }

                    // store the rest in the report
                    List<Errors.Error> errors = line.GetThreeErrors();
                    this.report.Add(null, null, ' ',
                        line.SourceLineNumber, line.SourceLine, errors);
                    continue;
                }

                // create the text record
                TextRecord rec = new TextRecord(this.symb.ProgramName);
                rec.ProgramLocation = line.ProgramCounter;
                rec.StatusFlag = 'A';
                rec.Adjustments = "0";
                string bin = line.Bytecode;

                // do we have an instruction?
                if (line.OpCategory != null)
                {
                    // equated symbols may need to be relocated
                    if (line.Equated != null)
                    {
                        Symbol symb = this.symb.GetSymbol(line.Equated);
                        if (symb.relocations == 0)
                        {
                            rec.StatusFlag = 'A';
                            rec.Adjustments = "0";
                        }
                        else if (symb.relocations == 1)
                        {
                            rec.StatusFlag = 'R';
                            rec.Adjustments = "0";
                        }
                        else
                        {
                            ModificationRecord mod = new ModificationRecord(this.symb.ProgramName);
                            mod.ProgramLocation = line.ProgramCounter;
                            mod.Word = Convert.ToString(Convert.ToInt32(line.Bytecode, 2), 16);
                            for (int i = 0; i < symb.relocations; i++)
                            {
                                mod.AddAdjustment(true, this.symb.ProgramName);
                            }
                            this.AddRecord(mod);
                            rec.StatusFlag = 'M';
                            rec.Adjustments = Convert.ToString(symb.relocations, 16);
                        }
                    }
                    // or a plain label
                    else if (line.OpLitOperand == OperandParser.Literal.NONE)
                    {
                        // get the symbol that is being referenced
                        if (line.OpOperand != null && this.symb.ContainsSymbol(line.OpOperand))
                        {
                            Symbol symb = this.symb.GetSymbol(line.OpOperand);
                            // external labels are processed in the linker
                            if (symb.usage == Usage.EXTERNAL) {
                                // create a modification record
                                ModificationRecord mod = new ModificationRecord(this.symb.ProgramName);
                                mod.ProgramLocation = line.ProgramCounter;
                                mod.Word = Convert.ToString(Convert.ToInt32(line.Bytecode, 2), 16);
                                mod.AddAdjustment(true, symb.rlabel);
                                this.AddRecord(mod);
                                // set the status to 1 modify
                                rec.StatusFlag = 'M';
                                rec.Adjustments = "1";
                            }
                            // otherwise we can resolve the symbol
                            else
                            {
                                // get the binary encoding padded to 10 bits
                                bin = BinaryHelper.BinaryString(symb.lc).PadLeft(10, '0');
                                // prefix it with the original instruction bytecode
                                bin = line.Bytecode.Substring(0, 6) + bin;
                                // relocatable label
                                rec.StatusFlag = 'R';
                            }
                        }
                        // was it empty?
                        else if (line.OpOperand == null || line.OpOperand.Length == 0)
                        {
                            bin = line.Bytecode;
                            rec.StatusFlag = 'A';
                        }
                        // error, otherwise
                        else
                        {
                            line.AddError(Errors.Category.Serious, 34);
                            line.NOPificate();
                            bin = line.Bytecode;
                        }
                    }
                    // otherwise if it is (was) an expression
                    else if (line.OpLitOperand == OperandParser.Literal.EXPRESSION)
                    {
                        // then is is relocatable

                        // get the expression to be evaluated
                        string expr = line.OpOperand;

                        // create the modification record, this will have at least one
                        // adjustment because these expressions are required to have a *
                        ModificationRecord mod = new ModificationRecord(symb.ProgramName);

                        // this is a garbage variable
                        int rel;

                        // evaluate the expression
                        bool worked;
                        worked = OperandParser.ParseExpression(ref expr, OperandParser.Expressions.Operand,
                                                      line, ref symb, mod, out rel);
                        if (worked)
                        {
                            // adjustments and such
                            rec.StatusFlag = 'M';
                            rec.Adjustments = Convert.ToString(mod.Adjustments, 16);

                            // get the hex sorted out
                            int adj = Convert.ToInt32(expr, 16);
                            int bytecode = Convert.ToInt32(bin, 2) + adj;

                            // check the range
                            int start = Convert.ToInt32(this.input.Line(1).DirectiveOperand, 16);
                            int eof = start + Convert.ToInt32(this.input.ModuleLength, 16);
                            if (Convert.ToInt32(expr, 16) > eof || Convert.ToInt32(expr, 16) < start)
                            {
                                line.AddError(Errors.Category.Serious, 38);
                                line.NOPificate();
                            }
                            else
                            {
                                bin = Convert.ToString(bytecode, 2);
                                mod.Word = Convert.ToString(bytecode, 16);
                                mod.ProgramLocation = line.ProgramCounter;
                                this.AddRecord(mod);
                            }
                        }
                        else
                        {

                        }
                    }
                    // special case: numeric values with GOTO, JUMP, MOPER
                    else if (line.OpLitOperand == OperandParser.Literal.NUMBER &&
                             (line.OpFunction == "GOTO" ||
                              line.OpCategory == "JUMP" ||
                              line.OpCategory == "MOPER"))
                    {
                        rec.StatusFlag = 'R';
                    }
                    // otherwise, it was a literal
                    else
                    {
                        rec.StatusFlag = 'A';
                    }
                }
                // or a DAT directive?
                else if (line.Directive == "DAT")
                {
                    // DAT fields shouldn't need to be modified
                    rec.StatusFlag = 'A';
                }
                // or an ADC directive?
                else if (line.Directive == "ADC" || line.Directive == "ADCE")
                {
                    // make the modification record
                    ModificationRecord mod = new ModificationRecord(symb.ProgramName);
                    bool worked = true;
                    string expr = line.DirectiveOperand;
                    int rel = 0;
                    int maxOp = 1;

                    // this differentiates between ADC and ADCe
                    if (line.Directive.EndsWith("E"))
                    {
                        maxOp = 3;
                    }
                    if (line.DirectiveLitOperand == OperandParser.Literal.EXPRESSION)
                    {
                        // wat do if expressions
                        worked = OperandParser.ParseExpression(ref expr, OperandParser.Expressions.ADC, line,
                                                      ref symb, mod, out rel, maxOp);
                        // catching errors
                        if (worked)
                        {
                            bin = Convert.ToString(Convert.ToInt32(expr, 16), 2);
                        }
                    }
                    else if (line.DirectiveLitOperand == OperandParser.Literal.NUMBER)
                    {
                        // wat do if just a number
                        mod.AddAdjustment(true, symb.ProgramName);
                        rel = 1;
                        bin = Convert.ToString(Convert.ToInt32(expr, 16), 2);
                    }

                    // check the range
                    int start = Convert.ToInt32(this.input.Line(1).DirectiveOperand, 16);
                    int eof = start + Convert.ToInt32(this.input.ModuleLength, 16);
                    if (Convert.ToInt32(expr, 16) > eof || Convert.ToInt32(expr, 16) < start)
                    {
                        line.AddError(Errors.Category.Serious, 38);
                        line.NOPificate();
                        bin = "0000000000000000";
                    }

                    // if there are modifications to be made, add them
                    if (mod.Adjustments > 0 && rel > 0 && worked)
                    {
                        rec.StatusFlag = 'M';
                        rec.Adjustments = Convert.ToString(mod.Adjustments, 16);
                        mod.Word = Convert.ToString(Convert.ToInt32(bin, 2), 16);
                        mod.ProgramLocation = line.ProgramCounter;
                        this.AddRecord(mod);
                    }
                }

                // anything else with a LC shouldn't be here...
                else
                {
                    // this code *should* be unreachable
                    throw new NotImplementedException();
                }

                // convert bytecode to hex and add the record
                rec.HexCode = Convert.ToString(Convert.ToInt32(bin, 2), 16).ToUpper();
                this.AddRecord(rec);

                // list of errors
                List<Errors.Error> errorlist = line.GetThreeErrors();

                // add a line to the assembly report
                this.report.Add(line.ProgramCounter, rec.HexCode, rec.StatusFlag,
                        line.SourceLineNumber, line.SourceLine, errorlist);
            }
        }
Beispiel #3
0
        /**
         * Reads an expression and evaluates it as much as it can. If the parsing is
         * successful, the operand variable is replaced with the most fully parsed
         * version of the expression possible.  If the expression cannot be parsed due
         * to an error in the expression, thie function returns false and an error is
         * added to the passed in IntermediateLine parameter.
         *
         * @refcode EX1, EX2, EX3
         * @errtest N/A
         * @errmsg ES.2, ES.19, ES.20, ES.22, ES.23, ES.24, ES.27, ES.30, ES.31, ES.32, ES.33
         * @author Mark Mathis
         * @creation April 18, 2011
         * @modlog
         *  - April 18, 2011 - Mark - Parses operand expressions (EX1).
         *  - April 19, 2011 - Mark - Parses EQU expressions (EX2).
         *  - April 19, 2011 - Mark - Parses ADC expressions (EX3).
         *  - April 19, 2011 - Mark - Errors are caught and reported in all expressions.
         *  - May 13, 2011 - Mark - Added rec and modifications parameters.
         *  - May 14, 2011 - Mark - Now keeps track of adjustments required for pass 2.
         * @teststandard Andrew Buelow
         * @codestandard Mark Mathis
         *
         * @param operand the expression to parse, will contain the outgoing value of the expression
         * @param type the type of expression to be parsed
         * @param interLine the intermediate line containing this expression
         * @param symb the symbol table for this source code file
         * @param rec the modification record for keeping track of adjustments in instruction expressions
         *        and ADC/ADCe expressions
         * @param modifications the number of adjustments needed for a EQU/EQUe expression
         * @param maxOperators the maximum number of operators allowed in this type of expression
         *
         * @return true if the expression is successfully parsed and evaluated.
         *         false if an error is found.
         */
        public static bool ParseExpression(ref string operand,
                                           OperandParser.Expressions type,
                                           IntermediateLine interLine,
                                           ref SymbolTable symb,
                                           ModificationRecord rec,
                                           out int modifications,
                                           int maxOperators = 1)
        {
            modifications = 0;
            if (operand != null && operand.Length > 0)
            {
                // if the expression is just a star, take care of it and return
                if (operand.Length == 1 && operand[0] == '*')
                {
                    modifications++;
                    rec.AddAdjustment(true, symb.ProgramName);
                    operand = interLine.ProgramCounter;
                    return true;
                }

                char[] validOperators = { '+', '-' };
                // if there are too many operators, give an error
                List<string> operands = operand.Split(validOperators, StringSplitOptions.RemoveEmptyEntries).ToList();

                if (operands.Count - 1 > maxOperators)
                {
                    // error, too many operators
                    interLine.AddError(Errors.Category.Serious, 22);
                    return false;
                }

                // check for absolute ADC/ADCe
                bool absolute = false;
                if (operand[0] == '+' && type == Expressions.ADC)
                {
                    absolute = true;
                    operand = operand.Substring(1);
                }

                List<char> operators = new List<char>();

                int pos = operand.IndexOfAny(validOperators, 0);

                while (pos != -1)
                {
                    operators.Add(operand[pos]);
                    pos = operand.IndexOfAny(validOperators, pos + 1);
                }

                // check that we have the correct number of operands
                if (operators.Count != operands.Count - 1)
                {
                    // error, wrong number of operators
                    interLine.AddError(Errors.Category.Serious, 24);
                    return false;
                }

                // it can't always be that easy
                switch (type)
                {
                    case OperandParser.Expressions.Operand:
                        {

                            char oprtr;
                            string opr2;
                            string star;

                            if (operand[0] == '*')
                            {
                                star = interLine.ProgramCounter;
                                oprtr = operand[1];
                                opr2 = operand.Substring(2);
                                rec.AddAdjustment(true, symb.ProgramName);

                                Tokenizer.TokenKinds valid;
                                Tokenizer.GetTokenKind(opr2, out valid);

                                if (valid == Tokenizer.TokenKinds.Label_Or_Command)
                                {
                                    if (2 <= opr2.Length && opr2.Length <= 32)
                                    {
                                        if (symb.ContainsSymbol(opr2))
                                        {
                                            if (symb.GetSymbol(opr2).usage == Usage.EQUATED)
                                            {
                                                opr2 = Convert.ToInt32(symb.GetSymbol(opr2).val, 16).ToString();
                                            }
                                            else if (symb.GetSymbol(opr2).usage == Usage.LABEL)
                                            {
                                                opr2 = Convert.ToInt32(symb.GetSymbol(opr2).lc, 16).ToString();
                                                rec.AddAdjustment(oprtr == '+', symb.ProgramName);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        // error:label is too long
                                        Logger.Log("ERROR: ES.2 encountered", "OperandParser");
                                        interLine.AddError(Errors.Category.Serious, 2);
                                        return false;
                                    }
                                }
                                else if (valid == Tokenizer.TokenKinds.Number)
                                {
                                    if (!(0 <= Convert.ToInt32(opr2) && Convert.ToInt32(opr2) <= 1023))
                                    {
                                        // error, the number is out of bounds
                                        Logger.Log("ERROR: ES.28 encountered", "OperandParser");
                                        interLine.AddError(Errors.Category.Serious, 27);
                                        return false;
                                    }
                                }
                                else if (opr2 == "*")
                                {
                                    // error: star used multiple times
                                    interLine.AddError(Errors.Category.Serious, 19);
                                    return false;
                                }
                                else
                                {
                                    //error, must be number or previously equated symbol
                                    Logger.Log("ERROR: ES.29 encountered", "OperandParser");
                                    interLine.AddError(Errors.Category.Serious, 27);
                                    return false;
                                }

                                Tokenizer.GetTokenKind(opr2, out valid);

                                if (valid == Tokenizer.TokenKinds.Number)
                                {
                                    int result = -1;
                                    // if the method gets here, then it's using a number or
                                    // symbol we can deal with
                                    switch (oprtr)
                                    {
                                        case '+':
                                            {
                                                result = Convert.ToInt32(star, 16) + Convert.ToInt32(opr2);
                                            } break;
                                        case '-':
                                            {
                                                result = Convert.ToInt32(star, 16) - Convert.ToInt32(opr2);
                                            } break;
                                        default:
                                            {
                                                // error invalid operator in expression
                                                Logger.Log("ERROR: ES.30 encountered", "OperandParser");
                                                interLine.AddError(Errors.Category.Serious, 30);
                                                return false;
                                            }
                                    }

                                    if (0 <= result && result <= 1023)
                                    {
                                        operand = Convert.ToString(result,16);
                                    }
                                    else
                                    {
                                        // error: computation out of bounds
                                        Logger.Log("ERROR: ES.27 encountered", "OperandParser");
                                        interLine.AddError(Errors.Category.Serious, 27);
                                        return false;
                                    }
                                }
                            }
                            else
                            {
                                //error invalid operand expression
                                Logger.Log("ERROR: ES.31 encountered", "OperandParser");
                                interLine.AddError(Errors.Category.Serious, 31);
                                return false;
                            }
                        } break;

                    case Expressions.EQU:
                        {
                            for (int i = 0; i < operands.Count; i++)
                            {
                                string label = operands[i];
                                Tokenizer.TokenKinds tokenkind;

                                Tokenizer.GetTokenKind(label, out tokenkind);

                                if (label == "*")
                                {
                                    if (i == 0)
                                    {
                                        operands[i] = Convert.ToInt32(Parser.LC, 16).ToString();
                                        modifications++;
                                    }
                                    else
                                    {
                                        // error, star must be first operand
                                        Logger.Log("ERROR: invalid star notation in expression.", "OperandParser");
                                        interLine.AddError(Errors.Category.Serious, 19);
                                        return false;
                                    }
                                }
                                else if (symb.ContainsSymbol(label))
                                {
                                    Symbol operSym = symb.GetSymbol(label);

                                    if (operSym.usage == Usage.EQUATED)
                                    {
                                        operands[i] = Convert.ToInt32(operSym.val, 16).ToString();
                                        modifications += operSym.relocations;
                                    }
                                    else if (operSym.usage == Usage.LABEL)
                                    {
                                        operands[i] = Convert.ToInt32(operSym.lc, 16).ToString();
                                        modifications++;
                                    }
                                    else
                                    {
                                        // error, can only use equated symbols or local references
                                        Logger.Log("ERROR: ES.32 encountered", "OperandParser");
                                        interLine.AddError(Errors.Category.Serious, 32);
                                        return false;
                                    }
                                }
                                else if (tokenkind == Tokenizer.TokenKinds.Number)
                                {
                                    // this needs to be caught, so the next else doesn't get
                                    // tripped. but there's nothing to do herp.
                                    // I will tell you stories of my people.
                                }
                                else
                                {
                                    // undefined symbol
                                    Logger.Log("ERROR: ES.20 encountered", "OperandParser");
                                    interLine.AddError(Errors.Category.Serious, 20);
                                    return false;
                                }
                            }

                            operands.Reverse();
                            operators.Reverse();

                            string possibleOperand = EvaluateExpression(new Stack<string>(operands), new Stack<char>(operators));

                            if (0 <= int.Parse(possibleOperand) && int.Parse(possibleOperand) <= 1023)
                            {
                                operand = Convert.ToString(int.Parse(possibleOperand), 16);
                            }
                            else
                            {
                                // error, calculation must be within the range of 0 to 1023
                                Logger.Log("ERROR: ES.27 encountered", "OperandParser");
                                interLine.AddError(Errors.Category.Serious, 27);
                                return false;
                            }
                        } break;

                    case Expressions.ADC:
                        {
                            bool noLabels = true;
                            for (int i = 0; i < operands.Count; i++)
                            {
                                string label = operands[i];

                                if (label == "*")
                                {
                                    noLabels = false;
                                    if (i == 0)
                                    {
                                        operands[i] = Convert.ToInt32(interLine.ProgramCounter,16).ToString();
                                        rec.AddAdjustment(true, symb.ProgramName);
                                        modifications++;
                                    }
                                    else
                                    {
                                        // error, star must be first operand
                                        Logger.Log("ERROR: ES.19 encountered", "OperandParser");
                                        interLine.AddError(Errors.Category.Serious, 19);
                                        return false;
                                    }
                                }
                                else if (symb.ContainsSymbol(label))
                                {
                                    noLabels = false;
                                    Symbol operSym = symb.GetSymbol(label);

                                    if (operSym.usage == Usage.LABEL)
                                    {
                                        operands[i] = Convert.ToInt32(operSym.lc, 16).ToString();
                                        modifications++;
                                        if (i > 0)
                                        {
                                            rec.AddAdjustment(operators[i - 1] == '+', symb.ProgramName);
                                        }
                                        else
                                        {
                                            rec.AddAdjustment(true, symb.ProgramName);
                                        }
                                    }
                                    else if (operSym.usage == Usage.EXTERNAL)
                                    {
                                        noLabels = false;
                                        operands[i] = "0";
                                        modifications++;
                                        if (i > 0)
                                        {
                                            rec.AddAdjustment(operators[i - 1] == '+', operSym.rlabel);
                                        }
                                        else
                                        {
                                            rec.AddAdjustment(true, operSym.rlabel);
                                        }
                                    }
                                    else
                                    {
                                        // error: symbols can only be external, local reference
                                        // in ADC/ADCe expressions
                                        Logger.Log("ERROR: ES.33 encountered", "OperandParser");
                                        interLine.AddError(Errors.Category.Serious, 33);
                                        return false;
                                    }
                                }
                            }

                            if (noLabels)
                            {
                                rec.AddAdjustment(true, symb.ProgramName);
                                modifications++;
                            }

                            bool allNumbers = true;

                            foreach (string op in operands)
                            {
                                Tokenizer.TokenKinds tokenKind;

                                Tokenizer.GetTokenKind(op, out tokenKind);

                                if (tokenKind == Tokenizer.TokenKinds.Number)
                                {
                                    allNumbers = allNumbers && true;
                                }
                                else
                                {
                                    allNumbers = false;
                                }
                            }

                            if (allNumbers)
                            {
                                operands.Reverse();
                                operators.Reverse();
                                operand = EvaluateExpression(new Stack<string>(operands), new Stack<char>(operators));
                                operand = Convert.ToString(Convert.ToInt32(operand), 16);
                            }
                            else
                            {
                                operand = operands[0];
                                for (int i = 0; i + 1 < operands.Count; i++)
                                {
                                    operand += operators[i] + operands[i + 1];
                                }
                            }
                            if (absolute)
                                modifications = 0;
                            } break;
                        }
                }
            return true;
        }