Exemplo n.º 1
0
        private void ParseDirectives(List <ListEntry> output, string line, bool lineFromMacro)
        {
            string directive = line.Substring(1);

            string[] parameters = directive.Split(' ');
            if (directive.ToLower() == "endif" || directive.ToLower() == "end")
            {
                if (IfStack.Count == 1)
                {
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.UncoupledStatement, lineFromMacro));
                }
                else
                {
                    IfStack.Pop();
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                }
            }
            else if (directive.ToLower().StartsWith("elseif") || directive.ToLower().StartsWith("elif"))
            {
                if (IfStack.Count == 1)
                {
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.UncoupledStatement, lineFromMacro));
                }
                else
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        var result = ParseExpression(line.Substring(line.IndexOf(' ')));
                        if (result.Successful)
                        {
                            if (result.Value > 0)
                            {
                                IfStack.Push(!IfStack.Pop());
                            }
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                        }
                        else
                        {
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                        }
                    }
                }
            }
            else if (directive.ToLower() == "else")
            {
                if (IfStack.Count == 1)
                {
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.UncoupledStatement, lineFromMacro));
                }
                else
                {
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                    IfStack.Push(!IfStack.Pop());
                }
            }
            else if (IfStack.Peek())
            {
                if (directive.ToLower() == "region" || directive.ToLower() == "endregion")
                {
                }                                                                              // Allowed but ignored
                else if (directive.ToLower() == "nolist")
                {
                    noList = true;
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro));
                }
                else if (directive.ToLower() == "list")
                {
                    noList = false;
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro));
                }
                else if ((directive.ToLower().StartsWith("dat ") || directive.ToLower().StartsWith("dw ")))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        string[]      dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(',');
                        List <ushort> binOutput   = new List <ushort>();
                        Dictionary <ushort, string> postponedExpressions = new Dictionary <ushort, string>();
                        foreach (string data in dataStrings)
                        {
                            if (data.Trim().StartsWith("\""))
                            {
                                if (!data.Trim().EndsWith("\""))
                                {
                                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                                }
                                else
                                {
                                    string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape();
                                    foreach (byte b in Encoding.ASCII.GetBytes(str))
                                    {
                                        binOutput.Add(b);
                                    }
                                }
                            }
                            else
                            {
                                postponedExpressions.Add((ushort)binOutput.Count, data.Trim());
                                binOutput.Add(0);
                            }
                        }
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList));
                        output[output.Count - 1].PostponedExpressions = postponedExpressions;
                        if (!noList)
                        {
                            currentAddress += (ushort)binOutput.Count;
                        }
                    }
                }
                else if (directive.ToLower().StartsWith("scope"))
                {
                    if (parameters.Length < 2)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else if (parameters.Length > 2)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro));
                    }
                    else
                    {
                        PriorGlobalLabel = parameters[1];
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro));
                    }
                }
                else if (directive.ToLower() == "uniquescope")
                {
                    PriorGlobalLabel = "_unique" + UniqueScopeNumber++;
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro));
                }
                else if (directive.ToLower().StartsWith("echo"))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        string[] dataStrings   = directive.Substring(directive.IndexOf(" ")).SafeSplit(',');
                        string   consoleOutput = "";
                        foreach (string data in dataStrings)
                        {
                            if (data.Trim().StartsWith("\""))
                            {
                                if (!data.Trim().EndsWith("\""))
                                {
                                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                                }
                                else
                                {
                                    string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape();
                                    consoleOutput += str;
                                }
                            }
                            else
                            {
                                ExpressionResult value = ParseExpression(data.Trim());
                                if (!value.Successful)
                                {
                                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                                }
                                else
                                {
                                    consoleOutput += value.Value;
                                }
                            }
                        }
                        Console.Write(consoleOutput + "\n");
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro));
                        output.Add(new ListEntry(consoleOutput, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro));
                    }
                }
                else if (directive.ToLower().StartsWith("ref"))
                {
                    ReferencedValues.Add(directive.Substring(directive.IndexOf(" ") + 1));
                }
                else if (directive.ToLower().StartsWith("asciip"))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        string[]      dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(',');
                        List <ushort> binOutput   = new List <ushort>();
                        foreach (string data in dataStrings)
                        {
                            if (data.Trim().StartsWith("\""))
                            {
                                if (!data.Trim().EndsWith("\""))
                                {
                                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                                }
                                else
                                {
                                    string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape();
                                    binOutput.Add((ushort)str.Length);
                                    foreach (byte b in Encoding.ASCII.GetBytes(str))
                                    {
                                        binOutput.Add(b);
                                    }
                                }
                            }
                            else
                            {
                                output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                            }
                        }
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList));
                        if (!noList)
                        {
                            currentAddress += (ushort)binOutput.Count;
                        }
                    }
                }
                else if (directive.ToLower().StartsWith("asciic") || directive.ToLower().StartsWith("asciiz"))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        string[]      dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(',');
                        List <ushort> binOutput   = new List <ushort>();
                        foreach (string data in dataStrings)
                        {
                            if (data.Trim().StartsWith("\""))
                            {
                                if (!data.Trim().EndsWith("\""))
                                {
                                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                                }
                                else
                                {
                                    string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape();
                                    foreach (byte b in Encoding.ASCII.GetBytes(str))
                                    {
                                        binOutput.Add(b);
                                    }
                                    binOutput.Add(0);
                                }
                            }
                            else
                            {
                                output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                            }
                        }
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList));
                        if (!noList)
                        {
                            currentAddress += (ushort)binOutput.Count;
                        }
                    }
                }
                else if (directive.ToLower().StartsWith("ascii"))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        string[]      dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(',');
                        List <ushort> binOutput   = new List <ushort>();
                        foreach (string data in dataStrings)
                        {
                            if (data.Trim().StartsWith("\""))
                            {
                                if (!data.Trim().EndsWith("\""))
                                {
                                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                                }
                                else
                                {
                                    string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape();
                                    foreach (byte b in Encoding.ASCII.GetBytes(str))
                                    {
                                        binOutput.Add(b);
                                    }
                                }
                            }
                            else
                            {
                                output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                            }
                        }
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList));
                        if (!noList)
                        {
                            currentAddress += (ushort)binOutput.Count;
                        }
                    }
                }
                else if (directive.ToLower() == "longform") // Handled properly in the second pass
                {
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                }
                else if (directive.ToLower() == "shortform")
                {
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                }
                else if (directive.ToLower().StartsWith("org"))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else if (parameters.Length > 2)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro));
                    }
                    else
                    {
                        ExpressionResult value = ParseExpression(parameters[1]);
                        if (value == null)
                        {
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                        }
                        else
                        {
                            currentAddress = value.Value;
                            var entry = new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList);
                            entry.RootLineNumber = RootLineNumber;
                            output.Add(entry);
                        }
                    }
                }
                else if (directive.ToLower().StartsWith("ifdef"))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else if (parameters.Length > 2)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro));
                    }
                    else
                    {
                        if (Values.ContainsKey(parameters[1].ToLower()))
                        {
                            IfStack.Push(true);
                        }
                        else
                        {
                            IfStack.Push(false);
                        }
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                    }
                }
                else if (directive.ToLower().StartsWith("ifndef"))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else if (parameters.Length > 2)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro));
                    }
                    else
                    {
                        if (Values.ContainsKey(parameters[1].ToLower()))
                        {
                            IfStack.Push(false);
                        }
                        else
                        {
                            IfStack.Push(true);
                        }
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                    }
                }
                else if (directive.ToLower().StartsWith("if"))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        var result = ParseExpression(line.Substring(3));
                        if (result.Successful)
                        {
                            if (result.Value > 0)
                            {
                                IfStack.Push(true);
                            }
                            else
                            {
                                IfStack.Push(false);
                            }
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                        }
                        else
                        {
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                        }
                    }
                }
                else if (directive.ToLower().StartsWith("equ") || directive.ToLower().StartsWith("define") || directive.ToLower().StartsWith("equate"))
                {
                    if (parameters.Length > 1)
                    {
                        if (Values.ContainsKey(parameters[1]))
                        {
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.DuplicateName, lineFromMacro));
                        }
                        else
                        {
                            if (parameters.Length == 2)
                            {
                                Values.Add(parameters[1], 1);
                                output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                            }
                            else if (parameters.Length > 2)
                            {
                                string expression = directive.TrimExcessWhitespace();
                                expression = expression.Substring(expression.IndexOf(' ') + 1);
                                expression = expression.Substring(expression.IndexOf(' ') + 1);
                                ExpressionResult value = ParseExpression(expression); // TODO: find a way to forward reference
                                if (value != null)
                                {
                                    Values.Add(parameters[1], value.Value);
                                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList));
                                }
                                else
                                {
                                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                                }
                            }
                            else
                            {
                                output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                            }
                        }
                    }
                }
                else if (directive.ToLower().StartsWith("pad") || directive.ToLower().StartsWith("fill")) // .pad length, value
                {
                    parameters = line.SafeSplit(',', ' ');
                    string[] fixedParams = new string[0];
                    foreach (string parameter in parameters)
                    {
                        if (!string.IsNullOrEmpty(parameter))
                        {
                            fixedParams = fixedParams.Concat(new string[] { parameter }).ToArray();
                        }
                    }
                    parameters = fixedParams;
                    if (parameters.Length == 3)
                    {
                        var length = ParseExpression(parameters[1]);
                        var value  = ParseExpression(parameters[2]);
                        if (!length.Successful)
                        {
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                        }
                        else
                        {
                            ushort[] padding = new ushort[length.Value];
                            Dictionary <ushort, string> postponed = new Dictionary <ushort, string>();
                            for (int i = 0; i < padding.Length; i++)
                            {
                                padding[i] = value.Value;
                                if (!value.Successful)
                                {
                                    postponed.Add((ushort)i, parameters[2]);
                                }
                            }
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), padding, currentAddress, !noList));
                            output[output.Count - 1].PostponedExpressions = postponed;
                            if (!noList)
                            {
                                currentAddress += (ushort)padding.Length;
                            }
                        }
                    }
                    else if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro));
                    }
                }
                else if (directive.ToLower().StartsWith("reserve"))
                {
                    if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        var expression = directive.Substring(7).Trim();
                        var result     = ParseExpression(expression);
                        if (result.Successful)
                        {
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), new ushort[result.Value], currentAddress, !noList));
                            currentAddress += result.Value;
                        }
                        else
                        {
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                        }
                    }
                }
                else if (directive.ToLower().StartsWith("align")) // .align addr
                {
                    if (parameters.Length == 2)
                    {
                        var addr = ParseExpression(parameters[1]);
                        if (!addr.Successful)
                        {
                            output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro));
                        }
                        else
                        {
                            if (currentAddress > addr.Value)
                            {
                                output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.AlignToPast, lineFromMacro));
                            }
                            else
                            {
                                var      amount  = (ushort)(addr.Value - currentAddress);
                                ushort[] padding = new ushort[amount];
                                output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), padding, currentAddress, !noList));
                                if (!noList)
                                {
                                    currentAddress = addr.Value;
                                }
                            }
                        }
                    }
                    else if (parameters.Length == 1)
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro));
                    }
                    else
                    {
                        output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro));
                    }
                }
                else if (directive == "relocate")
                {
                    OldAddress     = currentAddress;
                    currentAddress = 0;
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro));
                    output[output.Count - 1].CodeType = CodeType.RelocationTable;
                    RelocationGroup++;
                    IsRelocating = true;
                }
                else if (directive == "endrelocate")
                {
                    // TODO: Errors
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro));
                    currentAddress = OldAddress;
                    IsRelocating   = false;
                }
                else
                {
                    output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InvalidDirective, lineFromMacro));
                }
            }
            output[output.Count - 1].CodeType = CodeType.Directive;
        }