示例#1
0
 public void AddSymbolStruct()
 {
     var t = new SymbolTable();
     Symbol sym;
     sym.rlabel = "test";
     sym.lc = "5";
     sym.usage = Usage.EQUATED;
     sym.val = "DERP";
     sym.relocations = 0;
     t.AddSymbol(sym);
     Assert.AreEqual(sym, t.GetSymbol("test"));
 }
示例#2
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;
        }
示例#3
0
        /**
         * Parses the reset directive, ensuring that the reset operand is a number
         * that is higher than any previously or currently used location counter.
         *
         * @param interLine the intermediate line to process
         * @param symb symbol table reference
         *
         * @refcode D2
         * @errtest
         *  N/A
         * @errmsg ES.08, ES.10, ES.25
         * @author Mark Mathis
         * @creation April 15, 2011
         * @modlog
         * - April 17, 2011 - Mark - Changes the location counter to the operand value.
         * - April 17, 2011 - Mark - Checks that the operand value is valid.
         * @teststandard Andrew Buelow
         * @codestandard Mark Mathis
         */
        private static void ParseReset(ref IntermediateLine interLine, ref SymbolTable symb)
        {
            Logger.Log("Parsing RESET directive", "DirectiveParser");

            if (interLine.Label != null)
            {
                // the operand of the RESET directive must either be an equated label
                // or a literal number.
                if (symb.ContainsSymbol(interLine.DirectiveOperand) &&
                    symb.GetSymbol(interLine.DirectiveOperand).usage == Usage.EQUATED)
                {
                    int curLC = Convert.ToInt32(Parser.LC, 16);
                    int newLC = Convert.ToInt32(symb.GetSymbol(interLine.DirectiveOperand).val, 16);
                    if (curLC < newLC)
                    {
                        Parser.LC = Convert.ToString(newLC,16);
                    }
                    else
                    {
                        // error, attempt to use a previously used LC value
                        Logger.Log("ERROR: ES.08 encountered.", "DirectiveParser");
                        interLine.AddError(Errors.Category.Serious, 8);
                    }
                }
                else if (interLine.DirectiveLitOperand == OperandParser.Literal.NUMBER)
                {
                    int curLC = Convert.ToInt32(Parser.LC, 16);
                    int newLC = Convert.ToInt32(interLine.DirectiveOperand, 16);
                    if (curLC < newLC)
                    {
                        Parser.LC = Convert.ToString(newLC, 16);
                    }
                    else
                    {
                        // error, attempt to use a previously used LC value
                        Logger.Log("ERROR: ES.08 encountered.", "DirectiveParser");
                        interLine.AddError(Errors.Category.Serious, 8);
                    }
                }
                else
                {
                    // error invalid value
                    Logger.Log("ERROR: ES.10 encountered.", "DirectiveParser");
                    interLine.AddError(Errors.Category.Serious, 10);
                }
            }
            else
            {
                // error, label is required for reset directive
                Logger.Log("ERROR: ES.25 encountered.", "DirectiveParser");
                interLine.AddError(Errors.Category.Serious,25);
            }

            Logger.Log("Finished parsing RESET directive", "DirectiveParser");
        }
