/// <summary> /// Translates a line of MIPS assembly into the intermediate format and returns /// the result. /// </summary> /// <param name="assembly">MIPS assembly.</param> /// <param name="parentBlock">ProgramBlock containing previously translated code /// and associated information</param> /// <returns>Translated chunk.</returns> public IProgramChunk TranslateLine(string assembly, ProgramBlock parentBlock) { IProgramChunk translatedChunk = null; //***LABELS*** if (assembly.Contains(":")) { string labelName = assembly.Substring(0, assembly.IndexOf(":")); //label does not exist as an orphan if(parentBlock.GetOrphanJumpTargetByLabel(labelName) == null) translatedChunk = new ProgramChunkJumpTarget(labelName); //label does exist as an orphan. else { translatedChunk = parentBlock.GetOrphanJumpTargetByLabel(labelName); parentBlock.RemoveOrphanJumpTarget(parentBlock.GetOrphanJumpTargetByLabel(labelName)); } } //**KEYWORDS** else { string lineKeyword = assembly.Split(' ')[0]; string[] lineParameters = assembly.Substring(assembly.IndexOf(' ') + 1).Split(' '); switch (lineKeyword) { #region J - Unconditional Jump case "j": { ProgramChunkJumpTarget target = parentBlock.GetJumpTargetByLabel(lineParameters[0]); //label does not exist but should be defined later. create an orphan placeholder. if (target == null) { target = new ProgramChunkJumpTarget(lineParameters[0]); parentBlock.AddOrphanJumpTarget(target); } translatedChunk = new ProgramChunkJumpUnconditional(target); } break; #endregion #region Form: (command) product, multiplicand, multiplier case "addi": case "add": case "sllv"://SLL - Shift Left Logical (variable) case "sll": //SLL - Shift Left Logical (constant) case "sub": case "subi": //Form: (command) product, multiplicand, multiplier //see below (or above i guess) to see acceptable commands //Addition: 'add', and 'addi' (default) Operand commandOperand = Operand.ADDITION; //Multiplication: 'sll', and 'sllv' if(lineKeyword.Equals("sll") || lineKeyword.Equals("sllv")) commandOperand = Operand.MULTIPLICATION; //Subtraction: 'sub', and 'subi' if(lineKeyword.Equals("sub") || lineKeyword.Equals("subi")) commandOperand = Operand.SUBTRACTION; BlockVariable termAssignee; //must be variable ProgramChunkExpressionTerm termMultiplicand;//constant or variable? I think the doc only support var's ProgramChunkExpressionTerm termMultiplier; //constant or variable #region 1) find assignee if (IsVariable(lineParameters[0])) { ProcessVariable(ref lineParameters[0]); BlockVariable variable = parentBlock.GetVariableByNameForced(lineParameters[0]); termAssignee = variable; } else throw new Exception("FrontendMIPS - Detected attempt to assign expression to constant."); #endregion #region 2) find multiplicand if (IsVariable(lineParameters[1])) { ProcessVariable(ref lineParameters[1]); BlockVariable variable = parentBlock.GetVariableByNameForced(lineParameters[1]); termMultiplicand = variable; } else //The first (real) term is a constant { //CHECKME: attempt to parse hex numbers, does it work this way? int term = int.Parse(lineParameters[1], System.Globalization.NumberStyles.HexNumber); termMultiplicand = new BlockConstant(term); } #endregion #region 3) find multiplier if (IsVariable(lineParameters[2])) { ProcessVariable(ref lineParameters[2]); BlockVariable variable = parentBlock.GetVariableByNameForced(lineParameters[2]); termMultiplier = variable; } else//constant { //TODO: support hex numbers if(lineParameters[2].Contains("x")) throw new Exception("FrontendMIPS - Cannot parse hexidecimal numbers."); int term = int.Parse(lineParameters[2]); //deal with bit shifts if (lineKeyword.Equals("sll")) term *= 2; else if (lineKeyword.Equals("sllv")) throw new Exception("FrontendMIPS - Cannot bit shift by variable without subexpression support."); termMultiplier = new BlockConstant(term); } #endregion ProgramChunkExpression expression = new ProgramChunkExpression(termMultiplicand, commandOperand, termMultiplier); translatedChunk = new ProgramChunkAssignment(termAssignee, expression); break; #endregion #region Branchs (BNE, BEQ) //Form: if (var equality var) goto label. //e.g. "beq $a1 0 finish" case "bne": case "beq": { Equality equality; ProgramChunkExpressionTerm first; ProgramChunkExpressionTerm second; ProgramChunkJumpTarget target; #region 1) determine equality if (lineKeyword.Equals("bne")) equality = Equality.NOT_EQUAL; else if (lineKeyword.Equals("beq")) equality = Equality.EQUAL; else throw new Exception("FrontendMIPS - Unimplemented equality found."); #endregion #region 2) find first item to evaluate if (IsVariable(lineParameters[0])) { ProcessVariable(ref lineParameters[0]); first = parentBlock.GetVariableByNameForced(lineParameters[0]); } else //constant { //TODO: support hex numbers if (lineParameters[0].Contains("x")) throw new Exception("FrontendMIPS - Cannot parse hexidecimal numbers."); first = new BlockConstant(int.Parse(lineParameters[0])); } #endregion #region 3) find second item to evaluate if (IsVariable(lineParameters[1])) { ProcessVariable(ref lineParameters[1]); second = parentBlock.GetVariableByNameForced(lineParameters[1]); } else //constant { //TODO: support hex numbers if (lineParameters[1].Contains("x")) throw new Exception("FrontendMIPS - Cannot parse hexidecimal numbers."); second = new BlockConstant(int.Parse(lineParameters[1])); } #endregion #region 4) generate jump for true target = parentBlock.GetJumpTargetByLabel(lineParameters[2]); //label does not exist but should be defined later. create an orphan placeholder. if (target == null) { target = new ProgramChunkJumpTarget(lineParameters[2]); parentBlock.AddOrphanJumpTarget(target); } #endregion translatedChunk = new ProgramChunkBranch(equality, first, new ProgramChunkJumpUnconditional(target), second, new ProgramChunkNoOperation()); } break; #endregion } } if (translatedChunk == null) { translatedChunk = new ProgramChunkNoOperation(); UtilDebugConsole.AddException(new Exception("FrontendMIPS - Unidentified assembly encountered during translation.")); } return translatedChunk; }
private string EmitExpression(ProgramChunkExpression expression) { string finalExpression; if (expression.FirstTerm is BlockConstant) finalExpression = ((BlockConstant)expression.FirstTerm).Constant.ToString(); else if (expression.FirstTerm is BlockVariable) finalExpression = ((BlockVariable)expression.FirstTerm).Name; else throw new Exception("Attempted to emit an expression with at term that was not a constant or variable."); //HACK: e.g. n + 0 if (expression.SecondTerm is BlockConstant && ((BlockConstant)expression.SecondTerm).Constant == 0 && expression.Oper == Operand.ADDITION) return finalExpression; if (expression.Oper == Operand.ADDITION) finalExpression += " + "; else if (expression.Oper == Operand.DIVISION) finalExpression += " / "; else if (expression.Oper == Operand.MULTIPLICATION) finalExpression += " * "; else if (expression.Oper == Operand.SUBTRACTION) finalExpression += " - "; else throw new Exception("Attempted to emit an expression with an operand that doesn't exist."); if (expression.SecondTerm is BlockConstant) finalExpression += ((BlockConstant)expression.SecondTerm).Constant.ToString(); else if (expression.SecondTerm is BlockVariable) finalExpression += ((BlockVariable)expression.SecondTerm).Name; else throw new Exception("Attempted to emit an expression with at term that was not a constant or variable."); return finalExpression; }
//NOTE: we only allow the assignment to a variable, constants // can't change value. public ProgramChunkAssignment(BlockVariable variable, ProgramChunkExpression expression) { Variable = variable; Expression = expression; }