Beispiel #1
0
 private Listing HandleDirective(string line, bool passTwo = false)
 {
     string directive = line.Substring(1).Trim();
     string[] parameters = new string[0];
     string parameter = "";
     if (directive.SafeContains(' '))
     {
         parameter = directive.Substring(directive.SafeIndexOf(' ') + 1);
         parameters = parameter.SafeSplit(' ');
         directive = directive.Remove(directive.SafeIndexOf(' '));
     }
     directive = directive.ToLower();
     var listing = new Listing
     {
         Code = line,
         CodeType = CodeType.Directive,
         Address = PC,
         Error = AssemblyError.None,
         Warning = AssemblyWarning.None,
         FileName = FileNames.Peek(),
         LineNumber = LineNumbers.Peek(),
         RootLineNumber = RootLineNumber
     };
     try
     {
         switch (directive)
         {
             case "block":
                 {
                     ulong amount = ExpressionEngine.Evaluate(parameter, PC, RootLineNumber);
                     listing.Output = new byte[amount];
                     PC += (uint)amount;
                     return listing;
                 }
             case "byte":
             case "db":
                 {
                     if (passTwo)
                     {
                         var result = new List<byte>();
                         parameters = parameter.SafeSplit(',');
                         foreach (var p in parameters)
                         {
                             if (p.Trim().StartsWith("\"") && p.Trim().EndsWith("\""))
                                 result.AddRange(
                                     Settings.Encoding.GetBytes(p.Trim().Substring(1, p.Trim().Length - 2).Unescape()));
                             else
                             {
                                 try
                                 {
                                     result.Add((byte)ExpressionEngine.Evaluate(p, PC++, RootLineNumber));
                                 }
                                 catch (KeyNotFoundException)
                                 {
                                     listing.Error = AssemblyError.UnknownSymbol;
                                 }
                             }
                         }
                         listing.Output = result.ToArray();
                         return listing;
                     }
                     else
                     {
                         parameters = parameter.SafeSplit(',');
                         int length = 0;
                         foreach (var p in parameters)
                         {
                             if (p.StartsWith("\"") && p.EndsWith("\""))
                                 length += p.Substring(1, p.Length - 2).Unescape().Length;
                             else
                                 length++;
                         }
                         listing.Output = new byte[length];
                         listing.PostponeEvalulation = true;
                         PC += (uint)listing.Output.Length;
                         return listing;
                     }
                 }
             case "word":
             case "dw":
                 {
                     if (passTwo)
                     {
                         var result = new List<byte>();
                         parameters = parameter.SafeSplit(',');
                         foreach (var item in parameters)
                             result.AddRange(TruncateWord(ExpressionEngine.Evaluate(item, PC++, RootLineNumber)));
                         listing.Output = result.ToArray();
                         return listing;
                     }
                     else
                     {
                         listing.Output = new byte[parameters.Length * (InstructionSet.WordSize / 8)];
                         listing.PostponeEvalulation = true;
                         PC += (uint)listing.Output.Length;
                         return listing;
                     }
                 }
             case "error":
             case "echo":
                 {
                     if (passTwo)
                     {
                         string output = "";
                         bool formatOutput = false;
                         List<object> formatParameters = new List<object>();
                         foreach (var item in parameters)
                         {
                             if (item.Trim().StartsWith("\"") && item.EndsWith("\""))
                             {
                                 output += item.Substring(1, item.Length - 2);
                                 formatOutput = true;
                             }
                             else
                             {
                                 if (!formatOutput)
                                     output += ExpressionEngine.Evaluate(item, PC, RootLineNumber);
                                 else
                                 {
                                     formatParameters.Add(ExpressionEngine.Evaluate(item, PC, RootLineNumber));
                                 }
                             }
                         }
                         if (formatOutput)
                             output = string.Format(output, formatParameters.ToArray());
                         Console.WriteLine((directive == "error" ? "User Error: " : "") + output);
                         return listing;
                     }
                     else
                     {
                         listing.PostponeEvalulation = true;
                         return listing;
                     }
                 }
                 break;
             case "end":
                 return listing;
             case "fill":
                 {
                     parameters = parameter.SafeSplit(',');
                     ulong amount = ExpressionEngine.Evaluate(parameters[0], PC, RootLineNumber);
                     if (parameters.Length == 1)
                     {
                         Array.Resize<string>(ref parameters, 2);
                         parameters[1] = "0";
                     }
                     listing.Output = new byte[amount];
                     for (int i = 0; i < (int)amount; i++)
                         listing.Output[i] = (byte)ExpressionEngine.Evaluate(parameters[1], PC++, RootLineNumber);
                     return listing;
                 }
             case "org":
                 PC = (uint)ExpressionEngine.Evaluate(parameter, PC, RootLineNumber);
                 return listing;
             case "include":
                 {
                     string file = GetIncludeFile(parameter);
                     if (file == null)
                     {
                         listing.Error = AssemblyError.FileNotFound;
                         return listing;
                     }
                     FileNames.Push(Path.GetFileName(parameter.Substring(1, parameter.Length - 2)));
                     LineNumbers.Push(0);
                     string includedFile = File.ReadAllText(file) + "\n.endfile";
                     string[] lines = includedFile.Replace("\r", "").Split('\n');
                     Lines =
                         Lines.Take(CurrentIndex + 1)
                              .Concat(lines)
                              .Concat(Lines.Skip(CurrentIndex + 1))
                              .ToArray();
                     return listing;
                 }
             case "endfile": // Special, undocumented directive
                 RootLineNumber--;
                 LineNumbers.Pop();
                 FileNames.Pop();
                 return null;
             case "equ":
                 if (parameters.Length == 1)
                 {
                     if (ExpressionEngine.Symbols.ContainsKey(parameters[0].ToLower()))
                     {
                         listing.Error = AssemblyError.DuplicateName;
                         return listing;
                     }
                     ExpressionEngine.Symbols.Add(parameters[0].ToLower(), new Symbol(1));
                 }
                 else
                 {
                     if (ExpressionEngine.Symbols.ContainsKey(parameters[0].ToLower()))
                     {
                         listing.Error = AssemblyError.DuplicateName;
                         return listing;
                     }
                     ExpressionEngine.Symbols.Add(parameters[0].ToLower(), new Symbol(
                                                                               (uint)
                                                                               ExpressionEngine.Evaluate(
                                                                                   parameter.Substring(
                                                                                       parameter.IndexOf(' ') + 1)
                                                                                            .Trim(), PC,
                                                                                   RootLineNumber)));
                 }
                 return listing;
             case "exec":
                 if (parameters.Length == 0 || !AllowExec)
                 {
                     listing.Error = AssemblyError.InvalidDirective;
                     return listing;
                 }
                 else
                 {
                     var process = new ProcessStartInfo(parameters[0], string.Join(" ", parameters.Skip(1).ToArray()));
                     process.UseShellExecute = false;
                     process.RedirectStandardOutput = true;
                     var p = Process.Start(process);
                     var output = p.StandardOutput.ReadToEnd().Trim('\n', '\r', ' ');
                     p.WaitForExit();
                     listing.Output = Settings.Encoding.GetBytes(output);
                     PC += (uint)listing.Output.Length;
                     return listing;
                 }
             case "define":
                 if (parameters.Length == 1)
                 {
                     if (ExpressionEngine.Symbols.ContainsKey(parameters[0].ToLower()))
                     {
                         listing.Error = AssemblyError.DuplicateName;
                         return listing;
                     }
                     ExpressionEngine.Symbols.Add(parameters[0].ToLower(), new Symbol(1));
                 }
                 else
                 {
                     var macro = new Macro();
                     if (parameter.Contains("("))
                     {
                         var parameterDefinition = parameter.Substring(parameter.SafeIndexOf('(') + 1);
                         parameterDefinition = parameterDefinition.Remove(parameterDefinition.SafeIndexOf(')'));
                         // NOTE: This probably introduces the ability to use ".macro foo(bar)this_doesnt_cause_errors"
                         macro.Parameters = parameterDefinition.SafeSplit(',');
                         for (int i = 0; i < macro.Parameters.Length; i++)
                             macro.Parameters[i] = macro.Parameters[i].Trim();
                         macro.Name = parameter.Remove(parameter.SafeIndexOf('('));
                         macro.Code = parameter.Substring(parameter.SafeIndexOf(')') + 1);
                     }
                     else
                     {
                         macro.Name = parameter.Remove(parameter.SafeIndexOf(' ') + 1);
                         // TODO: Consider enforcing character usage restrictions
                         macro.Code = parameter.Substring(parameter.SafeIndexOf(' ') + 1).Trim();
                     }
                     macro.Name = macro.Name.ToLower().Trim();
                     if (Macros.Any(m => m.Name == macro.Name && m.Parameters.Length == macro.Parameters.Length))
                     {
                         listing.Error = AssemblyError.DuplicateName;
                         return listing;
                     }
                     Macros.Add(macro);
                 }
                 return listing;
             case "if":
                 if (parameters.Length == 0)
                 {
                     listing.Error = AssemblyError.InvalidDirective;
                     return listing;
                 }
                 if (!IfStack.Peek())
                 {
                     WorkingIfStack.Push(false);
                     return listing;
                 }
                 try
                 {
                     IfStack.Push(ExpressionEngine.Evaluate(parameter, PC, RootLineNumber) != 0);
                 }
                 catch (InvalidOperationException)
                 {
                     listing.Error = AssemblyError.InvalidExpression;
                 }
                 catch (KeyNotFoundException)
                 {
                     listing.Error = AssemblyError.UnknownSymbol;
                 }
                 return listing;
             case "ifdef":
                 {
                     if (parameters.Length != 1)
                     {
                         listing.Error = AssemblyError.InvalidDirective;
                         return listing;
                     }
                     if (!IfStack.Peek())
                     {
                         WorkingIfStack.Push(false);
                         return listing;
                     }
                     var result = ExpressionEngine.Symbols.ContainsKey(parameters[0].ToLower());
                     if (!result)
                         result = Macros.Any(m => m.Name.ToLower() == parameters[0].ToLower());
                     IfStack.Push(result);
                     return listing;
                 }
             case "ifndef":
                 {
                     if (parameters.Length != 1)
                     {
                         listing.Error = AssemblyError.InvalidDirective;
                         return listing;
                     }
                     if (!IfStack.Peek())
                     {
                         WorkingIfStack.Push(false);
                         return listing;
                     }
                     var result = ExpressionEngine.Symbols.ContainsKey(parameters[0].ToLower());
                     if (!result)
                         result = Macros.Any(m => m.Name.ToLower() == parameters[0].ToLower());
                     IfStack.Push(!result);
                     return listing;
                 }
             case "endif":
                 if (parameters.Length != 0)
                 {
                     listing.Error = AssemblyError.InvalidDirective;
                     return listing;
                 }
                 if (IfStack.Count == 1)
                 {
                     listing.Error = AssemblyError.UncoupledStatement;
                     return listing;
                 }
                 if (WorkingIfStack.Any())
                 {
                     WorkingIfStack.Pop();
                     return listing;
                 }
                 IfStack.Pop();
                 return listing;
             case "else":
                 if (parameters.Length != 0)
                 {
                     listing.Error = AssemblyError.InvalidDirective;
                     return listing;
                 }
                 if (WorkingIfStack.Any())
                     return listing;
                 IfStack.Push(!IfStack.Pop());
                 return listing;
             //case "elif": // TODO: Requires major logic changes
             //case "elseif":
             //    if (IfStack.Peek())
             //    {
             //        IfStack.Pop();
             //        IfStack.Push(false);
             //        return listing;
             //    }
             //    return listing;
             case "ascii":
                 if (parameters.Length == 0)
                 {
                     listing.Error = AssemblyError.InvalidDirective;
                     return listing;
                 }
                 if (!(parameter.StartsWith("\"") && parameter.EndsWith("\"")))
                 {
                     listing.Error = AssemblyError.InvalidDirective;
                     return listing;
                 }
                 parameter = parameter.Substring(1, parameter.Length - 2);
                 listing.Output = Settings.Encoding.GetBytes(parameter.Unescape());
                 return listing;
             case "asciiz":
                 if (passTwo)
                 {
                     var result = new List<byte>();
                     parameters = parameter.SafeSplit(',');
                     foreach (var p in parameters)
                     {
                         if (p.Trim().StartsWith("\"") && p.Trim().EndsWith("\""))
                             result.AddRange(Settings.Encoding.GetBytes(p.Trim().Substring(1, p.Length - 2).Unescape()));
                         else
                             listing.Error = AssemblyError.InvalidDirective;
                     }
                     listing.Output = new byte[result.Count + 1];
                     Array.Copy(result.ToArray(), listing.Output, result.Count);
                     listing.Output[listing.Output.Length - 1] = 0;
                     return listing;
                 }
                 else
                 {
                     parameters = parameter.SafeSplit(',');
                     int length = 0;
                     foreach (var p in parameters)
                     {
                         if (p.StartsWith("\"") && p.EndsWith("\""))
                             length += p.Substring(1, p.Length - 2).Unescape().Length;
                         else
                             listing.Error = AssemblyError.InvalidDirective;
                     }
                     length++;
                     listing.Output = new byte[length];
                     listing.PostponeEvalulation = true;
                     PC += (uint)listing.Output.Length;
                     return listing;
                 }
                 break;
             case "asciip":
                 if (passTwo)
                 {
                     var result = new List<byte>();
                     parameters = parameter.SafeSplit(',');
                     foreach (var p in parameters)
                     {
                         if (p.Trim().StartsWith("\"") && p.Trim().EndsWith("\""))
                             result.AddRange(Settings.Encoding.GetBytes(p.Trim().Substring(1, p.Length - 2).Unescape()));
                         else
                             listing.Error = AssemblyError.InvalidDirective;
                     }
                     listing.Output = new byte[result.Count + 1];
                     listing.Output[0] = (byte)result.Count;
                     Array.Copy(result.ToArray(), 0, listing.Output, 1, result.Count);
                     return listing;
                 }
                 else
                 {
                     parameters = parameter.SafeSplit(',');
                     int length = 0;
                     foreach (var p in parameters)
                     {
                         if (p.StartsWith("\"") && p.EndsWith("\""))
                             length += p.Substring(1, p.Length - 2).Unescape().Length;
                         else
                             listing.Error = AssemblyError.InvalidDirective;
                     }
                     length++;
                     listing.Output = new byte[length];
                     listing.PostponeEvalulation = true;
                     PC += (uint)listing.Output.Length;
                     return listing;
                 }
                 break;
             case "nolist":
                 Listing = false;
                 return listing;
             case "list":
                 Listing = true;
                 return listing;
             case "undefine":
                 if (parameters.Length == 0)
                 {
                     listing.Error = AssemblyError.InvalidDirective;
                     return listing;
                 }
                 foreach (var item in parameters)
                 {
                     if (Macros.Any(m => m.Name == item.ToLower()))
                         Macros.Remove(Macros.FirstOrDefault(m => m.Name == item));
                     else if (ExpressionEngine.Symbols.ContainsKey(item.ToLower()))
                         ExpressionEngine.Symbols.Remove(item.ToLower());
                     else
                     {
                         listing.Error = AssemblyError.UnknownSymbol;
                         return listing;
                     }
                 }
                 return listing;
         }
     }
     catch (KeyNotFoundException)
     {
         listing.Error = AssemblyError.UnknownSymbol;
         return listing;
     }
     catch (InvalidOperationException)
     {
         listing.Error = AssemblyError.InvalidExpression;
         return listing;
     }
     return null;
 }
