コード例 #1
0
 private static LineOfCode ParseStackInstruction(LineOfCode loc, string[] fragments)
 {
     if (fragments.Length < 2)
     {
         loc.Error = "Stack instructions must include a segment";
     }
     else if (fragments.Length < 3)
     {
         loc.Error = "Stack instructions must include a value";
     }
     else
     {
         if (!Enum.TryParse(fragments[1], true, out Segment s))
         {
             loc.Error = $"Segment '{fragments[1]}' not recognised";
         }
         else
         {
             loc.Segment = s;
             if (SetValue(loc, fragments[2]))
             {
                 if (loc.Instruction == InstructionType.Pop && loc.Segment == Segment.Constant)
                 {
                     loc.Error = "pop cannot be performed on a constant";
                 }
                 else if (loc.Segment == Segment.Pointer && loc.Value > 1)
                 {
                     loc.Error = "pointer value can only be 0 or 1";
                 }
             }
         }
     }
     return(loc);
 }
コード例 #2
0
 private LineOfCode ParseFunctionInstruction(LineOfCode loc, string[] fragments)
 {
     if (loc.Instruction == InstructionType.Function || loc.Instruction == InstructionType.Call)
     {
         if (fragments.Length < 2)
         {
             loc.Error = "Function must have a name";
         }
         else
         {
             loc.FunctionName = fragments[1];
             if (fragments.Length < 3)
             {
                 loc.Error = loc.Instruction == InstructionType.Function ? "Function must specify the number of local variables" : "Call must specify the number of arguments";
             }
             else
             {
                 SetValue(loc, fragments[2]);
             }
         }
     }
     if (loc.Instruction == InstructionType.Return && fragments.Length > 1)
     {
         loc.Error = "Return cannot have a name";
     }
     if (loc.Instruction == InstructionType.Function)
     {
         functionName = loc.FunctionName;
     }
     if (loc.Instruction == InstructionType.Return)
     {
         loc.FunctionName = functionName;
     }
     return(loc);
 }
コード例 #3
0
        public LineOfCode Parse(string line)
        {
            lineNumber++;
            line = StripComments(line);
            if (IsCommentOrWhitespace(line))
            {
                return(null);
            }

            string[]   fragments = line.Split(' ');
            LineOfCode loc       = ParseInstruction(fragments, line);

            switch (loc.Category)
            {
            case InstructionCategory.Branching:
                return(ParseBranchingInstruction(loc, fragments));

            case InstructionCategory.Stack:
                return(ParseStackInstruction(loc, fragments));

            case InstructionCategory.Function:
                return(ParseFunctionInstruction(loc, fragments));

            case InstructionCategory.Arithmetic:
            case InstructionCategory.Logical:
                return(ParseArithmeticOrLogicalInstruction(loc, fragments));

            default:
                return(ParseUnrecognisedInstruction(loc, fragments));
            }
        }
コード例 #4
0
 private static LineOfCode ParseArithmeticOrLogicalInstruction(LineOfCode loc, string[] fragments)
 {
     if (fragments.Length > 1)
     {
         loc.Error = "Arithmetic instructions cannot include any additional arguments";
     }
     return(loc);
 }
コード例 #5
0
 private static bool SetValue(LineOfCode loc, string s)
 {
     if (!int.TryParse(s, out int v))
     {
         loc.Error = $"Value '{s}' is not a valid integer";
         return(false);
     }
     loc.Value = v;
     return(true);
 }
コード例 #6
0
 private string Merge(string template, LineOfCode loc)
 {
     return(template
            .Replace("{vmcode}", loc.VmCode)
            .Replace("{functionname}", loc.FunctionName)
            .Replace("{label}", loc.Label)
            .Replace("{linenumber}", loc.LineNumber.ToString())
            .Replace("{value}", loc.Value.ToString())
            .Replace("{segment}", GetRamForSegment(loc))
            .Replace("{filename}", loc.FileName));
 }
コード例 #7
0
        private LineOfCode ParseInstruction(string[] fragments, string line)
        {
            LineOfCode loc = new LineOfCode {
                VmCode = line, LineNumber = lineNumber, FileName = fileName
            };

            if (Enum.TryParse(fragments[0].Replace("-", ""), true, out InstructionType c))
            {
                loc.Instruction = c;
            }
            return(loc);
        }
コード例 #8
0
 private static LineOfCode ParseBranchingInstruction(LineOfCode loc, string[] fragments)
 {
     if (fragments.Length < 2)
     {
         loc.Error = "Branching instructions must have a label";
     }
     else
     {
         loc.Label = fragments[1];
     }
     return(loc);
 }
コード例 #9
0
        private static string GetPopTemplate(LineOfCode loc)
        {
            switch (loc.Segment)
            {
            case Segment.Pointer: return(loc.Value == 0 ? popToPointer0 : popToPointer1);

            case Segment.Static: return(popToStatic);

            case Segment.Temp: return(popToTemp);

            default: return(popToSegment);
            }
        }
コード例 #10
0
        private static string GetPushTemplate(LineOfCode loc)
        {
            switch (loc.Segment)
            {
            case Segment.Constant: return(pushConstant);

            case Segment.Pointer: return(loc.Value == 0 ? pushFromPointer0 : pushFromPointer1);

            case Segment.Static: return(pushFromStatic);

            case Segment.Temp: return(pushFromTemp);

            default: return(pushFromSegment);
            }
        }
コード例 #11
0
        private string GetRamForSegment(LineOfCode loc)
        {
            switch (loc.Segment)
            {
            case Segment.Argument: return("ARG");

            case Segment.Local: return("LCL");

            case Segment.This: return("THIS");

            case Segment.That: return("THAT");

            case Segment.Static: return($"{loc.FileName}");

            default: return(null);
            }
        }
コード例 #12
0
 private static LineOfCode ParseUnrecognisedInstruction(LineOfCode loc, string[] fragments)
 {
     loc.Error = $"Command '{fragments[0]}' not recognised";
     return(loc);
 }
コード例 #13
0
        public string Translate(LineOfCode loc)
        {
            switch (loc.Instruction)
            {
            case InstructionType.Push:
                string push = GetPushTemplate(loc);
                return(Merge(push, loc));

            case InstructionType.Pop:
                string pop = GetPopTemplate(loc);
                return(Merge(pop, loc));

            case InstructionType.Add:
                return(add);

            case InstructionType.Sub:
                return(sub);

            case InstructionType.And:
                return(and);

            case InstructionType.Or:
                return(or);

            case InstructionType.Neg:
                return(neg);

            case InstructionType.Not:
                return(not);

            case InstructionType.Eq:
                return(Merge(eq, loc));

            case InstructionType.Lt:
                return(Merge(lt, loc));

            case InstructionType.Gt:
                return(Merge(gt, loc));

            case InstructionType.Label:
                return(Merge(label, loc));

            case InstructionType.Goto:
                return(Merge(goTo, loc));

            case InstructionType.IfGoto:
                return(Merge(ifGoto, loc));

            case InstructionType.Function:
                if (loc.Value == 0)
                {
                    return(Merge(functionNoArgs, loc));
                }
                if (loc.Value == 1)
                {
                    return(Merge(function1Arg, loc));
                }
                return(Merge(functionMultipleArgs, loc));

            case InstructionType.Return:
                return(Merge(functionReturn, loc));

            case InstructionType.Call:
                return(Merge(call, loc));

            default:
                return(null);
            }
        }