public SemanticAtom Visit(Block n)
        {
            var current       = BlockStack.Count == 0 ? null : BlockStack.Peek();
            var semanticBlock = new ClassMethodBlock(n, current, CurrentMethod, n.Location);

            n.AssociatedSemanticBlock = semanticBlock;

            BlockStack.Push(semanticBlock);
            current?.SubBlocks.Add(semanticBlock);

            // Plumb the for-loop initializer into this block in case it has a declaration.
            n.OptionalFor?.Initialize.Accept(this);
            n.OptionalFor?.Test.Accept(this);

            foreach (var d in n.StatementList)
            {
                d.Accept(this);
            }

            n.OptionalFor?.Afterthought.Accept(this);

            BlockStack.Pop();

            return(semanticBlock);
        }
        public SemanticAtom Visit(Block n)
        {
            var previousBlock = CurrentBlock;

            CurrentBlock = n.AssociatedSemanticBlock;

            // Handle the case for a for loop.
            if (n.OptionalFor != null)
            {
                n.OptionalFor.Initialize.Accept(this);
                var forTest = n.OptionalFor.Test.Accept(this);

                if (forTest != Primitive.Boolean)
                {
                    Globals.Errors.Add($"[{n.OptionalFor.Test.Location.StartLine}, {n.OptionalFor.Test.Location.StartColumn}] Test condition for \"while\" statement ({forTest.Name}) is not assignable to {Primitive.Boolean.Name}.");
                }
            }

            foreach (var s in n.StatementList)
            {
                s.Accept(this);
            }

            n.OptionalFor?.Afterthought.Accept(this);

            CurrentBlock = previousBlock;

            return(null);
        }
        public void Visit(Goal n)
        {
            // At this point, we are only evaluating statement type compatibility, so we don't need to do much with classes, methods, etc.
            // For each method in each class, we will check type compatibility of statements and type compatibility of the return expression and
            // return type.
            foreach (var t in Globals.TypeTable.EnumerateValues().Where(t => !t.IsPrimitive).Cast <Class>())
            {
                foreach (var m in t.Methods.EnumerateValues())
                {
                    // Set the singleton.
                    CurrentMethod = m;
                    CurrentBlock  = null;

                    m.MethodBody.AstBlock.Accept(this);
                }
            }
        }
Example #4
0
        public void Visit(Block n)
        {
            var previousBlock = CurrentBlock;

            CurrentBlock = n.AssociatedSemanticBlock;

            Globals.Builder.Start($"block [{n.Location.StartLine}, {n.Location.StartColumn}]");

            // For labels, if needed.
            var labelStart = $"forStart{Globals.Builder.Count()}";
            var labelEnd   = $"forEnd{Globals.Builder.Count()}";

            if (n.OptionalFor != null)
            {
                n.OptionalFor.Initialize.Accept(this);
                n.OptionalFor.Test.Accept(this);

                Globals.Builder.WriteBinaryOp("cmp", "rax", 1.ToString());

                Globals.Builder.WriteUnaryOp("jne", labelEnd);

                Globals.Builder.WriteLabel(labelStart);
            }

            foreach (var s in n.StatementList)
            {
                s.Accept(this);
            }

            if (n.OptionalFor != null)
            {
                n.OptionalFor.Afterthought.Accept(this);
                n.OptionalFor.Test.Accept(this);
                Globals.Builder.WriteBinaryOp("cmp", "rax", 1.ToString());
                Globals.Builder.WriteUnaryOp("je", labelStart);

                Globals.Builder.WriteLabel(labelEnd);
            }

            CurrentBlock = previousBlock;

            Globals.Builder.End($"block [{n.Location.EndLine}, {n.Location.EndColumn}]");
        }
