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); } } }
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}]"); }
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(); }