public Function ParseFunction(Node funcNode) { // Left node is identifier, right node is funcNode Expect(funcNode.Left, TokenType.Identifier); Expect(funcNode.Right, TokenType.Block); var func = new Function(funcNode, funcNode.Left.Value); if (funcNode.Right.Right == null) { return(func); } // Create a data label for this functions lr store var data = new Data(DataType.Return) { Name = "return" + Data.Count, Type = DataType.Word, Value = "0" }; Data.Add(data); var lrRegister = func.AddRegister(data); func.StoreLr(data, lrRegister); // Iterate through statements in this functions block // Parse return separately var statement = funcNode.Right.Right; do { if (statement.Type == TokenType.Return) { func.AddReturn(ParseReturn(func, statement)); } else { func.AddData(ParseStatement(func, statement)); } statement = statement.Right; } while (statement != null); func.LoadLr(data, lrRegister); return(func); }
/// <summary> /// Generate assembly code to load an identifier into a register. /// </summary> /// <param name="identifierNode">Node to generate for</param> /// <param name="parent">Parent containing assembly code</param> /// <param name="register">Register to load into</param> private void LoadIdentifier(Node identifierNode, Function parent, int register) { Logger.Instance.Debug("LoadIdentifier() {0}", identifierNode.ToString()); var locData = GetDataWithName(parent, identifierNode.Value); // If this is an identifier we just load it into the right register var data = locData as Statement; if (data != null && data.Type != DataType.Function) { var s = data; if (register != s.Register) // Don't load it in if it is already in the right register { parent.Lines.Add(string.Format("\tmov r{0}, r{1}\n", register, s.Register)); } return; } // Otherwise, take a different action dpeending on data type switch (locData.Type) { case DataType.Global: // if global, find the global and assemble from this parent var global = (Global)locData; parent.AssembleData(global.Datas, false, false); break; case DataType.Number: parent.Lines.Add(string.Format("\tmov r{0}, #{1}\n", register, locData.Value)); break; case DataType.Asciz: parent.Lines.Add(string.Format("\tldr r{0}, addr_{1}\n", register, locData.Name)); break; case DataType.Function: // Check if anything is already in r0 (function return) int?backupReg = null; var backupData = parent.Registers.ElementAtOrDefault(0); if (backupData != null) { // Move into an unused register backupReg = parent.AddRegister(backupData) + 1; parent.Lines.Add(string.Format("\tmov r{0}, r0\n", backupReg)); } // Call function parent.Lines.Add(string.Format("\tbl {0}\n", locData.Value)); // Result of function is in r0 // Move that into the required register if (register != 0) { parent.Lines.Add(string.Format("\tmov r{0}, r0\n", register)); } // If data was backed up restore it if (backupReg != null) { parent.Lines.Add(string.Format("\tmov r0, r{0}\n", backupReg)); } break; case DataType.Operator: // Data is in a register in parent, find it and load it var regData = parent.Registers.FirstOrDefault(r => r.Name == locData.Name); if (regData == null) { throw new Exception("Missing variable"); } // Useless moving data into a register its already in var existingRegister = ((Statement)regData).Register; if (existingRegister != register) { parent.Lines.Add(string.Format("\tmov r{0}, r{1}\n", register, existingRegister)); } break; default: throw new NotImplementedException("Cannot load this data type as an identifier"); } }