/// <summary> /// /// </summary> /// <param name="line">The line of code to parse.</param> /// <param name="sourceLine">The line number of the code file.</param> void ParseLine(StringSection line, int iSourceLine, out Error error) { error = Error.None; line = line.TrimLeft(); RemoveComments(ref line); int newInstructionIndex = assembly.ParsedInstructions.Count; bool loopLabel; do // This loop allows us to parse alternating named and anonymous labels (* label: +++ -- anotherLabel:) { loopLabel = false; loopLabel |= ParseNamedLabels(ref line, newInstructionIndex, iSourceLine); loopLabel |= ParseAnonymousLabel(ref line, newInstructionIndex, iSourceLine); } while (loopLabel); if (line.IsNullOrEmpty || line[0] == ';') { // Nothing on this line return; } // Dot-prefixed directive if (line[0] == '.') { line = line.Substring(1); var directiveName = GetSymbol(line); line = line.Substring(directiveName.Length).TrimLeft(); if (!ParseDirective(directiveName, line, iSourceLine, out error)) { error = new Error(ErrorCode.Directive_Not_Defined, string.Format(Error.Msg_DirectiveUndefined_name, directiveName), iSourceLine); return; } return; } bool parsedUncolonedLabel = false; // Set to true when an uncoloned label is found so we don't look for one again. bool loopAgain = false; // Set to true when an uncoloned label is found to loop back and try to parse the remaining text do { loopAgain = false; var symbol = GetSymbol(line); if (symbol.Length == 0) { break; } line = line.Substring(symbol.Length).Trim(); if (ParseDirective(symbol, line, iSourceLine, out error)) { return; } else if (ParseInstruction(symbol, line, iSourceLine, out error)) { return; } else if ((line.Length > 0 && line[0] == '=') || (line.Length > 1 && line[0] == ':' && line[1] == '=')) // Assignments and label assignments // := is a cross between a label and assignment: It declares a label with an explicit value. { bool isLabel = (line[0] == ':'); var expression = line.Substring(1).TrimLeft(); if (isLabel) { expression = expression.Substring(1).TrimLeft(); } if (expression.IsNullOrEmpty) { error = new Error(ErrorCode.Expected_Expression, Error.Msg_ExpectedValue, iSourceLine); } else { ParseAssignment(symbol, isLabel, expression, iSourceLine); } } else { // Todo: ensure 'symbol' is a valid label name if (!Assembler.RequireColonOnLabels && !parsedUncolonedLabel && symbol.Length > 0) { if (symbol[0] == '@') { string labelName = mostRecentNamedLabel + "." + symbol.Substring(1).ToString(); assembly.Labels.Add(new Label(labelName, newInstructionIndex, iSourceLine, true)); } else { mostRecentNamedLabel = symbol.ToString(); assembly.Labels.Add(new Label(symbol.ToString(), newInstructionIndex, iSourceLine, false)); } parsedUncolonedLabel = true; loopAgain = true; } else { error = new Error(ErrorCode.Unexpected_Text, Error.Msg_BadLine, iSourceLine); } } } while (parsedUncolonedLabel && loopAgain); }