예제 #1
0
        private static void Main(string[] args)
        {
            if (args == null || args.Length < 1)
            {
                var msg = "Expected one argument. The path to a directory with *.vm files";
                throw new ArgumentException(msg);
            }

            var root = args[0];

            if (!Directory.Exists(root))
            {
                var msg = $"directory {root} does not exist";
                throw new FileNotFoundException(msg);
            }

            var paths   = Directory.EnumerateFiles(root, "*.vm", SearchOption.AllDirectories);
            var dirName = Path.GetFileName(root);
            var outFile = Path.Combine(root, $"{dirName}.asm");

            using (var ctx = new Context(File.CreateText(outFile)))
            {
                ctx.Writer.WriteLine("@256");
                ctx.Writer.WriteLine("D=A");
                ctx.Writer.WriteLine("@SP");
                ctx.Writer.WriteLine("M=D");
                var sysInit = Path.Combine(root, "Sys.vm");
                if (File.Exists(sysInit))
                {
                    string EntryPoint = "Sys.Init".ToUpper();
                    ctx.CurrentFunction = new FunctionContext(EntryPoint, 0);
                    ctx.InputFilePath   = "Sys.vm";
                    AssemblyWriter.EmitCall(ctx, EntryPoint, 0);
                }
                foreach (var path in paths)
                {
                    Console.WriteLine($"processing {path}");
                    var inputFile = Path.GetFileName(path);
                    ctx.InputFilePath = inputFile;


                    var callbacks = new ParserCallBacks
                    {
                        OnPop =
                            (segment, index) =>
                            AssemblyWriter.EmitPop(ctx, segment, index),
                        OnPush = (segment, index) =>
                                 AssemblyWriter.EmitPush(ctx, segment, index),
                        OnArithmeticCommand = command =>
                                              AssemblyWriter.EmitOperator(ctx.Writer, command),
                        OnGoTo = label =>
                                 AssemblyWriter.EmitGoTo(ctx, label),
                        OnIfGoTo = label =>
                                   AssemblyWriter.EmitIfGoTo(ctx, label),
                        OnLabelDeclaration = label =>
                                             AssemblyWriter.EmitLabel(ctx, label),
                        OnCall = (command, n) =>
                                 AssemblyWriter.EmitCall(ctx, command.ToUpper(), n),
                        OnFuncDef = (functionName, n) =>
                        {
                            var name = functionName.ToUpper();
                            ctx.CurrentFunction = new FunctionContext(name, n);
                            AssemblyWriter.EmitFunction(ctx, name, n);
                        },
                        OnReturn = () =>
                        {
                            AssemblyWriter.EmitReturn(ctx);
                        },
                    };
                    Parser.Parse(File.ReadAllLines(path), callbacks);
                    ctx.Writer.Flush();
                }
            }
        }
예제 #2
0
        public void TestParser2()
        {
            //const string root = @"C:\Users\Dean.Pavlovsky\Projects\nand2tetris\08\FunctionCalls\NestedCall";
            //const string root = @"C:\Users\Dean.Pavlovsky\Projects\nand2tetris\08\ProgramFlow\BasicLoop";
            const string root = @"C:\Users\Dean.Pavlovsky\Projects\nand2tetris\08\ProgramFlow\FibonacciSeries";
            //const string root = @"C:\Users\Dean.Pavlovsky\Projects\nand2tetris\08\FunctionCalls\SimpleFunction";
            //const string root = @"C:\Users\Dean.Pavlovsky\Projects\nand2tetris\08\FunctionCalls\FibonacciElement";
            //const string root = @"C:\Users\Dean.Pavlovsky\Projects\nand2tetris\08\FunctionCalls\StaticsTest";
            var paths = Directory.EnumerateFiles(root, "*.vm", SearchOption.AllDirectories);
            //var paths = new[]
            //{
            //    $@"{root}\MemoryAccess\BasicTest\BasicTest.vm",
            //    $@"{root}\MemoryAccess\PointerTest\PointerTest.vm",
            //    $@"{root}\MemoryAccess\StaticTest\StaticTest.vm",
            //    $@"{root}\StackArithmetic\SimpleAdd\SimpleAdd.vm",
            //    $@"{root}\StackArithmetic\StackTest\StackTest.vm"
            //};
            var dirName = Path.GetFileName(root);
            var outFile = Path.Combine(root, $"{dirName}.asm");

            using (var ctx = new Context(File.CreateText(outFile) /*new StringWriter(sb)*/))
            {
                ctx.Writer.WriteLine("@256");
                ctx.Writer.WriteLine("D=A");
                ctx.Writer.WriteLine("@SP");
                ctx.Writer.WriteLine("M=D");
                var sysInit = Path.Combine(root, "Sys.vm");
                if (File.Exists(sysInit))
                {
                    string EntryPoint = "Sys.Init".ToUpper();
                    ctx.CurrentFunction = new FunctionContext(EntryPoint, 0);
                    ctx.InputFilePath   = "Sys.vm";
                    AssemblyWriter.EmitCall(ctx, EntryPoint, 0);
                }
                foreach (var path in paths)
                {
                    Console.WriteLine($"processing {path}");
                    var inputFile = Path.GetFileName(path);
                    ctx.InputFilePath = inputFile;


                    var callbacks = new ParserCallBacks
                    {
                        OnPop =
                            (segment, index) =>
                            AssemblyWriter.EmitPop(ctx, segment, index),
                        OnPush = (segment, index) =>
                                 AssemblyWriter.EmitPush(ctx, segment, index),
                        OnArithmeticCommand = command =>
                                              AssemblyWriter.EmitOperator(ctx.Writer, command),
                        OnGoTo = label =>
                                 AssemblyWriter.EmitGoTo(ctx, label),
                        OnIfGoTo = label =>
                                   AssemblyWriter.EmitIfGoTo(ctx, label),
                        OnLabelDeclaration = label =>
                                             AssemblyWriter.EmitLabel(ctx, label),
                        OnCall = (command, n) =>
                                 AssemblyWriter.EmitCall(ctx, command.ToUpper(), n),
                        //Console.WriteLine($">> call {command},{n}"),
                        OnFuncDef = (functionName, n) =>
                        {
                            var name = functionName.ToUpper();
                            ctx.CurrentFunction = new FunctionContext(name, n);
                            AssemblyWriter.EmitFunction(ctx, name, n);
                        },
                        OnReturn = () =>
                        {
                            AssemblyWriter.EmitReturn(ctx);
                            //ctx.CurrentFunction = null;
                        },
                    };
                    Parser.Parse(File.ReadAllLines(path), callbacks);
                    ctx.Writer.Flush();
                }
            }
        }
