Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class Compiler
- {
- public Compiler(IEnumerable<CommandSignature> insn, IEnumerable<Directive> dir)
- {
- commands = new List<CommandSignature>(insn);
- directives = new List<Directive>(dir);
- }
- List<CommandSignature> commands;
- List<Directive> directives;
- public byte[] Compile(string src)
- {
- src = Format(src);
- // Split into readable components
- string[] lines = source.Split('\n');
- string[][] parts = new string[lines.Length][];
- for (int i = 0; i < lines.Length; i++)
- parts[i] = lines[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
- foreach (Directive dir in directives)
- dir.Preprocess(parts);
- using (BinaryWriter bytecode = new BinaryWriter(new MemoryStream()))
- {
- for (int l = 0; l < parts.Length; l++)
- {
- // Skip empty lines
- if (string.IsNullOrEmpty(lines[l]))
- continue;
- // Execute directives:
- if (directives.Contains(dir => dir.Name == parts[l][0]))
- {
- dir = directives.First(dir => dir.Name == parts[l][0]);
- dir.Execute(parts[l].Skip(1).ToArray(), bytecode);
- } // Compile commands:
- else if (commands.Contains(sig => (sig.Name == parts[l][0]) && (sig.ParameterTypes.Length == parts[l].Length - 1)))
- {
- CommandSignature cmd = commands.First(sig => (sig.Name == parts[l][0]) && (sig.ParameterTypse.Length == parts[l].Length - 1));
- bytecode.Write(cmd.ID);
- for (int p = 0; p < cmd.ParameterTypes.Length; p++)
- {
- // Compile numeric arguments
- if (Regex.IsMatch(parts[l][p + 1], "^\d+$"))
- {
- int val = Convert.ToInt32(parts[l][p + 1]);
- for (int b = 0; b < cmd.ParameterTypes[p]; b++)
- {
- bytecode.Write((byte)val);
- val >>= 8;
- }
- } // Resolve non-numeric arguments
- else if (directives.Contains(d => d.CanCompileValue(parts[l][p + 1])))
- {
- Directive dir = directives.First(d => d.CanCompileValue(parts[l][p + 1]));
- dir.CompileValue(parts[l][p + 1], cmd.ParameterTypes[p], bytecode);
- } // Could not resolve
- else
- {
- Console.WriteLine("Error in line {0}: Cannot compile argument '{1}'.", l + 1, parts[l][p + 1]);
- }
- }
- } // No matching command signature
- else
- {
- if (commands.Contains(sig => sig.Name == parts[l][0]))
- Console.WriteLine("Error in line {0}: Command '{1}' does not accept {2} arguments.", l + 1, parts[l][0], parts[l].Length - 1);
- else
- Console.WriteLine("Error in line {0}: Command '{1}' does not exist.", l + 1, parts[l][0]);
- }
- }
- foreach (Directive dir in directives)
- dir.Postprocess(bytecode);
- return (bytecode.BaseStream as MemoryStream).ToArray();
- }
- }
- private string Format(string src)
- {
- src = Regex.Replace(src, "\t", " "); // Remove tabs
- src = Regex.Replace(src, "\r\n?", "\n"); // Assimilate line breaks
- // Remove comments:
- src = Regex.Replace(src, @"\/\/.*", string.Empty);
- src = Regex.Replace(src, @"\/\*.*\*\/", " ");
- MatchCollection blockComments = Regex.Matches(src, @"^\/\*[.\n]*\*\/$");
- foreach (Match comment in blockComments)
- {
- // Get all line breaks by replacing all non-linebreaks with nothing:
- string breaks = Regex.Replace(comment.Value, ".", string.Empty);
- src = src.Replace(comment.Value, breaks);
- }
- // Remove extra spaces so no attempt is made at compiling " " or similar:
- while (src.Contains(" "));
- src = src.Replace(" ", " ");
- return src;
- }
- }
- public class CommandSignature
- {
- public CommandSignature(string name, byte id, params byte[] args)
- {
- this.Name = name;
- this.ID = id;
- this.ParameterTypes = (args == null) ? new byte[0] : args;
- }
- public string Name { get; private set; }
- public byte ID { get; private set; }
- public byte[] ParameterTypes { get; private set; }
- }
- public abstract class Directive
- {
- public Directive(string name, int paramCount)
- {
- this.Name = name;
- this.Parameters = paramCount;
- }
- public string Name { get; private set; }
- public int Parameters { get; private set; }
- public virtual void Preprocess(string[][] source) { }
- public virtual void Execute(string[] args, BinaryWriter bytecode) { }
- public virtual void Postprocess(BinaryWriter bytecode) { }
- public virtual bool CanCompileValue(string val) { return false; }
- public virtual void CompileValue(string val, int argLength, BinaryWriter bytecode) { }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement