/// <summary> /// Create the specified definition, closure, source, comparer, openBlock and closeBlock. /// </summary> /// <returns>The resulting macro.</returns> /// <param name="definition">Definition.</param> /// <param name="closure">Closure.</param> /// <param name="source">Source.</param> /// <param name="comparer">Comparer.</param> /// <param name="openBlock">Open block.</param> /// <param name="closeBlock">Close block.</param> public static Macro Create(SourceLine definition, SourceLine closure, IEnumerable <SourceLine> source, StringComparison comparer, string openBlock, string closeBlock) { var macro = new Macro(); string name = definition.Label; string class_ = ".macro"; bool isSegment = false; if (definition.Instruction.Equals(".segment", comparer)) { isSegment = true; name = definition.Operand; class_ = ".segment"; } if (definition.IsComment == false) { macro.IsSegment = isSegment; if (macro.IsSegment == false) { macro.Source.Add(new SourceLine()); macro.Source.First().Filename = definition.Filename; macro.Source.First().LineNumber = definition.LineNumber; macro.Source.First().Instruction = openBlock; if (string.IsNullOrEmpty(definition.Operand) == false) { var parms = definition.Operand.CommaSeparate(); if (parms == null) { throw new MacroException(definition, "Invalid parameter(s) (" + definition.Operand + ")"); } for (int i = 0; i < parms.Count; i++) { var p = parms[i]; var parm = new Macro.Param { Number = i + 1 }; if (p.Contains("=")) { var ps = p.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries); var pname = ps.First().Trim(); if (ps.Count() != 2) { throw new MacroException(definition, "Default parameter assignment error"); } if (Regex.IsMatch(pname, Patterns.SymbolUnicode) == false) { throw new MacroException(definition, "Parameter name '" + pname + "' invalid"); } parm.Name = pname; parm.DefaultValue = ps.Last().Trim(); } else if (Regex.IsMatch(p, Patterns.SymbolUnicode) == false) { throw new MacroException(definition, "Parameter name '" + p + "' invalid"); } else { parm.Name = p; parm.DefaultValue = string.Empty; } // check for duplicate param names if (macro.Params.Any(prm => parm.Name.Equals(prm.Name, comparer))) { throw new MacroException(definition, "Duplicate parameter name found: " + parm.Name); } macro.Params.Add(parm); } } } } foreach (var line in source.Where(l => !l.IsComment)) { if (object.ReferenceEquals(definition, line) || object.ReferenceEquals(closure, line)) { continue; } if ((isSegment && line.Instruction.Equals("." + name, comparer)) || line.Instruction.Equals("." + name, comparer)) { throw new MacroException(line, string.Format(ErrorStrings.RecursiveMacro, line.Label)); } var param_ix = line.Operand.IndexOf('\\'); if (param_ix >= 0 && isSegment == false) { if (line.Operand.EndsWith("\\")) { throw new MacroException(line, ErrorStrings.MacroParamNotSpecified); } string param = String.Empty; if (char.IsLetterOrDigit(line.Operand.ElementAt(param_ix + 1)) == false) { throw new MacroException(line, ErrorStrings.MacroParamIncorrect); } foreach (var c in line.Operand.Substring(param_ix + 1, line.Operand.Length - param_ix - 1)) { if (Regex.IsMatch(c.ToString(), Patterns.SymbolUnicodeChar)) { param += c; } else { break; } } if (string.IsNullOrEmpty(param)) { throw new MacroException(line, ErrorStrings.MacroParamNotSpecified); } // is the parameter in the operand a number or named if (int.TryParse(param, out int paramref)) { // if it is a number and higher than the number of explicitly // defined params, just add it as a param int paramcount = macro.Params.Count; if (paramref > paramcount) { while (paramref > paramcount) { macro.Params.Add(new Macro.Param { Number = ++paramcount }); } } else if (paramref < 1) { throw new MacroException(line, string.Format(ErrorStrings.InvalidParamRef, param)); } paramref--; macro.Params[paramref].SourceLines.Add(line.SourceInfo()); } else { if (macro.Params.Any(p => p.Name == param) == false) { throw new MacroException(line, string.Format(ErrorStrings.InvalidParamRef, param)); } var macparm = macro.Params.First(p => p.Name == param); macparm.SourceLines.Add(line.SourceInfo()); } } macro.Source.Add(line); } if (closure.IsComment) { throw new MacroException(closure, string.Format(ErrorStrings.MissingClosureMacro, class_)); } if (string.IsNullOrEmpty(closure.Operand) == false) { if (isSegment && !name.Equals(closure.Operand, comparer)) { throw new MacroException(closure, string.Format(ErrorStrings.ClosureDoesNotCloseMacro, definition.Instruction, "segment")); } if (!isSegment) { throw new MacroException(closure, string.Format(ErrorStrings.DirectiveTakesNoArguments, definition.Instruction)); } } if (macro.IsSegment == false) { macro.Source.Add(new SourceLine { Filename = closure.Filename, LineNumber = closure.LineNumber, Label = closure.Label, Instruction = closeBlock }); } return(macro); }
public void Process(SourceLine line) { var instruction = line.Instruction.ToLower(); if (!Processes(line.Instruction)) { if (_macroDefinitions.Count > 0) { // We are in a macro definition if (instruction.Equals(_macros.Last().Key)) { Assembler.Log.LogEntry(line, ErrorStrings.RecursiveMacro, line.Instruction); } _macroDefinitions.Peek().Add(line); } else { // We are consuming source after an undefined .dsegment _expandedSource.Add(line); } return; } if (instruction.Equals(".macro") || instruction.Equals(".segment")) { _macroDefinitions.Push(new List <SourceLine>()); string name; _definitions.Push(line); if (instruction.Equals(".segment")) { if (!string.IsNullOrEmpty(line.Label)) { Assembler.Log.LogEntry(line, ErrorStrings.None); return; } name = line.Operand; } else { name = "." + line.Label; } if (!Macro.IsValidMacroName(name) || _instructionFcn(name)) { Assembler.Log.LogEntry(line, ErrorStrings.LabelNotValid, line.Label); return; } if (_macros.ContainsKey(name)) { Assembler.Log.LogEntry(line, ErrorStrings.MacroRedefinition, line.Label); return; } _macros.Add(name, null); } else if (instruction.Equals(".endmacro") || instruction.Equals(".endsegment")) { var def = instruction.Replace("end", string.Empty); var name = "." + _definitions.Peek().Label; if (!_definitions.Peek().Instruction.Equals(def, Assembler.Options.StringComparison)) { Assembler.Log.LogEntry(line, ErrorStrings.ClosureDoesNotCloseMacro, line.Instruction); return; } if (def.Equals(".segment")) { name = _definitions.Peek().Operand; if (!name.Equals(line.Operand, Assembler.Options.StringComparison)) { Assembler.Log.LogEntry(line, ErrorStrings.None); return; } //name = "." + name; } _macros[name] = Macro.Create(_definitions.Pop(), line, _macroDefinitions.Pop(), Assembler.Options.StringComparison, ConstStrings.OPEN_SCOPE, ConstStrings.CLOSE_SCOPE); if (def.Equals(".segment")) { while (_declarations.Any(l => l.Operand.Equals(name, Assembler.Options.StringComparison))) { var dsegment = _declarations.Pop(); var segname = dsegment.Operand; var ix = _expandedSource.IndexOf(dsegment); _expandedSource.RemoveAt(ix); _expandedSource.InsertRange(ix, _macros[segname].Expand(dsegment)); } } } else if (instruction.Equals(".dsegment")) { if (string.IsNullOrEmpty(line.Operand)) { Assembler.Log.LogEntry(line, ErrorStrings.TooFewArguments, line.Instruction); return; } if (_macros.ContainsKey(line.Operand)) { var seg = _macros[line.Operand]; _expandedSource = seg.Expand(line).ToList(); } else { _expandedSource.Add(line); _declarations.Push(line); } } else { var macro = _macros[line.Instruction]; if (macro == null) { Assembler.Log.LogEntry(line, ErrorStrings.MissingClosureMacro, line.Instruction); return; } if (IsProcessing()) { _macroDefinitions.Peek().Remove(line); _macroDefinitions.Peek().AddRange(macro.Expand(line).ToList()); } else { _expandedSource = macro.Expand(line).ToList(); } } }
public void Process(SourceLine line) { var instruction = line.Instruction.ToLower(); if (!Processes(line.Instruction)) { if (instruction.Equals(_macros.Last().Key)) { Controller.Log.LogEntry(line, ErrorStrings.RecursiveMacro, line.Instruction); } _macroDefinitions.Peek().Add(line); return; } if (instruction.Equals(".macro") || instruction.Equals(".segment")) { _macroDefinitions.Push(new List <SourceLine>()); string name; _definitions.Push(line); if (instruction.Equals(".segment")) { if (!string.IsNullOrEmpty(line.Label)) { Controller.Log.LogEntry(line, ErrorStrings.None); return; } name = line.Operand; } else { name = line.Label; } if (!Macro.IsValidMacroName(name) || _instructionFcn(name)) { Controller.Log.LogEntry(line, ErrorStrings.LabelNotValid, line.Label); return; } if (_macros.ContainsKey("." + name)) { Controller.Log.LogEntry(line, ErrorStrings.MacroRedefinition, line.Label); return; } _macros.Add("." + name, null); } else if (instruction.Equals(".endmacro") || instruction.Equals(".endsegment")) { var def = instruction.Replace("end", string.Empty); var name = "." + _definitions.Peek().Label; if (!_definitions.Peek().Instruction.Equals(def, Controller.Options.StringComparison)) { Controller.Log.LogEntry(line, ErrorStrings.ClosureDoesNotCloseMacro, line.Instruction); return; } if (def.Equals(".segment")) { name = _definitions.Peek().Operand; if (!name.Equals(line.Operand, Controller.Options.StringComparison)) { Controller.Log.LogEntry(line, ErrorStrings.None); return; } name = "." + name; } _macros[name] = Macro.Create(_definitions.Pop(), line, _macroDefinitions.Pop(), Controller.Options.StringComparison, ConstStrings.OPEN_SCOPE, ConstStrings.CLOSE_SCOPE); } else { var macro = _macros[line.Instruction]; if (macro == null) { Controller.Log.LogEntry(line, ErrorStrings.MissingClosureMacro, line.Instruction); return; } if (IsProcessing()) { _macroDefinitions.Peek().Remove(line); _macroDefinitions.Peek().AddRange(macro.Expand(line).ToList()); } else { _expandedSource = macro.Expand(line).ToList(); } } }
/// <summary> /// Create the specified definition, closure, source, comparer, openBlock and closeBlock. /// </summary> /// <returns>The resulting macro.</returns> /// <param name="definition">Definition.</param> /// <param name="closure">Closure.</param> /// <param name="source">Source.</param> /// <param name="comparer">Comparer.</param> /// <param name="openBlock">Open block.</param> /// <param name="closeBlock">Close block.</param> /// <exception cref="T:System.Exception"></exception> public static Macro Create(SourceLine definition, SourceLine closure, IEnumerable <SourceLine> source, StringComparison comparer, string openBlock, string closeBlock) { var macro = new Macro(); string name = definition.Label; bool isSegment = false; if (definition.Instruction.Equals(".segment", comparer)) { isSegment = true; name = definition.Operand; } macro.IsSegment = isSegment; if (macro.IsSegment == false) { macro.Source.Add(new SourceLine()); macro.Source.First().Filename = definition.Filename; macro.Source.First().LineNumber = definition.LineNumber; macro.Source.First().Instruction = openBlock; if (string.IsNullOrEmpty(definition.Operand) == false) { var parms = definition.Operand.CommaSeparate(); if (parms == null) { Assembler.Log.LogEntry(definition, ErrorStrings.InvalidParameters, definition.Operand); return(macro); } for (int i = 0; i < parms.Count; i++) { var p = parms[i]; var parm = new Macro.Param { Number = i + 1 }; if (p.Contains("=")) { var ps = p.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries); var pname = ps.First().Trim(); if (ps.Count() != 2) { throw new Exception("Default parameter assignment error"); } if (Regex.IsMatch(pname, Patterns.SymbolUnicode) == false) { throw new Exception(string.Format(ErrorStrings.ParameterNameInvalid, pname)); } parm.Name = pname; parm.DefaultValue = ps.Last().Trim(); } else if (Regex.IsMatch(p, Patterns.SymbolUnicode) == false) { throw new Exception(string.Format(ErrorStrings.ParameterNameInvalid, p)); } else { parm.Name = p; parm.DefaultValue = string.Empty; } // check for duplicate param names if (macro.Params.Any(prm => parm.Name.Equals(prm.Name, comparer))) { throw new Exception("Duplicate parameter name found: " + parm.Name); } macro.Params.Add(parm); } } } foreach (var line in source.Where(l => !l.IsComment)) { if (object.ReferenceEquals(definition, line) || object.ReferenceEquals(closure, line)) { continue; } if ((isSegment && line.Instruction.Equals("." + name, comparer)) || line.Instruction.Equals("." + name, comparer)) { throw new Exception(string.Format(ErrorStrings.RecursiveMacro, line.Label)); } macro.Source.Add(line); } if (string.IsNullOrEmpty(closure.Operand) == false) { if (isSegment && !name.Equals(closure.Operand, comparer)) { throw new Exception(string.Format(ErrorStrings.ClosureDoesNotCloseMacro, definition.Instruction, "segment")); } if (!isSegment) { throw new Exception(string.Format(ErrorStrings.DirectiveTakesNoArguments, definition.Instruction)); } } if (macro.IsSegment == false) { macro.Source.Add(new SourceLine { Filename = closure.Filename, LineNumber = closure.LineNumber, Label = closure.Label, Instruction = closeBlock }); } return(macro); }