/// <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); }
/// <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); }