/// <summary> /// Generates the byte representation of an instruction from a line of assembly code. /// </summary> /// <param name="asmLine">The line to parse.</param> /// <param name="objFile">The object file that will be written to.</param> /// <param name="currAlignment">The current specified alignment of the file.</param> public void GenerateCodeForSegment(string fileName, LineData asmLine, BasicObjectFile objFile, int currAlignment) { string[] tokens = asmLine.Text.Split(' ', '\t'); string[] fixedTokens = ParserCommon.GetTrimmedTokenArray(tokens).ToArray(); bool foundDataDeclaration = false; int dataDeclarationIdx = 0; for (int i = 0; i < fixedTokens.Length && !foundDataDeclaration; ++i) { if (ParserCommon.IsDataDeclaration(fixedTokens[i])) { foundDataDeclaration = true; dataDeclarationIdx = i; } } // we found a data declaration; make sure that there's at least one value following it. if (foundDataDeclaration) { if (dataDeclarationIdx + 1 < fixedTokens.Length) { // if it is a trivial type, use our precomputed map to get the size. if (ParserCommon.IsTrivialDataType(fixedTokens[dataDeclarationIdx])) { // determine before writing the next data element if we need to add padding. int paddingSize = ParserCommon.GetNumPaddingBytes(m_NumBytesLaidOut, currAlignment); int dataSize = ParserCommon.DetermineTrivialDataSize(fixedTokens[dataDeclarationIdx]); int numElements = ParserCommon.GetArraySize(asmLine.Text, fixedTokens[dataDeclarationIdx]); if (dataSize > paddingSize) { // add as much padding as we need to reach the next alignment boundary. for (int i = 0; i < paddingSize; ++i) { objFile.AddDataElement((byte)0); m_NumBytesLaidOut += 1; } } int totalReservedSize = dataSize * numElements; m_NumBytesLaidOut += totalReservedSize; AddTrivialDataElementsToFile(objFile, dataSize, asmLine.Text, fixedTokens[dataDeclarationIdx]); } // see if we can figure out the string length else if (ParserCommon.IsStringDeclaration(fixedTokens[dataDeclarationIdx])) { int paddingSize = ParserCommon.GetNumPaddingBytes(m_NumBytesLaidOut, currAlignment); // if this is a string declaration, then get the original string data string dataStr = ParserCommon.GetStringData(asmLine.Text); int dataSize = ParserCommon.DetermineNonTrivialDataLength(fixedTokens[dataDeclarationIdx], dataStr); if (dataSize > paddingSize) { // add as much padding as we need to reach the next alignment boundary. for (int i = 0; i < paddingSize; ++i) { objFile.AddDataElement((byte)0); m_NumBytesLaidOut += 1; } } // add the string data to the object file. AddNonTrivialDataElementToObjectFile(objFile, fixedTokens[dataDeclarationIdx], dataStr); m_NumBytesLaidOut += dataSize; } // otherwise, this must be a .space declaration. just get the size following it. else { int dataSize = ParserCommon.DetermineNonTrivialDataLength(fixedTokens[dataDeclarationIdx], fixedTokens[dataDeclarationIdx + 1]); int paddingSize = ParserCommon.GetNumPaddingBytes(dataSize, currAlignment); // fill the space and padding with zeroes. for (int i = 0; i < dataSize + paddingSize; ++i) { objFile.AddDataElement((byte)0); } // we expect one token after this word. // otherwise, it may be garbage that we should detect. if (fixedTokens.Length > dataDeclarationIdx + 2) { throw new AssemblyException(asmLine.LineNum, "Unknown token \"" + fixedTokens[dataDeclarationIdx + 2] + "\" found."); } } } else { throw new AssemblyException(asmLine.LineNum, "Expected data value after token " + fixedTokens[dataDeclarationIdx]); } } // check to see if this is just a label. // otherwise, it is probably garbage that we should throw. else if (!ParserCommon.ContainsLabel(asmLine.Text)) { throw new AssemblyException(asmLine.LineNum, "Unable to ascertain data type from line " + asmLine.Text); } }
/// <summary> /// Parses an unlabeled line to calculate the appropriate address of the next element (if any). /// </summary> /// <param name="originalLine">The line data being parsed.</param> /// <param name="tokens">The string array of space-separated tokens.</param> /// <param name="alignment">The current alignment</param> /// <returns>A boolean determining if anything of use was parsed. If this is false, /// the line should be examined to make sure a symbol was at least parsed. Otherwise, /// this could indicate that garbage was on the line.</returns> private bool ParseUnlabeledLine(LineData originalLine, string[] tokens, int alignment) { bool foundDataDeclaration = false; int dataDeclarationIdx = 0; // scan it for a data size (e.g. .asciiz, .word, etc) for (int i = 0; i < tokens.Length && !foundDataDeclaration; ++i) { if (ParserCommon.IsDataDeclaration(tokens[i])) { foundDataDeclaration = true; dataDeclarationIdx = i; } } // we found a data declaration; make sure that there's at least one value following it. if (foundDataDeclaration) { int dataSize = 0; if (dataDeclarationIdx + 1 < tokens.Length) { // if it is a trivial type, use our precomputed map to get the size. if (ParserCommon.IsTrivialDataType(tokens[dataDeclarationIdx])) { int paddingSize = ParserCommon.GetNumPaddingBytes(m_TotalBytesLaidOut, alignment); dataSize = ParserCommon.DetermineTrivialDataSize(tokens[dataDeclarationIdx]); int numElementsToStore = ParserCommon.GetArraySize(originalLine.Text, tokens[dataDeclarationIdx]); if (dataSize > paddingSize) { // add as much padding as we need to reach the next alignment boundary. for (int i = 0; i < paddingSize; ++i) { ++m_CurrDataAddress; ++m_TotalBytesLaidOut; } } int reservedSize = numElementsToStore * dataSize; // need to fixup the address here, since we have committed to placing padding // here. if (m_UnresolvedSym != null) { m_UnresolvedSym.Address = m_CurrDataAddress; } m_CurrDataAddress += reservedSize; m_TotalBytesLaidOut += reservedSize; } // otherwise, we'd expect there to be another token after the data type. // see if we can figure out the string length else if (ParserCommon.IsStringDeclaration(tokens[dataDeclarationIdx])) { // if this is a string declaration, then get the original string data string dataStr = ParserCommon.GetStringData(originalLine.Text); dataSize = ParserCommon.DetermineNonTrivialDataLength(tokens[dataDeclarationIdx], dataStr); int paddingSize = ParserCommon.GetNumPaddingBytes(m_TotalBytesLaidOut, alignment); if (dataSize > paddingSize) { // add as much padding as we need to reach the next alignment boundary. for (int i = 0; i < paddingSize; ++i) { ++m_CurrDataAddress; ++m_TotalBytesLaidOut; } } // need to fixup the address here, since we have committed to placing padding // here. if (m_UnresolvedSym != null) { m_UnresolvedSym.Address = m_CurrDataAddress; } m_CurrDataAddress += dataSize; m_TotalBytesLaidOut += dataSize; } // otherwise, this must be a .space declaration. just get the size following it. else { int paddingSize = ParserCommon.GetNumPaddingBytes(m_TotalBytesLaidOut, alignment); dataSize = ParserCommon.DetermineNonTrivialDataLength(tokens[dataDeclarationIdx], tokens[dataDeclarationIdx + 1]); if (dataSize > paddingSize) { // add as much padding as we need to reach the next alignment boundary. for (int i = 0; i < paddingSize; ++i) { ++m_CurrDataAddress; ++m_TotalBytesLaidOut; } } // need to fixup the address here, since we have committed to placing padding // here. // need to really clean this logic up. if (m_UnresolvedSym != null) { m_UnresolvedSym.Address = m_CurrDataAddress; } m_CurrDataAddress += dataSize; m_TotalBytesLaidOut += dataSize; } } else { throw new AssemblyException(originalLine.LineNum, "Expected data value after token " + tokens[dataDeclarationIdx]); } if (m_UnresolvedSym != null) { m_UnresolvedSym.Size = dataSize; m_UnresolvedSym = null; } } return(foundDataDeclaration); }