List <SourceLine> ProcessFromStream(string fileName, int lineNumber, StreamReader sr, bool stopAtFirstInstruction = false) { var sourceLines = new List <SourceLine>(); var lineSources = new List <string>(); var blockComment = false; var readyForNewLine = true; var expected = TokenType.LabelInstr; var previousType = TokenType.None; var opens = new Stack <char>(); Macro definingMacro = null; string nextLine; var stopProcessing = false; var previousWasPlus = false; List <Token> tokens = null; var linesProcessed = lineNumber; while ((nextLine = sr.ReadLine()) != null && !stopProcessing) { if (readyForNewLine) { StartNewLine(); } else { lineSources.Add(nextLine); } linesProcessed++; var it = nextLine.GetIterator(); char c; var previous = EOS; var isWidth = false; while (!_lineHasErrors && (c = it.GetNext()) != EOS) { if (char.IsWhiteSpace(c)) { while (c == ' ' || c == '\t') { previous = c; c = it.GetNext(); } if (c == EOS) { break; } } if (blockComment) { if (c == '*' && it.PeekNext() == '/') { blockComment = !it.MoveNext(); } continue; } char peek = it.PeekNext(); if (c == '/' && peek == '/') { break; } if (c == '*' && peek == '/') { LogError(fileName, lineNumber, it.Index + 1, "\"*/\" does not close a block comment."); break; } if (c == '/' && peek == '*') { it.MoveNext(); blockComment = true; continue; } if (c == ';') { if (!_options.IgnoreCommentColons) { expected = TokenType.Instruction; c = it.FirstOrDefault(chr => chr == ':'); } else { c = EOS; } if (c == EOS) { break; } } if (c == ':') { if ((expected != TokenType.Instruction && expected != TokenType.EndOrBinary && (tokens.Count == 0 || tokens[^ 1].Type != TokenType.Instruction)) || !LineTerminates()) { LogError(fileName, lineNumber, it.Index + 1, "Unexpected expression."); break; } lineSources[^ 1] = lineSources[^ 1].Substring(0, it.Index);
IEnumerable <SourceLine> ProcessMacros(IEnumerable <SourceLine> uncommented) { var macroProcessed = new List <SourceLine>(); RandomAccessIterator <SourceLine> lineIterator = uncommented.GetIterator(); SourceLine line = null; while ((line = lineIterator.GetNext()) != null) { try { if (string.IsNullOrWhiteSpace(line.ParsedSource)) { macroProcessed.Add(line); continue; } if (line.InstructionName.Equals(".macro")) { if (string.IsNullOrEmpty(line.LabelName)) { Assembler.Log.LogEntry(line, line.Instruction, "Macro name not specified."); continue; } var macroName = "." + line.LabelName; if (_macros.ContainsKey(macroName)) { Assembler.Log.LogEntry(line, line.Label, $"Macro named \"{line.LabelName}\" already defined."); continue; } if (Assembler.IsReserved.Any(i => i.Invoke(macroName)) || !char.IsLetter(line.LabelName[0])) { Assembler.Log.LogEntry(line, line.Label, $"Macro name \"{line.LabelName}\" is not valid."); continue; } Reserved.AddWord("MacroNames", macroName); var compare = Assembler.Options.CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; var macro = new Macro(line.Operand, line.ParsedSource, compare); _macros[macroName] = macro; var instr = line; while ((line = lineIterator.GetNext()) != null && !line.InstructionName.Equals(".endmacro")) { if (macroName.Equals(line.InstructionName)) { Assembler.Log.LogEntry(line, line.Instruction, "Recursive macro call not allowed."); continue; } if (line.InstructionName.Equals(".macro")) { Assembler.Log.LogEntry(line, line.Instruction, "Nested macro definitions not allowed."); continue; } if (line.InstructionName.Equals(".include") || line.InstructionName.Equals(".binclude")) { var includes = ExpandInclude(line); foreach (var incl in includes) { if (macroName.Equals(incl.InstructionName)) { Assembler.Log.LogEntry(incl, incl.Instruction, "Recursive macro call not allowed."); continue; } macro.AddSource(incl); } } else { macro.AddSource(line); } } if (!string.IsNullOrEmpty(line.LabelName)) { if (line.OperandHasToken) { Assembler.Log.LogEntry(line, line.Operand, "Unexpected argument found for macro definition closure."); continue; } line.Instruction = null; line.ParsedSource = line.ParsedSource.Replace(".endmacro", string.Empty); macro.AddSource(line); } else if (line == null) { line = instr; Assembler.Log.LogEntry(instr, instr.Instruction, "Missing closure for macro definition."); continue; } } else if (line.InstructionName.Equals(".include") || line.InstructionName.Equals(".binclude")) { macroProcessed.AddRange(ExpandInclude(line)); } else if (_macros.ContainsKey(line.InstructionName)) { if (!string.IsNullOrEmpty(line.LabelName)) { SourceLine clone = line.Clone(); clone.Operand = clone.Instruction = null; clone.UnparsedSource = clone.ParsedSource = line.LabelName; macroProcessed.Add(clone); } Macro macro = _macros[line.InstructionName]; macroProcessed.AddRange(ProcessExpansion(macro.Expand(line.Operand))); } else if (line.InstructionName.Equals(".endmacro")) { Assembler.Log.LogEntry(line, line.Instruction, "Directive \".endmacro\" does not close a macro definition."); continue; } else { macroProcessed.Add(line); } } catch (ExpressionException ex) { Assembler.Log.LogEntry(line, ex.Position, ex.Message); } } return(macroProcessed); }