IEnumerable <SourceLine> ProcessExpansion(IEnumerable <SourceLine> sources) { var processed = new List <SourceLine>(); foreach (SourceLine line in sources) { if (line.InstructionName.Equals(".include") || line.InstructionName.Equals(".binclude")) { processed.AddRange(ExpandInclude(line)); } else if (_macros.ContainsKey(line.InstructionName)) { Macro macro = _macros[line.InstructionName]; processed.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."); break; } else { processed.Add(line); } } return(processed); }
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); }