예제 #3
0
    public static void Parse(IEnumerable <string> lines, ParserCallBacks callbacks)
    {
        IEnumerable <string> filteredLines = from line in lines
                                             where !string.IsNullOrWhiteSpace(line)
                                             select line.Trim();

        foreach (string item in filteredLines)
        {
            string[] elems = item.Split((string[])null, StringSplitOptions.RemoveEmptyEntries);
            if (elems.Length != 0)
            {
                string opcode = elems.First();
                if (!opcode.StartsWith("//"))
                {
                    switch (opcode)
                    {
                    case "add":
                        callbacks.OnArithmeticCommand(Operator.Add);
                        break;

                    case "sub":
                        callbacks.OnArithmeticCommand(Operator.Sub);
                        break;

                    case "neg":
                        callbacks.OnArithmeticCommand(Operator.Neg);
                        break;

                    case "eq":
                        callbacks.OnArithmeticCommand(Operator.Eq);
                        break;

                    case "gt":
                        callbacks.OnArithmeticCommand(Operator.Gt);
                        break;

                    case "lt":
                        callbacks.OnArithmeticCommand(Operator.Lt);
                        break;

                    case "and":
                        callbacks.OnArithmeticCommand(Operator.And);
                        break;

                    case "or":
                        callbacks.OnArithmeticCommand(Operator.Or);
                        break;

                    case "not":
                        callbacks.OnArithmeticCommand(Operator.Not);
                        break;

                    case "push":
                        if (elems.Length < 3)
                        {
                            throw new ArgumentException($"invalid line {item}");
                        }
                        callbacks.OnPush(ParseMemorySegment(elems[1]), short.Parse(elems[2]));
                        break;

                    case "pop":
                        if (elems.Length < 3)
                        {
                            throw new ArgumentException($"invalid line {item}");
                        }
                        callbacks.OnPop(ParseMemorySegment(elems[1]), short.Parse(elems[2]));
                        break;

                    case "label":
                        if (elems.Length < 2 || string.IsNullOrWhiteSpace(elems[1]))
                        {
                            throw new ArgumentException($"invalid line {item}");
                        }
                        callbacks.OnLabelDeclaration(elems[1].Trim());
                        break;

                    case "goto":
                        if (elems.Length < 2 || string.IsNullOrWhiteSpace(elems[1]))
                        {
                            throw new ArgumentException($"invalid line {item}");
                        }
                        callbacks.OnGoTo(elems[1].Trim());
                        break;

                    case "if-goto":
                        if (elems.Length < 2 || string.IsNullOrWhiteSpace(elems[1]))
                        {
                            throw new ArgumentException($"invalid line {item}");
                        }
                        callbacks.OnIfGoTo(elems[1].Trim());
                        break;

                    case "function":
                        if (elems.Length < 3 || string.IsNullOrWhiteSpace(elems[1]) ||
                            string.IsNullOrWhiteSpace(elems[2]))
                        {
                            throw new ArgumentException($"invalid line {item}");
                        }
                        callbacks.OnFuncDef(elems[1].Trim(), short.Parse(elems[2]));
                        break;

                    case "call":
                        if (elems.Length < 3 || string.IsNullOrWhiteSpace(elems[1]) ||
                            string.IsNullOrWhiteSpace(elems[2]))
                        {
                            throw new ArgumentException($"invalid line {item}");
                        }
                        callbacks.OnCall(elems[1].Trim(), short.Parse(elems[2]));
                        break;

                    case "return":
                        callbacks.OnReturn();
                        break;

                    default:
                        throw new NotImplementedException($"Can't parse {item}");
                    }
                }
            }
        }
    }