public static int ParseParameter(Command.ParameterType t, PreParsedLine l, out ParsedType foundType, Dictionary <string, Alias> aliases, Dictionary <string, int> labels = null)
        {
            int x = 0;

            foundType = ParsedType.Constant;
            switch (t)
            {
            case Command.ParameterType.Label:
                if (labels != null && !labels.TryGetValue(l.Parameter.Value, out x))
                {
                    throw new ArgumentException("Unable to find label '" + l.Parameter + "' of line '" + l.InputLine + "'");
                }
                foundType = ParsedType.Label;
                break;

            case Command.ParameterType.Constant:
                if (!int.TryParse(l.Parameter.Value, out x))
                {
                    throw new ArgumentException("Unable to parse parameter '" + l.Parameter + "' of line '" + l.InputLine + "'");
                }
                break;

            case Command.ParameterType.StackDelta:
                x         = ParseNonNegative(l);
                foundType = ParsedType.StackDelta;
                break;

            case Command.ParameterType.StackAddress:
                x         = ParseNonNegative(l);
                foundType = ParsedType.Address;
                break;

            case Command.ParameterType.Address:
                foundType = ParsedType.Address;
                if (!int.TryParse(l.Parameter.Value, out x))
                {
                    Alias alias;
                    if (aliases.TryGetValue(l.Parameter.Value, out alias))
                    {
                        x         = alias.Address;
                        foundType = ParsedType.Alias;
                    }
                    else
                    {
                        throw new ArgumentException("Unable to parse address parameter '" + l.Parameter + "' of line '" + l.InputLine + "'. Parameter is no valid integer, or known alias");
                    }
                }
                if (x < 0 || x >= State.MemorySize)
                {
                    throw new ArgumentException("Address parameter '" + l.Parameter + "' of line '" + l.InputLine + "' exceeds valid address range");
                }
                break;
            }
            return(x);
        }
        private static int ParseNonNegative(PreParsedLine l)
        {
            int x = 0;

            if (!int.TryParse(l.Parameter.Value, out x))
            {
                throw new ArgumentException("Unable to parse parameter '" + l.Parameter + "' of line '" + l.InputLine + "'");
            }
            if (x < 0)
            {
                throw new ArgumentException("Parameter '" + l.Parameter + "' of line '" + l.InputLine + "' must not be negative");
            }
            if (x >= State.MemorySize)
            {
                throw new ArgumentException("Parameter '" + l.Parameter + "' of line '" + l.InputLine + "' must be less than the address space size " + State.MemorySize);
            }

            return(x);
        }
        public static Instruction[] Parse(IEnumerable <string> lines)
        {
            int lineIndex    = 0;
            var labels       = new Dictionary <string, int>();
            var instructions = new List <Instruction>();

            lineIndex = 0;
            int commandCounter = 0;

            Dictionary <string, Alias> aliases = new Dictionary <string, Alias>();

            foreach (var line in lines)
            {
                lineIndex++;
                try
                {
                    var l = new PreParsedLine(line);
                    if (l.Label.HasValue)
                    {
                        if (labels.ContainsKey(l.Label.Value))
                        {
                            throw new ArgumentException("Label '" + l.Label.Value + "' re-defined. Was originally defined at command #" + labels[l.Label.Value]);
                        }
                        labels.Add(l.Label.Value, commandCounter);
                    }
                    if (l.IsAlias)
                    {
                        var alias = l.ToAlias();
                        if (aliases.ContainsKey(alias.Name))
                        {
                            throw new ArgumentException("Alias '" + alias.Name + "' already defined");
                        }
                        aliases.Add(alias.Name, alias);

                        if (l.IntAliasValue.HasValue)
                        {
                            commandCounter++;                                   //set
                        }
                    }

                    if (l.IsCommand)
                    {
                        commandCounter++;
                    }
                }
                catch (Exception ex)
                {
                    throw new CommandException(ex, line, lineIndex);
                }
            }

            foreach (var alias in aliases.Values)
            {
                if (alias.InitialValue.HasValue)
                {
                    instructions.Add(new Instruction(s => { s.m[alias.Address] = alias.InitialValue.Value; s.LogM(alias.Address); }, alias.ToString()));
                }
            }

            lineIndex = 0;
            foreach (var line in lines)
            {
                lineIndex++;
                var l = new PreParsedLine(line);
                if (!l.IsCommand)
                {
                    continue;
                }

                Action <State> action   = null;
                string         lineText = "";

                Language.Command command;
                try
                {
                    command = Language.FindCommand(l.Command.Value, l.Parameter != null);
                }
                catch (Exception ex)
                {
                    throw new CommandException(ex, line, lineIndex);
                }
                if (l.Label != null)
                {
                    lineText = l.Label + "(=" + instructions.Count + "): ";
                }
                else
                {
                    lineText = "(" + instructions.Count + "): ";
                }



                if (command.RequiresParameter)
                {
                    ParsedType ignore;
                    int        x = ParseParameter(command.Parameter, l, out ignore, aliases, labels);
                    action    = (s) => command.Action(s, x);
                    lineText += command.Name + " " +
                                "" + l.Parameter;
                }
                else
                {
                    action    = (s) => command.Action(s, 0);
                    lineText += command.Name;
                }
                instructions.Add(new Instruction(action, lineText));
            }
            return(instructions.ToArray());
        }