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); }