예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
        }