示例#4
0
        /**
         * Parses the equ directive, ensuring that the operand is a valid value for an
         * equated symbol.
         *
         * @param interLine the intermediate line to process
         * @param symb symbol table reference
         * @param maxOp maximum number of operations to process
         *
         * @refcode D3
         * @errtest
         *  N/A
         * @errmsg ES.21, ES.22, ES.26
         * @author Mark Mathis
         * @creation April 15, 2011
         * @modlog
         * @teststandard Andrew Buelow
         * @codestandard Mark Mathis
         */
        private static void ParseEqu(ref IntermediateLine interLine, ref SymbolTable symb, int maxOp = 1)
        {
            Logger.Log("Parsing EQU directive", "DirectiveParser");
            bool success = true;

            if (symb.ContainsSymbol(interLine.Label))
            {
                Symbol equSym = symb.RemoveSymbol(interLine.Label);
                interLine.ProgramCounter = equSym.lc;
                if (interLine.DirectiveLitOperand == OperandParser.Literal.NUMBER)
                {
                    // check that number is in bounds
                    int num = BinaryHelper.HexToInt(interLine.DirectiveOperand, 10);
                    if (0 <= num && num <= 1023)
                    {
                        equSym.usage = Usage.EQUATED;
                        equSym.val = interLine.DirectiveOperand;
                    }
                    else
                    {
                        // error: out of bounds
                        Logger.Log("ERROR: ES.26 encountered", "DirectiveParser");
                        interLine.AddError(Errors.Category.Serious, 26);
                        success = false;
                    }
                }
                else if (symb.ContainsSymbol(interLine.DirectiveOperand) &&
                    symb.GetSymbol(interLine.DirectiveOperand).usage == Usage.EQUATED)
                {
                    // do stuff with the symbol
                    equSym.usage = Usage.EQUATED;
                    equSym.val = symb.GetSymbol(interLine.DirectiveOperand).val;
                    equSym.relocations = symb.GetSymbol(interLine.DirectiveOperand).relocations;
                }
                else if (interLine.DirectiveLitOperand == OperandParser.Literal.EXPRESSION)
                {
                    string oper = interLine.DirectiveOperand;
                    int modifications;
                    success = OperandParser.ParseExpression(ref oper, OperandParser.Expressions.EQU,
                                                  interLine, ref symb, new ModificationRecord("junk"),
                                                  out modifications, maxOp);
                    equSym.usage = Usage.EQUATED;
                    equSym.val = oper;
                    equSym.relocations = modifications;
                }
                else
                {
                    // error: invalid operand for equ
                    Logger.Log("ERROR: EW.21 encountered", "DirectiveParser");
                    interLine.AddError(Errors.Category.Serious, 21);
                    success = false;
                }

                interLine.ProgramCounter = null;
                equSym.lc = null;

                if (success)
                {
                    // this needs to be checked here in case ParseExpression
                    // finds an error
                    int finval = Convert.ToInt32(equSym.val, 16);
                    if (!(0 <= finval && finval <= 1023))
                    {
                        // the final value of the equ is out of bounds
                        Logger.Log("ERROR: EW.22 encountered", "DirectiveParser");
                        interLine.AddError(Errors.Category.Serious, 22);
                        success = false;
                    }
                    symb.AddSymbol(equSym);
                }
            }

            Logger.Log("Finished parsing EQU directive", "DirectiveParser");
        }
示例#5
0
        /**
         * Parses the entry directive, ensuring that the operand is a valid value
         * for an equated symbol using extended expressions.
         *
         * @param interLine the intermediate line to process
         * @param symb symbol table reference
         *
         * @refcode D5
         * @errtest
         *  N/A
         * @errmsg EW.05
         * @author Mark Mathis
         * @creation April 17, 2011
         * @modlog
         * @teststandard Andrew Buelow
         * @codestandard Mark Mathis
         */
        private static void ParseEntry(ref IntermediateLine interLine, ref SymbolTable symb)
        {
            Logger.Log("Parsing ENTRY directive", "DirectiveParser");

            // check for a label
            if (interLine.Label != null)
            {
                // entry doesn't expect a label
                Logger.Log("ERROR: EW.05 encountered", "DirectiveParser");
                interLine.AddError(Errors.Category.Warning, 5);
            }
            if (symb.ContainsSymbol(interLine.DirectiveOperand))
            {
                if (symb.GetSymbol(interLine.DirectiveOperand).usage != Usage.EQUATED)
                {
                    Symbol tempsym = symb.RemoveSymbol(interLine.DirectiveOperand);
                    tempsym.usage = Usage.ENTRY;
                    symb.AddSymbol(tempsym);
                }
            }
            else
            {
                symb.AddSymbol(interLine.DirectiveOperand, null, Usage.ENTRY);
            }

            Logger.Log("Finished parsing ENTRY directive", "DirectiveParser");
        }
示例#6
0
        /**
         * Parses the end directive, ensuring that the end operand is the same as
         * the start directive's rlabel.
         *
         * @param interLine the intermediate line to process
         * @param symb symbol table reference
         *
         * @refcode D7
         * @errtest
         *  N/A
         * @errmsg EF.05, EW.05
         * @author Mark Mathis
         * @creation April 9, 2011
         * @modlog
         *  - April  9, 2011 - Mark - Not sure if needed.
         *  - April 14, 2011 - Mark - Moved into DirectiveParser class.
         *  - April 17, 2011 - Mark - Actually checks that the operand is correct.
         *  - April 19, 2011 - Mark - Reports errors.
         * @teststandard Andrew Buelow
         * @codestandard Mark Mathis
         */
        private static void ParseEnd(ref IntermediateLine interLine, ref SymbolTable symb)
        {
            Logger.Log("Parsing END directive", "DirectiveParser");

            // check to see if this line has a label
            if (interLine.Label != null)
            {
                // the end directive should not have a label
                interLine.AddError(Errors.Category.Warning, 5);
            }

            // check to see if the operand of the END directive matches the program name

            if (!(symb.ContainsSymbol(interLine.DirectiveOperand) &&
                symb.GetSymbol(interLine.DirectiveOperand).usage == Usage.PRGMNAME))
            {
                // error things
                interLine.AddError(Errors.Category.Fatal, 5);
            }

            Logger.Log("Finished parsing END directive.", "DirectiveParser");
        }
