// When Assignment 4 is completed, there should be no calls to // this method any longer private void notImplemented(AST n, string where) { string s = string.Format("Node type {0} not implemented in function {1}", n.Tag, where); Console.WriteLine(s); Asm.AppendComment(s); }
void GenConstDefn(AST n) { if (n[2].Tag == NodeType.IntConst) { Asm.AppendDirective(".align", "2"); // the .align is almost certainly redundant Asm.AppendLabel(((AST_leaf)n[1]).Sval); Asm.AppendDirective(".word", ((AST_leaf)n[2]).Ival.ToString()); } else // n[2] must be a StringConst { createStringConstant(((AST_leaf)n[1]).Sval, ((AST_leaf)n[2]).Sval); } }
void GenMethod(AST n) { // NOT DONE ; NEEDS A LOT OF WORK Asm.StartMethod(((AST_leaf)n[1]).Sval); // 1. generate prolog code returnLabel = getNewLabel(); // push all registers in r4-r14 onto stack Asm.Append("stmfd", "sp!", "{r4-r12,lr}"); // set up frame pointer Asm.Append("mov", "fp", "sp"); // NOTE: Need to add code in CbTcVistitor.cs to determine number of local variables; // FROM NIGEL... store the sizes as annotations on the tree nodes ... and the leaf // node class for an identifier used as a variable's name or a struct type name // does have an unused int field which can be used for that purpose. // ^^ THIS HAS BEEN DONE, BUT IS NOT TESTED!!! // reserve bytes for local variables in the function int allocb = ((AST_leaf)n[1]).Ival; Console.WriteLine("Allocating {0} bytes for local variables of method '{1}'", allocb * 4, ((AST_leaf)n[1]).Sval); Asm.Append("sub", "sp", "sp", "#" + (allocb * 4).ToString()); // 2. translate the method body IList <Tuple <string, FrontEnd.CbType, int, int> > LocalVariables = new List <Tuple <string, FrontEnd.CbType, int, int> >(); GenStatement(n[3], LocalVariables); // 3. generate epilog code Asm.EndMethod(); Asm.AppendLabel(returnLabel); // pop local variables Asm.Append("mov", "sp", "fp"); // reload saved registers and return flow Asm.Append("ldmfd", "sp!", "{r4-r12,pc}"); // go back to calling method Asm.Append("mov", "pc", "lr"); }
public void GenProgram(AST n) { // main method prologue Asm.AppendDirective(".global _start"); Asm.AppendDirective(".text"); Asm.AppendLabel("_start"); Asm.Append("mov", "r0", "#0"); Asm.Append("bl", "Main"); // main method epilogue Asm.Append("mov", "r0", "#0x18"); Asm.Append("mov", "r1", "#0"); Asm.Append("swi", "0x123456"); AST decls = n[2]; for (int i = 0; i < decls.NumChildren; i++) { AST decl = decls[i]; if (decl.Tag == NodeType.Struct) { structs.Add(((AST_leaf)decl[0]).Sval, new Dictionary <string, Tuple <int, int> >()); } } for (int i = 0; i < decls.NumChildren; i++) { AST decl = decls[i]; if (decl.Tag == NodeType.Struct) { AST fields = decl[1]; string name = ((AST_leaf)decl[0]).Sval; Dictionary <string, Tuple <int, int> > s; if (structs.TryGetValue(name, out s)) { int pos = 0; for (int j = 0; j < fields.NumChildren; j++) { AST fieldDecl = fields[j]; AST idList = fieldDecl[1]; int size = getTypeSize(fieldDecl[0].Type); for (int k = 0; k < idList.NumChildren; k++) { //Console.WriteLine("Structure '{0}' has field '{1}' of size '{2}' at position '{3}'", name, ((AST_leaf)idList[k]).Sval, size, pos); Tuple <int, int> t = new Tuple <int, int>(pos, size); s.Add(((AST_leaf)idList[k]).Sval, t); pos += size; } } } } } /* * // how to access struct properties * foreach (string s in structs.Keys) * { * Dictionary<string, Tuple<int,int>> s0; * if (structs.TryGetValue(s, out s0)) * { * foreach (string f in s0.Keys) * { * Tuple<int, int> t; * if (s0.TryGetValue(f, out t)) * { * Console.WriteLine("Structure '{0}' has field '{1}' of size '{3}' at position '{2}'", s, f, t.Item1, t.Item2); * } * } * } * } */ for (int i = 0; i < decls.NumChildren; i++) { AST decl = decls[i]; switch (decl.Tag) { case NodeType.Method: GenMethod(decl); break; case NodeType.Const: GenConstDefn(decl); break; case NodeType.Struct: // already handled above break; default: throw new Exception("Unexpected tag: " + n.Tag.ToString()); } } // start the data section and // declare any string constants used in the program Asm.AppendDirective(".data"); defineStringConstants(); // if there are any static data items left to declare, they should // be generated at this point ... but there probably aren't any }
// n is a subtree which generates a true-false test // TL and FL are labels to jump to if the test is true/false respectively void GenConditional(AST n, string TL, string FL, IList <Tuple <string, FrontEnd.CbType, int, int> > LocalVariables) { int lhs, rhs; switch (n.Tag) { case NodeType.And: // DONE string mida = getNewLabel(); // check if first condition is true GenConditional(n[0], mida, FL, LocalVariables); // if first condition is true, check second condition Asm.AppendLabel(mida); GenConditional(n[1], TL, FL, LocalVariables); break; case NodeType.Or: // DONE string mido = getNewLabel(); // check if first condition is true; if true, go to end GenConditional(n[0], TL, mido, LocalVariables); // if first condition is false, check second condition Asm.AppendLabel(mido); GenConditional(n[1], TL, FL, LocalVariables); break; case NodeType.Equals: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("beq", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.NotEquals: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("bne", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.LessThan: // DONENG // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("blt", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.GreaterThan: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("bgt", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.LessOrEqual: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("ble", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.GreaterOrEqual: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("bge", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; default: throw new Exception("Unexpected tag: " + n.Tag.ToString()); } }
void GenStatement(AST n, IList <Tuple <string, FrontEnd.CbType, int, int> > LocalVariables) { Loc variable; switch (n.Tag) { case NodeType.Assign: // DONE ; NEEDS CHECKING int reg; Loc lhs = GenVariable(n[0], LocalVariables); // LHS // check for call if (n[1].Tag == NodeType.Call) { GenStatement(n[1], LocalVariables); // RHS reg = 1; } else { reg = GenExpression(n[1], LocalVariables); // RHS } if (lhs.Type == MemType.Word || lhs.Type == MemType.Byte) { Asm.Append("str", Loc.RegisterName(reg), lhs); } else { throw new Exception("unsupported memory type " + lhs.Type.ToString()); } freeReg(reg); break; case NodeType.LocalDecl: // DONE ; NEEDS CHECKING int offset; int typeSize; if (n[0].Type == FrontEnd.CbType.Int || n[0].Type == FrontEnd.CbType.String || n[0].Type is FrontEnd.CbArray) { typeSize = 4; } else if (n[0].Type is FrontEnd.CbStruct) { typeSize = getTypeSize(n[0].Type); } else // unknown { throw new Exception(string.Format("Unknown local declaration type '{0}'", n[0].Type)); } // add newly declared variables to array for (int i = 0; i < n[1].NumChildren; i++) { offset = getNextOffset(LocalVariables); LocalVariables.Add(Tuple.Create(((AST_leaf)n[1][i]).Sval, n[0].Type, offset, typeSize)); } break; case NodeType.Block: // DONE for (int i = 0; i < n.NumChildren; i++) { GenStatement(n[i], LocalVariables); } break; case NodeType.Read: // DONE variable = GenVariable(n[1], LocalVariables); Asm.Append("bl", "cb.ReadInt"); Asm.Append("str", Loc.RegisterName(0), variable); break; case NodeType.Call: // Note the special case: cbio.Write(x) where x is an int or a string expression. // The argument x must be loaded into register r0 and then a bl instruction // with cb.WriteInt or cb.WriteString as the destination must be generated. // Otherwise for a call to a method in the CFlat program, the actual parameters // should be evaluated in reverse order and pushed onto the stack; then a // bl instruction to the method generated; that is followed by an add immediate // instruction to pop the stack of all the parameters. // cbio.Write(x) if (n[0].Tag == NodeType.Dot) { int regw = GenExpression(n[1][0], LocalVariables); Asm.Append("mov", "r0", Loc.RegisterName(regw)); // print integer if (n[1][0].Type == FrontEnd.CbType.Int) { Asm.Append("bl", "cb.WriteInt"); } // print string else if (n[1][0].Type == FrontEnd.CbType.String) { Asm.Append("bl", "cb.WriteString"); } else { throw new Exception("Invalid parameter to cbio.Write: " + n[1][0].Tag.ToString()); } freeReg(regw); } // regular method call else { int tmpr = getReg(); AST param = n[1]; int totalSize = 0; for (int i = 0; i < param.NumChildren; i++) { int size = getTypeSize(param[i].Type); totalSize += size; int register = GenExpression(param[i], LocalVariables); variable = new LocRegOffset(sp, -size, MemType.Word); Asm.Append("str", Loc.RegisterName(register), variable + "!"); } Console.WriteLine("Calculated {0} bytes required for parameters of method '{1}'", totalSize, ((AST_leaf)n[0]).Sval); // go to method Asm.Append("bl", ((AST_leaf)n[0]).Sval); // pop bytes off stack Asm.Append("add", "sp", "sp", "#" + totalSize.ToString()); // move result out of scratch register Asm.Append("mov", Loc.RegisterName(tmpr), "r0"); // store result in local variable variable = new LocRegOffset(fp, -totalSize, MemType.Byte); Asm.Append("str", Loc.RegisterName(tmpr), variable); Console.WriteLine("Method call register r{0}", tmpr); freeReg(tmpr); } break; case NodeType.Return: // DONE ; NEEDS CHECKING ; MAYBE NEEDS TO DO A LOT MORE // load result into r1 if something is returned if (n.NumChildren > 0) // FIX ME: "n[0].Tag != CbType.Empty" does not work { int ret = GenExpression(n[0], LocalVariables); Asm.Append("mov", Loc.RegisterName(1), Loc.RegisterName(ret)); } // return statement is a transfer to the label held in 'returnLabel' Asm.Append("b", returnLabel); break; case NodeType.PlusPlus: // DONE int pp = GenExpression(n[0], LocalVariables); string preg = Loc.RegisterName(pp); Asm.Append("add", preg, preg, "#1"); freeReg(pp); break; case NodeType.MinusMinus: // DONE int mm = GenExpression(n[0], LocalVariables); string mreg = Loc.RegisterName(mm); Asm.Append("sub", mreg, mreg, "#1"); freeReg(mm); break; case NodeType.If: // DONE string tl = getNewLabel(); string lend = getNewLabel(); // no else statement if (n[2].Tag == NodeType.Empty) { // if GenConditional(n[0], tl, lend, LocalVariables); // then Asm.AppendLabel(tl); GenStatement(n[1], LocalVariables); Asm.Append("b", lend); } // else statement else { string fl = getNewLabel(); // if GenConditional(n[0], tl, fl, LocalVariables); // then Asm.AppendLabel(tl); GenStatement(n[1], LocalVariables); Asm.Append("b", lend); // else Asm.AppendLabel(fl); GenStatement(n[2], LocalVariables); } // end of if statement Asm.AppendLabel(lend); break; case NodeType.While: // DONE ; NEEDS CHECKING string wcond = getNewLabel(); string wstart = getNewLabel(); string wend = getNewLabel(); // while Asm.AppendLabel(wcond); GenConditional(n[0], wstart, wend, LocalVariables); // then do Asm.AppendLabel(wstart); GenStatement(n[1], LocalVariables); Asm.Append("b", wcond); // end of loop Asm.AppendLabel(wend); break; case NodeType.Break: // DONE ; NEEDS CHECKING ; MIGHT NEED TO DO A LOT MORE Asm.Append("b", returnLabel); break; case NodeType.Empty: // DONE // no code to generate! break; default: throw new Exception("Unexpected tag: " + n.Tag.ToString()); } }
/********************** AST Traversal Methods ************************/ int GenExpression(AST n, IList <Tuple <string, FrontEnd.CbType, int, int> > LocalVariables) { int result = 0; int lhs, rhs; Loc mem; switch (n.Tag) { case NodeType.Ident: // DONE ; NEEDS CHECKING mem = GenVariable(n, LocalVariables); result = getReg(); Asm.Append("ldr", Loc.RegisterName(result), mem); break; case NodeType.Dot: // DONE ; NEEDS CHECKING mem = GenVariable(n, LocalVariables); result = getReg(); Asm.Append("ldr", Loc.RegisterName(result), mem); break; case NodeType.Index: // DONE mem = GenVariable(n, LocalVariables); result = getReg(); Asm.Append("ldr", Loc.RegisterName(result), mem); break; case NodeType.Add: // DONE result = lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("add", Loc.RegisterName(lhs), Loc.RegisterName(lhs), Loc.RegisterName(rhs)); freeReg(rhs); break; case NodeType.StringConst: // DONE result = getReg(); string slab = createStringConstant(((AST_leaf)n).Sval); Asm.Append("ldr", Loc.RegisterName(result), "=" + slab); break; case NodeType.UnaryMinus: // DONE result = lhs = GenExpression(n[0], LocalVariables); Asm.Append("rsb", Loc.RegisterName(lhs), Loc.RegisterName(lhs), "#0"); break; case NodeType.Sub: // DONE result = lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("sub", Loc.RegisterName(lhs), Loc.RegisterName(lhs), Loc.RegisterName(rhs)); freeReg(rhs); break; case NodeType.Mul: // DONE lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); result = getReg(); Asm.Append("mul", Loc.RegisterName(result), Loc.RegisterName(lhs), Loc.RegisterName(rhs)); freeReg(lhs); freeReg(rhs); break; case NodeType.Div: // DONE result = lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("mov", "r0", Loc.RegisterName(lhs)); Asm.Append("mov", "r1", Loc.RegisterName(rhs)); Asm.Append("bl", "cb.DivMod"); Asm.Append("mov", Loc.RegisterName(lhs), "r0"); freeReg(rhs); break; case NodeType.Mod: // DONE result = lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("mov", "r0", Loc.RegisterName(lhs)); Asm.Append("mov", "r1", Loc.RegisterName(rhs)); Asm.Append("bl", "cb.DivMod"); Asm.Append("mov", Loc.RegisterName(lhs), "r1"); freeReg(rhs); break; case NodeType.IntConst: // DONE result = getReg(); int val = ((AST_leaf)n).Ival; if (255 >= val && val >= 0) { Asm.Append("mov", Loc.RegisterName(result), "#" + val.ToString()); } else if (-255 <= val && val < 0) { Asm.Append("mvn", Loc.RegisterName(result), "#" + (-val).ToString()); } else { Asm.Append("ldr", Loc.RegisterName(result), "=" + val.ToString()); } break; case NodeType.NewStruct: notImplemented(n, "GenExpression"); break; case NodeType.NewArray: // DONE ; NEEDS CHECKING // calculate heap space needed (4 bytes for length of array, and 'size' bytes for each element) int length = ((AST_leaf)n[1]).Ival; int size = getTypeSize(n[0].Type); int space = (length * size) + 4; int reg = getReg(); Asm.Append("mov", "r0", "#" + space.ToString()); // request space from the malloc routine Asm.Append("bl", "cb.Malloc"); Asm.Append("mov", Loc.RegisterName(reg), "#" + length.ToString()); // store array size in first word, and advance pointer to first element mem = new LocRegOffset(0, size, MemType.Word); Asm.Append("str", Loc.RegisterName(reg), mem); freeReg(reg); result = 0; break; default: throw new Exception("Unexpected tag: " + n.Tag.ToString()); } return(result); }
Loc GenVariable(AST n, IList <Tuple <string, FrontEnd.CbType, int, int> > LocalVariables) { Loc result = null; int lhs, offset = 0; MemType mtyp; switch (n.Tag) { case NodeType.Ident: // The ident must be a local variable or a formal parameter. // In either case, the memory location is at an offset from // the frame pointer register. // determine offset offset = getOffset(LocalVariables, ((AST_leaf)n).Sval); Console.WriteLine("Offset: {0}", offset); // local variable if (offset != -1) { result = new LocRegOffset(fp, -offset, MemType.Word); } else { int reg = getReg(); Asm.Append("ldr", Loc.RegisterName(reg), "=" + ((AST_leaf)n).Sval); result = new LocRegOffset(reg, 0, MemType.Word); } break; case NodeType.Dot: // FIX ME // case where expression is String.Length if (n[0].Type == FrontEnd.CbType.String) { lhs = getReg(); int reg = GenExpression(n[0], LocalVariables); Asm.Append("mov", "r0", Loc.RegisterName(reg)); Asm.Append("bl", "cb.StrLen"); offset = 0; mtyp = MemType.Word; } // case where expression is Array.Length else if (n[0].Type is FrontEnd.CbArray) { lhs = GenExpression(n[0], LocalVariables); offset = -4; mtyp = MemType.Word; } // case where expression is Struct.Field else if (n[0].Type is FrontEnd.CbStruct) { // FIX ME // The left operand must be an expression with a struct type. // The right operand must be the name of a field in that struct. // The code should set result to a LocRegOffset instance where // the register comes from n[0] and the offset from n[1]. // get memory location of struct lhs = GenExpression(n[0], LocalVariables); string structName = getStructName(n[0].Type); string fieldName = ((AST_leaf)n[1]).Sval; offset = -1; Dictionary <string, Tuple <int, int> > fields; if (structs.TryGetValue(structName, out fields)) { Tuple <int, int> properties; if (fields.TryGetValue(fieldName, out properties)) { offset = properties.Item1; } } if (offset == -1) { throw new Exception(string.Format("Struct {0} does not contain field '{1}'; Line {2}", structName, fieldName, n.LineNumber)); } offset = -offset; mtyp = MemType.Word; } else { throw new Exception("Unknown Dot operation with left node type " + n[0].Type.ToString()); } result = new LocRegOffset(lhs, offset, mtyp); break; case NodeType.Index: // The left operand must be an expression with an array or string type // The right operand must be an int expression to use as an index. // The code should set result to a LocRegIndex instance where // the register comes from n[0] and the offset from n[1]. lhs = GenExpression(n[0], LocalVariables); // get the offset offset = GenExpression(n[1], LocalVariables); Asm.Append("add", Loc.RegisterName(offset), "#1"); // struct if (n[0].Tag == NodeType.Dot) { int typeSize = getTypeSize(n[0].Type); // FIX ME: does this work? Asm.Append("ldr", "r1", "=" + typeSize.ToString()); Asm.Append("rsb", "r1", "r1", "#0"); Asm.Append("mul", Loc.RegisterName(offset), Loc.RegisterName(offset), "r1"); } // regular array else { Asm.Append("ldr", "r2", "=-4"); Asm.Append("mul", Loc.RegisterName(offset), Loc.RegisterName(offset), "r1"); } mtyp = MemType.Byte; result = new LocRegIndex(lhs, offset, mtyp); break; } return(result); }
public void GenProgram(AST n) { // main method prologue Asm.AppendDirective(".global _start"); Asm.AppendDirective(".text"); Asm.AppendLabel("_start"); Asm.Append("mov", "r0", "#0"); Asm.Append("bl", "Main"); // main method epilogue Asm.Append("mov", "r0", "#0x18"); Asm.Append("mov", "r1", "#0"); Asm.Append("swi", "0x123456"); AST decls = n[2]; for (int i = 0; i < decls.NumChildren; i++) { AST decl = decls[i]; if (decl.Tag == NodeType.Struct) structs.Add(((AST_leaf)decl[0]).Sval, new Dictionary<string, Tuple<int,int>>()); } for (int i = 0; i < decls.NumChildren; i++) { AST decl = decls[i]; if (decl.Tag == NodeType.Struct) { AST fields = decl[1]; string name = ((AST_leaf)decl[0]).Sval; Dictionary<string, Tuple<int,int>> s; if (structs.TryGetValue(name, out s)) { int pos = 0; for (int j = 0; j < fields.NumChildren; j++) { AST fieldDecl = fields[j]; AST idList = fieldDecl[1]; int size = getTypeSize(fieldDecl[0].Type); for (int k = 0; k < idList.NumChildren; k++) { //Console.WriteLine("Structure '{0}' has field '{1}' of size '{2}' at position '{3}'", name, ((AST_leaf)idList[k]).Sval, size, pos); Tuple<int, int> t = new Tuple<int, int>(pos, size); s.Add(((AST_leaf)idList[k]).Sval, t); pos += size; } } } } } /* // how to access struct properties foreach (string s in structs.Keys) { Dictionary<string, Tuple<int,int>> s0; if (structs.TryGetValue(s, out s0)) { foreach (string f in s0.Keys) { Tuple<int, int> t; if (s0.TryGetValue(f, out t)) { Console.WriteLine("Structure '{0}' has field '{1}' of size '{3}' at position '{2}'", s, f, t.Item1, t.Item2); } } } } */ for (int i = 0; i < decls.NumChildren; i++) { AST decl = decls[i]; switch (decl.Tag) { case NodeType.Method: GenMethod(decl); break; case NodeType.Const: GenConstDefn(decl); break; case NodeType.Struct: // already handled above break; default: throw new Exception("Unexpected tag: " + n.Tag.ToString()); } } // start the data section and // declare any string constants used in the program Asm.AppendDirective(".data"); defineStringConstants(); // if there are any static data items left to declare, they should // be generated at this point ... but there probably aren't any }
Loc GenVariable(AST n, IList<Tuple<string, FrontEnd.CbType, int, int>> LocalVariables) { Loc result = null; int lhs, offset = 0; MemType mtyp; switch (n.Tag) { case NodeType.Ident: // The ident must be a local variable or a formal parameter. // In either case, the memory location is at an offset from // the frame pointer register. // determine offset offset = getOffset(LocalVariables, ((AST_leaf)n).Sval); Console.WriteLine("Offset: {0}", offset); // local variable if (offset != -1) { result = new LocRegOffset(fp, -offset, MemType.Word); } else { int reg = getReg(); Asm.Append("ldr", Loc.RegisterName(reg), "=" + ((AST_leaf)n).Sval); result = new LocRegOffset(reg, 0, MemType.Word); } break; case NodeType.Dot: // FIX ME // case where expression is String.Length if (n[0].Type == FrontEnd.CbType.String) { lhs = getReg(); int reg = GenExpression(n[0], LocalVariables); Asm.Append("mov", "r0", Loc.RegisterName(reg)); Asm.Append("bl", "cb.StrLen"); offset = 0; mtyp = MemType.Word; } // case where expression is Array.Length else if (n[0].Type is FrontEnd.CbArray) { lhs = GenExpression(n[0], LocalVariables); offset = -4; mtyp = MemType.Word; } // case where expression is Struct.Field else if (n[0].Type is FrontEnd.CbStruct) { // FIX ME // The left operand must be an expression with a struct type. // The right operand must be the name of a field in that struct. // The code should set result to a LocRegOffset instance where // the register comes from n[0] and the offset from n[1]. // get memory location of struct lhs = GenExpression(n[0], LocalVariables); string structName = getStructName(n[0].Type); string fieldName = ((AST_leaf)n[1]).Sval; offset = -1; Dictionary<string, Tuple<int, int>> fields; if (structs.TryGetValue(structName, out fields)) { Tuple<int, int> properties; if (fields.TryGetValue(fieldName, out properties)) { offset = properties.Item1; } } if (offset == -1) throw new Exception(string.Format("Struct {0} does not contain field '{1}'; Line {2}", structName, fieldName, n.LineNumber)); offset = -offset; mtyp = MemType.Word; } else { throw new Exception("Unknown Dot operation with left node type " + n[0].Type.ToString()); } result = new LocRegOffset(lhs, offset, mtyp); break; case NodeType.Index: // The left operand must be an expression with an array or string type // The right operand must be an int expression to use as an index. // The code should set result to a LocRegIndex instance where // the register comes from n[0] and the offset from n[1]. lhs = GenExpression(n[0], LocalVariables); // get the offset offset = GenExpression(n[1], LocalVariables); Asm.Append("add", Loc.RegisterName(offset), "#1"); // struct if (n[0].Tag == NodeType.Dot) { int typeSize = getTypeSize(n[0].Type); // FIX ME: does this work? Asm.Append("ldr", "r1", "=" + typeSize.ToString()); Asm.Append("rsb", "r1", "r1", "#0"); Asm.Append("mul", Loc.RegisterName(offset), Loc.RegisterName(offset), "r1"); } // regular array else { Asm.Append("ldr", "r2", "=-4"); Asm.Append("mul", Loc.RegisterName(offset), Loc.RegisterName(offset), "r1"); } mtyp = MemType.Byte; result = new LocRegIndex(lhs, offset, mtyp); break; } return result; }
void GenStatement(AST n, IList<Tuple<string, FrontEnd.CbType, int, int>> LocalVariables) { Loc variable; switch (n.Tag) { case NodeType.Assign: // DONE ; NEEDS CHECKING int reg; Loc lhs = GenVariable(n[0], LocalVariables); // LHS // check for call if (n[1].Tag == NodeType.Call) { GenStatement(n[1], LocalVariables); // RHS reg = 1; } else reg = GenExpression(n[1], LocalVariables); // RHS if (lhs.Type == MemType.Word || lhs.Type == MemType.Byte) Asm.Append("str", Loc.RegisterName(reg), lhs); else throw new Exception("unsupported memory type " + lhs.Type.ToString()); freeReg(reg); break; case NodeType.LocalDecl: // DONE ; NEEDS CHECKING int offset; int typeSize; if (n[0].Type == FrontEnd.CbType.Int || n[0].Type == FrontEnd.CbType.String || n[0].Type is FrontEnd.CbArray) { typeSize = 4; } else if (n[0].Type is FrontEnd.CbStruct) { typeSize = getTypeSize(n[0].Type); } else // unknown { throw new Exception(string.Format("Unknown local declaration type '{0}'", n[0].Type)); } // add newly declared variables to array for (int i = 0; i < n[1].NumChildren; i++) { offset = getNextOffset(LocalVariables); LocalVariables.Add(Tuple.Create(((AST_leaf)n[1][i]).Sval, n[0].Type, offset, typeSize)); } break; case NodeType.Block: // DONE for (int i = 0; i < n.NumChildren; i++) GenStatement(n[i], LocalVariables); break; case NodeType.Read: // DONE variable = GenVariable(n[1], LocalVariables); Asm.Append("bl", "cb.ReadInt"); Asm.Append("str", Loc.RegisterName(0), variable); break; case NodeType.Call: // Note the special case: cbio.Write(x) where x is an int or a string expression. // The argument x must be loaded into register r0 and then a bl instruction // with cb.WriteInt or cb.WriteString as the destination must be generated. // Otherwise for a call to a method in the CFlat program, the actual parameters // should be evaluated in reverse order and pushed onto the stack; then a // bl instruction to the method generated; that is followed by an add immediate // instruction to pop the stack of all the parameters. // cbio.Write(x) if (n[0].Tag == NodeType.Dot) { int regw = GenExpression(n[1][0], LocalVariables); Asm.Append("mov", "r0", Loc.RegisterName(regw)); // print integer if (n[1][0].Type == FrontEnd.CbType.Int) Asm.Append("bl", "cb.WriteInt"); // print string else if (n[1][0].Type == FrontEnd.CbType.String) Asm.Append("bl", "cb.WriteString"); else throw new Exception("Invalid parameter to cbio.Write: " + n[1][0].Tag.ToString()); freeReg(regw); } // regular method call else { int tmpr = getReg(); AST param = n[1]; int totalSize = 0; for (int i = 0; i < param.NumChildren; i++) { int size = getTypeSize(param[i].Type); totalSize += size; int register = GenExpression(param[i], LocalVariables); variable = new LocRegOffset(sp, -size, MemType.Word); Asm.Append("str", Loc.RegisterName(register), variable + "!"); } Console.WriteLine("Calculated {0} bytes required for parameters of method '{1}'", totalSize, ((AST_leaf)n[0]).Sval); // go to method Asm.Append("bl", ((AST_leaf)n[0]).Sval); // pop bytes off stack Asm.Append("add", "sp", "sp", "#" + totalSize.ToString()); // move result out of scratch register Asm.Append("mov", Loc.RegisterName(tmpr), "r0"); // store result in local variable variable = new LocRegOffset(fp, -totalSize, MemType.Byte); Asm.Append("str", Loc.RegisterName(tmpr), variable); Console.WriteLine("Method call register r{0}", tmpr); freeReg(tmpr); } break; case NodeType.Return: // DONE ; NEEDS CHECKING ; MAYBE NEEDS TO DO A LOT MORE // load result into r1 if something is returned if (n.NumChildren > 0) // FIX ME: "n[0].Tag != CbType.Empty" does not work { int ret = GenExpression(n[0], LocalVariables); Asm.Append("mov", Loc.RegisterName(1), Loc.RegisterName(ret)); } // return statement is a transfer to the label held in 'returnLabel' Asm.Append("b", returnLabel); break; case NodeType.PlusPlus: // DONE int pp = GenExpression(n[0], LocalVariables); string preg = Loc.RegisterName(pp); Asm.Append("add", preg, preg, "#1"); freeReg(pp); break; case NodeType.MinusMinus: // DONE int mm = GenExpression(n[0], LocalVariables); string mreg = Loc.RegisterName(mm); Asm.Append("sub", mreg, mreg, "#1"); freeReg(mm); break; case NodeType.If: // DONE string tl = getNewLabel(); string lend = getNewLabel(); // no else statement if (n[2].Tag == NodeType.Empty) { // if GenConditional(n[0], tl, lend, LocalVariables); // then Asm.AppendLabel(tl); GenStatement(n[1], LocalVariables); Asm.Append("b", lend); } // else statement else { string fl = getNewLabel(); // if GenConditional(n[0], tl, fl, LocalVariables); // then Asm.AppendLabel(tl); GenStatement(n[1], LocalVariables); Asm.Append("b", lend); // else Asm.AppendLabel(fl); GenStatement(n[2], LocalVariables); } // end of if statement Asm.AppendLabel(lend); break; case NodeType.While: // DONE ; NEEDS CHECKING string wcond = getNewLabel(); string wstart = getNewLabel(); string wend = getNewLabel(); // while Asm.AppendLabel(wcond); GenConditional(n[0], wstart, wend, LocalVariables); // then do Asm.AppendLabel(wstart); GenStatement(n[1], LocalVariables); Asm.Append("b", wcond); // end of loop Asm.AppendLabel(wend); break; case NodeType.Break: // DONE ; NEEDS CHECKING ; MIGHT NEED TO DO A LOT MORE Asm.Append("b", returnLabel); break; case NodeType.Empty: // DONE // no code to generate! break; default: throw new Exception("Unexpected tag: " + n.Tag.ToString()); } }
void GenMethod(AST n) { // NOT DONE ; NEEDS A LOT OF WORK Asm.StartMethod(((AST_leaf)n[1]).Sval); // 1. generate prolog code returnLabel = getNewLabel(); // push all registers in r4-r14 onto stack Asm.Append("stmfd", "sp!", "{r4-r12,lr}"); // set up frame pointer Asm.Append("mov", "fp", "sp"); // NOTE: Need to add code in CbTcVistitor.cs to determine number of local variables; // FROM NIGEL... store the sizes as annotations on the tree nodes ... and the leaf // node class for an identifier used as a variable's name or a struct type name // does have an unused int field which can be used for that purpose. // ^^ THIS HAS BEEN DONE, BUT IS NOT TESTED!!! // reserve bytes for local variables in the function int allocb = ((AST_leaf)n[1]).Ival; Console.WriteLine("Allocating {0} bytes for local variables of method '{1}'", allocb*4, ((AST_leaf)n[1]).Sval); Asm.Append("sub", "sp", "sp", "#" + (allocb*4).ToString()); // 2. translate the method body IList<Tuple<string, FrontEnd.CbType, int, int>> LocalVariables = new List<Tuple<string, FrontEnd.CbType, int, int>>(); GenStatement(n[3], LocalVariables); // 3. generate epilog code Asm.EndMethod(); Asm.AppendLabel(returnLabel); // pop local variables Asm.Append("mov", "sp", "fp"); // reload saved registers and return flow Asm.Append("ldmfd", "sp!", "{r4-r12,pc}"); // go back to calling method Asm.Append("mov", "pc", "lr"); }
/********************** AST Traversal Methods ************************/ int GenExpression(AST n, IList<Tuple<string, FrontEnd.CbType, int, int>> LocalVariables) { int result = 0; int lhs, rhs; Loc mem; switch (n.Tag) { case NodeType.Ident: // DONE ; NEEDS CHECKING mem = GenVariable(n, LocalVariables); result = getReg(); Asm.Append("ldr", Loc.RegisterName(result), mem); break; case NodeType.Dot: // DONE ; NEEDS CHECKING mem = GenVariable(n, LocalVariables); result = getReg(); Asm.Append("ldr", Loc.RegisterName(result), mem); break; case NodeType.Index: // DONE mem = GenVariable(n, LocalVariables); result = getReg(); Asm.Append("ldr", Loc.RegisterName(result), mem); break; case NodeType.Add: // DONE result = lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("add", Loc.RegisterName(lhs), Loc.RegisterName(lhs), Loc.RegisterName(rhs)); freeReg(rhs); break; case NodeType.StringConst: // DONE result = getReg(); string slab = createStringConstant(((AST_leaf)n).Sval); Asm.Append("ldr", Loc.RegisterName(result), "=" + slab); break; case NodeType.UnaryMinus: // DONE result = lhs = GenExpression(n[0], LocalVariables); Asm.Append("rsb", Loc.RegisterName(lhs), Loc.RegisterName(lhs), "#0"); break; case NodeType.Sub: // DONE result = lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("sub", Loc.RegisterName(lhs), Loc.RegisterName(lhs), Loc.RegisterName(rhs)); freeReg(rhs); break; case NodeType.Mul: // DONE lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); result = getReg(); Asm.Append("mul", Loc.RegisterName(result), Loc.RegisterName(lhs), Loc.RegisterName(rhs)); freeReg(lhs); freeReg(rhs); break; case NodeType.Div: // DONE result = lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("mov", "r0", Loc.RegisterName(lhs)); Asm.Append("mov", "r1", Loc.RegisterName(rhs)); Asm.Append("bl", "cb.DivMod"); Asm.Append("mov", Loc.RegisterName(lhs), "r0"); freeReg(rhs); break; case NodeType.Mod: // DONE result = lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("mov", "r0", Loc.RegisterName(lhs)); Asm.Append("mov", "r1", Loc.RegisterName(rhs)); Asm.Append("bl", "cb.DivMod"); Asm.Append("mov", Loc.RegisterName(lhs), "r1"); freeReg(rhs); break; case NodeType.IntConst: // DONE result = getReg(); int val = ((AST_leaf)n).Ival; if (255 >= val && val >= 0) Asm.Append("mov", Loc.RegisterName(result), "#" + val.ToString()); else if (-255 <= val && val < 0) Asm.Append("mvn", Loc.RegisterName(result), "#" + (-val).ToString()); else Asm.Append("ldr", Loc.RegisterName(result), "=" + val.ToString()); break; case NodeType.NewStruct: notImplemented(n, "GenExpression"); break; case NodeType.NewArray: // DONE ; NEEDS CHECKING // calculate heap space needed (4 bytes for length of array, and 'size' bytes for each element) int length = ((AST_leaf)n[1]).Ival; int size = getTypeSize(n[0].Type); int space = (length * size) + 4; int reg = getReg(); Asm.Append("mov", "r0", "#" + space.ToString()); // request space from the malloc routine Asm.Append("bl", "cb.Malloc"); Asm.Append("mov", Loc.RegisterName(reg), "#" + length.ToString()); // store array size in first word, and advance pointer to first element mem = new LocRegOffset(0, size, MemType.Word); Asm.Append("str", Loc.RegisterName(reg), mem); freeReg(reg); result = 0; break; default: throw new Exception("Unexpected tag: " + n.Tag.ToString()); } return result; }
void GenConstDefn(AST n) { if (n[2].Tag == NodeType.IntConst) { Asm.AppendDirective(".align", "2"); // the .align is almost certainly redundant Asm.AppendLabel(((AST_leaf)n[1]).Sval); Asm.AppendDirective(".word", ((AST_leaf)n[2]).Ival.ToString()); } else // n[2] must be a StringConst createStringConstant(((AST_leaf)n[1]).Sval, ((AST_leaf)n[2]).Sval); }
// n is a subtree which generates a true-false test // TL and FL are labels to jump to if the test is true/false respectively void GenConditional(AST n, string TL, string FL, IList<Tuple<string, FrontEnd.CbType, int, int>> LocalVariables) { int lhs, rhs; switch (n.Tag) { case NodeType.And: // DONE string mida = getNewLabel(); // check if first condition is true GenConditional(n[0], mida, FL, LocalVariables); // if first condition is true, check second condition Asm.AppendLabel(mida); GenConditional(n[1], TL, FL, LocalVariables); break; case NodeType.Or: // DONE string mido = getNewLabel(); // check if first condition is true; if true, go to end GenConditional(n[0], TL, mido, LocalVariables); // if first condition is false, check second condition Asm.AppendLabel(mido); GenConditional(n[1], TL, FL, LocalVariables); break; case NodeType.Equals: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("beq", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.NotEquals: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("bne", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.LessThan: // DONENG // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("blt", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.GreaterThan: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("bgt", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.LessOrEqual: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("ble", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; case NodeType.GreaterOrEqual: // DONE // needs to compare strings? lhs = GenExpression(n[0], LocalVariables); rhs = GenExpression(n[1], LocalVariables); Asm.Append("cmp", Loc.RegisterName(lhs), Loc.RegisterName(rhs)); Asm.Append("bge", TL); Asm.Append("b", FL); freeReg(lhs); freeReg(rhs); break; default: throw new Exception("Unexpected tag: " + n.Tag.ToString()); } }