Beispiel #2
0
 private Listing HandleDirective(string line, bool passTwo = false)
 {
     string directive = line.Substring(1).Trim();
     string[] parameters = new string[0];
     string parameter = "";
     if (directive.SafeContains(' '))
     {
         parameter = directive.Substring(directive.SafeIndexOf(' ') + 1);
         parameters = parameter.SafeSplit(',');
         directive = directive.Remove(directive.SafeIndexOf(' '));
     }
     var listing = new Listing
     {
         Code = line,
         CodeType = CodeType.Directive,
         Address = PC,
         Error = AssemblyError.None,
         Warning = AssemblyWarning.None,
         FileName = FileNames.Peek(),
         LineNumber = LineNumbers.Peek(),
         RootLineNumber = RootLineNumber
     };
     switch (directive)
     {
         case "block":
         {
             ulong amount = ExpressionEngine.Evaluate(parameter, PC);
             listing.Output = new byte[amount];
             PC += (uint)amount;
             return listing;
         }
         case "byte":
         case "db":
         {
             if (passTwo)
             {
                 var result = new List<byte>();
                 foreach (var item in parameters)
                     result.Add((byte)ExpressionEngine.Evaluate(item, PC++));
                 listing.Output = result.ToArray();
                 return listing;
             }
             else
             {
                 listing.Output = new byte[parameters.Length];
                 listing.PostponeEvalulation = true;
                 PC += (uint)listing.Output.Length;
                 return listing;
             }
         }
         case "word":
         case "dw":
         {
             if (passTwo)
             {
                 var result = new List<byte>();
                 foreach (var item in parameters)
                     result.AddRange(TruncateWord(ExpressionEngine.Evaluate(item, PC++)));
                 listing.Output = result.ToArray();
                 return listing;
             }
             else
             {
                 listing.Output = new byte[parameters.Length * (InstructionSet.WordSize / 8)];
                 listing.PostponeEvalulation = true;
                 PC += (uint)listing.Output.Length;
                 return listing;
             }
         }
         case "error":
         case "echo":
         {
             string output = "";
             foreach (var item in parameters)
             {
                 if (item.Trim().StartsWith("\"") && item.EndsWith("\""))
                     output += item.Substring(1, item.Length - 2);
                 else
                     output += ExpressionEngine.Evaluate(item, PC);
             }
             Console.WriteLine((directive == "error" ? "User Error: " : "") + output);
             return listing;
         }
         case "nolist":
         case "list": // TODO: Do either of these really matter?
         case "end":
             return listing;
         case "fill":
         {
             ulong amount = ExpressionEngine.Evaluate(parameters[0], PC);
             if (parameters.Length == 1)
             {
                 Array.Resize<string>(ref parameters, 2);
                 parameters[1] = "0";
             }
             listing.Output = new byte[amount];
             for (int i = 0; i < (int)amount; i++)
                 listing.Output[i] = (byte)ExpressionEngine.Evaluate(parameters[1], PC++);
             return listing;
         }
         case "option": // TODO: Spasm-style bitmap imports
             return listing;
         case "org":
             PC = (uint)ExpressionEngine.Evaluate(parameter, PC);
             return listing;
         case "include":
             {
                 string file = GetIncludeFile(parameter);
                 if (file == null)
                 {
                     listing.Error = AssemblyError.FileNotFound;
                     return listing;
                 }
                 FileNames.Push(parameter);
                 LineNumbers.Push(0);
                 string includedFile = File.ReadAllText(file) + "\n.endfile";
                 string[] lines = includedFile.Replace("\r", "").Split('\n');
                 Lines = Lines.Take(CurrentIndex + 1).Concat(lines).Concat(Lines.Skip(CurrentIndex + 1)).ToArray();
                 return listing;
             }
         case "endfile": // Special directive
             RootLineNumber--;
             LineNumbers.Pop();
             FileNames.Pop();
             return null;
         case "equ":
         case "define":
             // TODO: Macro
             // TODO: Equates in a different way
             ExpressionEngine.Equates.Add(parameters[0], (uint)ExpressionEngine.Evaluate(parameter.Substring(parameter.IndexOf(',') + 1).Trim(), PC));
             return listing;
     }
     return null;
 }