示例#7
0
        /**
         * Parses a single line of source code.
         *
         * @param line current line to parse
         * @param lineNum line number of current line
         * @param symb symbol table reference
         * @return the line to be parsed as a single line in the intermediate file
         *
         * @refcode N/A
         * @errtest
         *  N/A
         * @errmsg
         *  N/A
         * @author Mark Mathis
         * @creation April 8, 2011
         * @modlog
         *  - April  9, 2011 - Mark - ParseLine parses lines with instructions.
         *  - April  9, 2011 - Mark - ParseLine parses lines with directives.
         *  - April  9, 2011 - Mark - Increments program counter after parsing instructions.
         *  - April  9, 2011 - Mark - Sets OpCategory = "_ERROR" if the token expected to be
         *      an instruction category or a directive is niether of those.
         *  - April 10, 2011 - Mark - Properly handles lines that only have a comment.
         * @teststandard Andrew Buelow
         * @codestandard Mark Mathis
         */
        private IntermediateLine ParseLine(string line, short lineNum, ref SymbolTable symb)
        {
            Logger.Log("Parsing line " + lineNum, "Parser");
            string token = "";
            Tokenizer.TokenKinds tokenKind = Tokenizer.TokenKinds.Empty;

            // make Intermediate version of this line to be returned
            IntermediateLine interLine = new IntermediateLine(line, lineNum);

            // check for a label at the beginning of the line
            if (line.Trim().Length > 0)
            {
                if (char.IsLetter(line[0]))
                {
                    Logger.Log(String.Format("Line {0} has a label, parsing label", lineNum), "Parser");
                    Tokenizer.GetNextToken(ref line, out token, out tokenKind);
                    if (tokenKind == Tokenizer.TokenKinds.Label_Or_Command
                        && (2 <= token.Length && token.Length <= 32))
                    {
                        interLine.Label = token;
                        if (symb.ContainsSymbol(token))
                        {
                            if (symb.GetSymbol(token).usage != Usage.ENTRY)
                            {
                                // error: cannot redefine symbol
                                interLine.AddError(Errors.Category.Warning, 4);
                            }
                        }
                        else
                        {
                            // the symbol is not defined, define it
                            symb.AddSymbol(token, LC, Usage.LABEL);
                        }
                    }
                    else
                    {
                        interLine.Label = "_ERROR";
                        interLine.AddError(Errors.Category.Serious, 2);
                    }
                }
                else if (!char.IsWhiteSpace(line[0]) && line[0] != ':')
                {
                    // invalid label start
                    interLine.Label = "_ERROR";
                    interLine.AddError(Errors.Category.Serious, 2);
                }
            }

            // Get the next token, which will specify whether or not the line has a
            // directive or an instruction.
            Tokenizer.GetNextToken(ref line, out token, out tokenKind);

            if (tokenKind == Tokenizer.TokenKinds.Label_Or_Command)
            {
                // coerce into uppercase
                token = token.ToUpper();
                // instruction
                if (instructionList.IsGroup(token))
                {
                    interLine.OpCategory = token;
                    ParseInstruction(ref line, ref interLine, ref symb);
                    interLine.ProgramCounter = LC;
                    IncrementLocationCounter();
                }
                // directive
                else if (directiveList.Contains(token))
                {
                    interLine.Directive = token;
                    DirectiveParser.ParseDirective(ref line, ref interLine, ref symb);
                }
                else
                {
                    // bad category, but don't NOP
                    interLine.OpCategory = "_ERROR";
                    interLine.AddError(Errors.Category.Serious, 1);
                    return interLine;
                }
            }
            else if (tokenKind == Tokenizer.TokenKinds.Comment)
            {
                interLine.Comment = token;
                return interLine;
            }
            else if (tokenKind != Tokenizer.TokenKinds.Empty)
            {
                // garbage data
                interLine.AddError(Errors.Category.Serious, 18);
                return interLine;
            }

            // If there's anything else, get it. If there's anything there,
            // it should be a comment.
            Tokenizer.GetNextToken(ref line, out token, out tokenKind);

            if (tokenKind == Tokenizer.TokenKinds.Comment)
            {
                interLine.Comment = token;
            }
            else if (tokenKind != Tokenizer.TokenKinds.Empty)
            {
                // error: invalid input after the operand
                Logger.Log("ERROR: EW.6 encountered", "Parser");
                interLine.AddError(Errors.Category.Warning, 6);
            }

            // process this line if it's an instruction
            if (interLine.OpCategory != null)
            {
                interLine.ProcessLine(ref symb);
            }

            Logger.Log("Finished parsing line " + lineNum, "Parser");

            return interLine;
        }
示例#8
0
 public void NonexistingSymbol()
 {
     var t = new SymbolTable();
     try
     {
         t.GetSymbol("herp");
     } catch (SymbolException)
     {
         return;
     }
     Assert.Fail();
 }