Example #5
0
        public void Visit(Goal n)
        {
            Globals.Builder.WritePreamble();

            Globals.Builder.WriteStartCode();

            // We already have the class information embedded, so start emmitting statements.
            foreach (var t in Globals.TypeTable.EnumerateValues().Where(t => !t.IsPrimitive).Cast <Class>().Where(c => !c.IsMainClass))
            {
                foreach (var m in t.Methods.EnumerateValues())
                {
                    CurrentMethod = m;
                    CurrentBlock  = null;

                    Globals.Builder.Tab();
                    Globals.Builder.WriteLabel(m.MethodTableName, $"[{n.Location.StartLine}, {n.Location.StartColumn}]");
                    Globals.Builder.Write();
                    Globals.Builder.Tab();

                    Globals.Builder.Start("prologue");
                    Globals.Builder.WriteUnaryOp("push", "rbp");
                    Globals.Builder.WriteBinaryOp("mov", "rbp", "rsp");
                    Globals.Builder.WriteLocalCreation(m.LocalCount);
                    Globals.Builder.WriteBinaryOp("mov", "[rbp + 16]", "rcx");
                    Globals.Builder.WriteBinaryOp("mov", "[rbp + 24]", "rdx");
                    Globals.Builder.WriteBinaryOp("mov", "[rbp + 32]", "r8");
                    Globals.Builder.WriteBinaryOp("mov", "[rbp + 40]", "r9");
                    Globals.Builder.End("prologue");

                    Globals.Builder.Start("statements");
                    m.MethodBody.AstBlock.Accept(this);
                    Globals.Builder.End("statements");

                    Globals.Builder.WriteLabel(m.ReturnLabelName);

                    Globals.Builder.Start("epilogue");
                    Globals.Builder.WriteBinaryOp("mov", "rsp", "rbp");
                    Globals.Builder.WriteUnaryOp("pop", "rbp");
                    Globals.Builder.End("epilogue");

                    Globals.Builder.Write("ret");

                    Globals.Builder.Untab();
                    Globals.Builder.Untab();
                }
            }

            foreach (var t in Globals.TypeTable.EnumerateValues().Where(t => !t.IsPrimitive).Cast <Class>().Where(c => c.IsMainClass))
            {
                CurrentMethod = null;
                CurrentBlock  = null;

                Globals.Builder.Tab();
                Globals.Builder.Write("mainCRTStartup proc", $"[{n.Location.StartLine}, {n.Location.StartColumn}] Main method.");
                Globals.Builder.Write();
                Globals.Builder.Tab();

                Globals.Builder.Start("statements");
                t.Methods.Values.First().MethodBody.AstBlock.Accept(this);
                Globals.Builder.End("statements");

                Globals.Builder.Write();
                Globals.Builder.WriteComment("Main Epilogue.");
                Globals.Builder.WriteBinaryOp("mov", "rcx", "0");
                Globals.Builder.WriteCall("_exit");
                Globals.Builder.Write("ret");

                Globals.Builder.Untab();
                Globals.Builder.Write("mainCRTStartup endp");
                Globals.Builder.Untab();
            }

            // Data section.
            Globals.Builder.Write(".data");
            Globals.Builder.Tab();

            // Vtables.
            foreach (var t in Globals.TypeTable.EnumerateValues().Where(t => !t.IsPrimitive).Cast <Class>().Where(c => !c.IsMainClass))
            {
                var builder = new StringBuilder();

                builder.Append($"{t.ClassTableName} qword ");

                builder.Append(t.BaseClass != null ? $"{t.BaseClass.ClassTableName}, " : "0, ");

                foreach (var m in t.MethodTableEnumerator())
                {
                    builder.Append(m.MethodTableName + ", ");
                }
                builder.Append(0);

                Globals.Builder.Write(builder.ToString());
            }

            // Strings.
            Globals.Builder.Write("$$true byte 'true', 0");
            Globals.Builder.Write("$$false byte 'false', 0");
            foreach (var kvp in Globals.StringTable)
            {
                if (kvp.Key.Length == 2 /* empty */)
                {
                    Globals.Builder.Write($"{kvp.Value} byte 0");
                }
                else
                {
                    var str = kvp.Key.Replace('\"', '\'');

                    int beforeLength;
                    do
                    {
                        beforeLength = str.Length;

                        str = str
                              .Replace("'\n", "10, '")
                              .Replace("\n'", "', 10");
                    } while (beforeLength != str.Length);
                    str = str.Replace("\n", "', 10, '");

                    Globals.Builder.Write($"{kvp.Value} byte {str}, 0");
                }
            }

            Globals.Builder.Untab();

            Globals.Builder.WriteEnd();
        }