/// <summary> /// Reads a line in a .text segment of a program, and adds any found symbols to the /// symbol table. /// </summary> /// <param name="asmLine">The line of assembly code to parse.</param> /// <param name="symbolList">The list of symbols that will be added to.</param> /// <param name="alignment">Unused. Alignment is always on word boundaries in the text segment.</param> public void ParseSymbolsInLine(LineData asmLine, SymbolTable symbolList, int alignment) { string[] tokens = asmLine.Text.Split(' '); // a label should end with a ':' character. // this is OK if there's trash and no real assembly at this point, // as the second pass code generator will flag it. // we're just here to get symbols and addresses. if (ParserCommon.ContainsLabel(tokens[0])) { string labelName = ParserCommon.ExtractLabel(tokens[0]); var label = new Symbol(labelName, SegmentType.Text, m_CurrTextAddress); label.Size = sizeof(int); symbolList.AddSymbol(label); // determine if there are any instructions on this line. string[] subTokens = tokens[0].Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); // if we have more than one subtoken, then there is more than just a label on this line. // increment the number of words in the segment (since we're assuming whatever is on the right-hand side // is an instruction) by however many bytes the instruction is if (subTokens.Length > 1) { ParseUnlabeledLine(asmLine); } } // if this doesn't have a label, and is not empty or a comment, // then this is an instruction. increment the counter. else { ParseUnlabeledLine(asmLine); } }
/// <summary> /// Reads a denoted .data segment line of an assembly program for symbols /// </summary> /// <param name="reader">The reader used to read the file.</param> /// <param name="symbolList">The list of symbols that will be added to.</param> /// <param name="startingLine">The line that the .data segment starts on. Will be incremented</param> public void ParseSymbolsInLine(LineData asmLine, SymbolTable symbolList, int alignment) { string[] tokens = asmLine.Text.Split(' ', '\t'); string[] fixedTokens = ParserCommon.GetTrimmedTokenArray(tokens).ToArray(); // a label should end with a ':' character and should be the first token. if (ParserCommon.ContainsLabel(fixedTokens[0])) { ParseLabeledLine(symbolList, asmLine, fixedTokens, alignment); } // if this doesn't have a label, and is not empty or a comment, // then this is a data element. else { // try to make sure this isn't garbage. // this will return false if no data was parsed, if (!ParseUnlabeledLine(asmLine, fixedTokens, alignment)) { throw new AssemblyException(asmLine.LineNum, "Expected size declaration, received \"" + asmLine.Text + '\"'); } } }
/// <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); } }