示例#9
0
        /**
         * Process a line, generating partial bytecode and appropriate flags.
         * Errors may be set on lines (and NOP'd) as they occur.
         *
         * @param symb symbol table reference
         *
         * @refcode OP
         * @errtest
         *  N/A
         * @errmsg
         *  ES.3, ES.4, ES.9, ES.11, ES.12, ES.16, EW.3
         * @author Jacob Peddicord
         * @creation April 10, 2011
         * @modlog
         *  - April 15, 2011 - Jacob - Converted to a property; begin generating full bytecode
         *  - April 15, 2011 - Jacob - Changed to ProcessLine; we'll do more general things here
         *  - April 16, 2011 - Jacob - Fix padding on generated instructions.
         *  - April 17, 2011 - Jacob - Handle error conditions.
         * @codestandard Mark Mathis
         * @teststandard Andrew Buelow
         */
        public void ProcessLine(ref SymbolTable symb)
        {
            Logger.Log("Processing line \"" + this.source + "\"", "IntermediateLine");
            // get the first 5 bits
            StringBuilder code = new StringBuilder();
            try
            {
                code.Append(Instructions.GetInstance().GetBytecodeString(
                    this.category == null ? "" : this.category,
                    this.function == null ? "" : this.function
                ));
            }
            catch (InstructionException)
            {
                this.AddError(Errors.Category.Serious, 3);
                this.NOPificate();
                return;
            }

            // fetch equated symbols
            if (this.OpLitOperand == OperandParser.Literal.NONE &&
                this.OpOperand != null &&
                symb.ContainsSymbol(this.OpOperand) &&
                symb.GetSymbol(this.OpOperand).usage == Usage.EQUATED)
            {
                Logger.Log("Evaluating equated symbol " + this.OpOperand, "IntermediateLine");
                this.Equated = this.OpOperand;
                this.OpOperand = symb.GetSymbol(this.OpOperand).val;
            }

            // from here on, everything is instruction-dependent
            switch (this.category)
            {
                case "CNTL": {
                    // unused bit
                    code.Append("0");
                    // validation
                    if (this.function == "HALT")
                    {
                        // we want a number
                        if (this.OpLitOperand == OperandParser.Literal.NUMBER)
                        {
                            int val = BinaryHelper.HexToInt(this.OpOperand, 16);
                            // out of bounds
                            if (val < 0 || val > 1023)
                            {
                                this.AddError(Errors.Category.Serious, 12);
                                this.NOPificate();
                                return;
                            }
                        }
                        // wrong operand type
                        else
                        {
                            this.AddError(Errors.Category.Serious, 12);
                            this.NOPificate();
                            return;
                        }
                    }
                    else if (this.function == "DUMP")
                    {
                        // not a 1, 2, or 3
                        if (this.OpOperand != "1" && this.OpOperand != "2" && this.OpOperand != "3")
                        {
                            this.AddError(Errors.Category.Serious, 11);
                            this.NOPificate();
                            return;
                        }
                    }
                    else if (this.function == "CLRD" || this.function == "CLRT")
                    {
                        // no operand for CLRD/CLRT
                        if (this.OpOperand != "" && this.OpOperand != null)
                        {
                            this.AddError(Errors.Category.Warning, 3);
                            this.NOPificate();
                            return;
                        }
                    }
                    else if (this.function == "GOTO")
                    {
                        // make sure there's a label or expression
                        if ((this.OpLitOperand != OperandParser.Literal.EXPRESSION &&
                            this.OpLitOperand != OperandParser.Literal.NONE) ||
                            this.OpOperand == "" || this.OpOperand == null)
                        {
                            this.AddError(Errors.Category.Serious, 9);
                            this.NOPificate();
                            return;
                        }
                    }
                    // actual processing!
                    // numeric operand
                    if (this.OpLitOperand == OperandParser.Literal.NUMBER)
                    {
                        code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(10, '0'));
                    }
                    // otherwise pad with zeros (labels & expressions in pass 2)
                    else
                    {
                        code.Append("0000000000");
                    }
                } break;
                case "STACK": {
                    // ensure there is an operand
                    if (this.OpOperand.Length == 0)
                    {
                        this.AddError(Errors.Category.Serious, 16);
                        this.NOPificate();
                        return;
                    }
                    // literal operand
                    if (this.OpLitOperand != OperandParser.Literal.NONE &&
                        this.OpLitOperand != OperandParser.Literal.EXPRESSION)
                    {
                        // bounds-check
                        int val = Convert.ToInt32(this.OpOperand, 16);
                        if (val < 0 || val > 1023) // actually (val < -512 || val > 511) in 10 bits
                        {
                            this.AddError(Errors.Category.Serious, 4);
                            this.NOPificate();
                            return;
                        }
                        // literal flag
                        code.Append("1");
                        // and the value
                        code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(10, '0'));
                    }
                    // expression
                    else if (this.OpLitOperand == OperandParser.Literal.EXPRESSION)
                    {
                        // we'll have literal data once the expression is evaluated.
                        code.Append("1");
                        code.Append("0000000000");
                    }
                    // label
                    else
                    {
                        // non-literal (reference) bit
                        code.Append("0");
                        // and the reference itself, which will be filled in pass 2
                        code.Append("0000000000");
                    }
                } break;
                case "JUMP": {
                    // ensure there is an operand
                    if (this.OpOperand.Length == 0)
                    {
                        this.AddError(Errors.Category.Serious, 16);
                        this.NOPificate();
                        return;
                    }
                    // unused bit
                    code.Append("0");
                    // ensure that JUMP is taking a label
                    if (this.OpLitOperand == OperandParser.Literal.NONE)
                    {
                        // reference label, filled in pass 2
                        code.Append("0000000000");
                    }
                    // or a number
                    else if (this.OpLitOperand == OperandParser.Literal.NUMBER)
                    {
                        int val = Convert.ToInt32(this.OpOperand, 16);
                        if (val < 0 || val > 1023)
                        {
                            this.AddError(Errors.Category.Serious, 12);
                            this.NOPificate();
                            return;
                        }
                        code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(10, '0'));
                    }
                    // or an expression (processed later)
                    else if (this.OpLitOperand == OperandParser.Literal.EXPRESSION)
                    {
                        code.Append("0000000000");
                    }
                    // otherwise, error
                    else
                    {
                        this.AddError(Errors.Category.Serious, 9);
                        this.NOPificate();
                        return;
                    }
                } break;
                case "SOPER": {
                    // ensure there is an operand of type Number
                    if (this.OpLitOperand != OperandParser.Literal.NUMBER)
                    {
                        this.AddError(Errors.Category.Serious, 17);
                        this.NOPificate();
                        return;
                    }
                    // bounds-check
                    int val = Convert.ToInt32(this.OpOperand, 16);
                    if (val < 0 || val > 255) // will catch 2's complement negatives as well
                    {
                        this.AddError(Errors.Category.Serious, 17);
                        this.NOPificate();
                        return;
                    }
                    // the write flag is only set for character operations
                    if (this.OpFunction == "READC" || this.OpFunction == "WRITEC")
                    {
                        code.Append("1");
                    }
                    // for everything else, it's a zero
                    else
                    {
                        code.Append("0");
                    }
                    // unused 2 bits
                    code.Append("00");
                    // operand (assumed literal)
                    code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(8, '0'));
                } break;
                case "MOPER": {
                    // ensure there is an operand
                    if (this.OpOperand.Length == 0)
                    {
                        this.AddError(Errors.Category.Serious, 16);
                        this.NOPificate();
                        return;
                    }
                    // the write flag is only set for character operations
                    if (this.OpFunction == "READC" || this.OpFunction == "WRITEC")
                    {
                        code.Append("1");
                    }
                    // for everything else, it's a zero
                    else
                    {
                        code.Append("0");
                    }
                    // ensure that MOPER is taking a label
                    if (this.OpLitOperand == OperandParser.Literal.NONE)
                    {
                        // reference label, filled pass 2
                        code.Append("0000000000");
                    }
                    // or a number
                    else if (this.OpLitOperand == OperandParser.Literal.NUMBER)
                    {
                        int val = Convert.ToInt32(this.OpOperand, 16);
                        if (val < 0 || val > 1023)
                        {
                            this.AddError(Errors.Category.Serious, 4);
                            this.NOPificate();
                            return;
                        }
                        code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(10, '0'));
                    }
                    // or an expression (pass 2)
                    else if (this.OpLitOperand == OperandParser.Literal.EXPRESSION)
                    {
                        code.Append("0000000000");
                    }
                    // otherwise, it's invalid
                    else
                    {
                        this.AddError(Errors.Category.Serious, 9);
                        this.NOPificate();
                        return;
                    }
                } break;
            }

            // set the bytecode
            this.bytecode = code.ToString();
        }