Advertisement
Guest User

compiler

a guest
Oct 30th, 2014
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.40 KB | None | 0 0
  1. public class Compiler
  2. {
  3.     public Compiler(IEnumerable<CommandSignature> insn, IEnumerable<Directive> dir)
  4.     {
  5.         commands = new List<CommandSignature>(insn);
  6.         directives = new List<Directive>(dir);
  7.     }
  8.    
  9.     List<CommandSignature> commands;
  10.     List<Directive> directives;
  11.    
  12.     public byte[] Compile(string src)
  13.     {
  14.         src = Format(src);
  15.    
  16.         // Split into readable components
  17.         string[] lines = source.Split('\n');
  18.         string[][] parts = new string[lines.Length][];
  19.         for (int i = 0; i < lines.Length; i++)
  20.             parts[i] = lines[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  21.    
  22.         foreach (Directive dir in directives)
  23.             dir.Preprocess(parts);
  24.    
  25.         using (BinaryWriter bytecode = new BinaryWriter(new MemoryStream()))
  26.         {
  27.             for (int l = 0; l < parts.Length; l++)
  28.             {
  29.                 // Skip empty lines
  30.                 if (string.IsNullOrEmpty(lines[l]))
  31.                     continue;
  32.                
  33.                 // Execute directives:
  34.                 if (directives.Contains(dir => dir.Name == parts[l][0]))
  35.                 {
  36.                     dir = directives.First(dir => dir.Name == parts[l][0]);
  37.                     dir.Execute(parts[l].Skip(1).ToArray(), bytecode);
  38.                 }   // Compile commands:
  39.                 else if (commands.Contains(sig => (sig.Name == parts[l][0]) && (sig.ParameterTypes.Length == parts[l].Length - 1)))
  40.                 {
  41.                     CommandSignature cmd = commands.First(sig => (sig.Name == parts[l][0]) && (sig.ParameterTypse.Length == parts[l].Length - 1));
  42.                     bytecode.Write(cmd.ID);
  43.                    
  44.                     for (int p = 0; p < cmd.ParameterTypes.Length; p++)
  45.                     {
  46.                         // Compile numeric arguments
  47.                         if (Regex.IsMatch(parts[l][p + 1], "^\d+$"))
  48.                         {
  49.                             int val = Convert.ToInt32(parts[l][p + 1]);
  50.                            
  51.                             for (int b = 0; b < cmd.ParameterTypes[p]; b++)
  52.                             {
  53.                                 bytecode.Write((byte)val);
  54.                                 val >>= 8;
  55.                             }
  56.                         }   // Resolve non-numeric arguments
  57.                         else if (directives.Contains(d => d.CanCompileValue(parts[l][p + 1])))
  58.                         {
  59.                             Directive dir = directives.First(d => d.CanCompileValue(parts[l][p + 1]));
  60.                             dir.CompileValue(parts[l][p + 1], cmd.ParameterTypes[p], bytecode);
  61.                         }   // Could not resolve
  62.                         else
  63.                         {
  64.                             Console.WriteLine("Error in line {0}: Cannot compile argument '{1}'.", l + 1, parts[l][p + 1]);
  65.                         }
  66.                     }
  67.                 }   // No matching command signature
  68.                 else
  69.                 {
  70.                     if (commands.Contains(sig => sig.Name == parts[l][0]))
  71.                         Console.WriteLine("Error in line {0}: Command '{1}' does not accept {2} arguments.", l + 1, parts[l][0], parts[l].Length - 1);
  72.                     else
  73.                         Console.WriteLine("Error in line {0}: Command '{1}' does not exist.", l + 1, parts[l][0]);
  74.                 }
  75.             }
  76.        
  77.             foreach (Directive dir in directives)
  78.                 dir.Postprocess(bytecode);
  79.        
  80.             return (bytecode.BaseStream as MemoryStream).ToArray();
  81.         }
  82.     }
  83.    
  84.     private string Format(string src)
  85.     {
  86.         src = Regex.Replace(src, "\t", " ");        // Remove tabs
  87.         src = Regex.Replace(src, "\r\n?", "\n");    // Assimilate line breaks
  88.        
  89.         // Remove comments:
  90.         src = Regex.Replace(src, @"\/\/.*", string.Empty);
  91.         src = Regex.Replace(src, @"\/\*.*\*\/", " ");
  92.        
  93.         MatchCollection blockComments = Regex.Matches(src, @"^\/\*[.\n]*\*\/$");
  94.         foreach (Match comment in blockComments)
  95.         {
  96.             // Get all line breaks by replacing all non-linebreaks with nothing:
  97.             string breaks = Regex.Replace(comment.Value, ".", string.Empty);
  98.             src = src.Replace(comment.Value, breaks);
  99.         }
  100.        
  101.         // Remove extra spaces so no attempt is made at compiling "   " or similar:
  102.         while (src.Contains("  "));
  103.             src = src.Replace("  ", " ");
  104.        
  105.         return src;
  106.     }
  107. }
  108.  
  109. public class CommandSignature
  110. {
  111.     public CommandSignature(string name, byte id, params byte[] args)
  112.     {
  113.         this.Name = name;
  114.         this.ID = id;
  115.         this.ParameterTypes = (args == null) ? new byte[0] : args;
  116.     }
  117.  
  118.     public string Name { get; private set; }
  119.     public byte ID { get; private set; }
  120.     public byte[] ParameterTypes { get; private set; }
  121. }
  122.  
  123. public abstract class Directive
  124. {
  125.     public Directive(string name, int paramCount)
  126.     {
  127.         this.Name = name;
  128.         this.Parameters = paramCount;
  129.     }
  130.    
  131.     public string Name { get; private set; }
  132.     public int Parameters { get; private set; }
  133.  
  134.     public virtual void Preprocess(string[][] source) { }
  135.     public virtual void Execute(string[] args, BinaryWriter bytecode) { }
  136.     public virtual void Postprocess(BinaryWriter bytecode) { }
  137.  
  138.     public virtual bool CanCompileValue(string val) { return false; }
  139.     public virtual void CompileValue(string val, int argLength, BinaryWriter bytecode) { }
  140. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement