Beispiel #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);
        }
Beispiel #2
0
        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();
                }
            }
        }
Beispiel #4
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);
        }