public void Assemble(IPositionableInputStream input, BinaryWriter output, ILog log)
        {
            ((Printer)buildInCodes[messagePrinterCode]).PrinterAction = log.AddMessage;
            ((Printer)buildInCodes[errorPrinterCode]).PrinterAction = log.AddError;
            ((Printer)buildInCodes[warningPrinterCode]).PrinterAction = log.AddWarning;

            Context assemblyContext = new Context();
            assemblyContext.AddNewScope();
            var codes = new List<KeyValuePair<INamed<string>, string[]>>(FirstPass(input, assemblyContext, log));

            assemblyContext.Offset = 0;
            SecondPass(codes, assemblyContext, log, output);
        }
        private static void SecondPass(IEnumerable<KeyValuePair<INamed<string>, string[]>> codes, 
            Context assemblyContext, ILog log, BinaryWriter output)
        {
            foreach (var code in codes)
            {
                //Insert labels and currentOffsetCode
                for (int i = 1; i < code.Value.Length; i++)
                {
                    int offset;
                    if (code.Value[i].Equals(currentOffsetCode, StringComparison.OrdinalIgnoreCase))
                    {
                        code.Value[i] = assemblyContext.Offset.ToString();
                    }
                    else if (assemblyContext.TryGetLabelOffset(code.Value[i], out offset))
                    {
                        code.Value[i] = offset.ToString();
                    }
                }

                if (code.Key is IBuiltInCode)
                {
                    var error = ((IBuiltInCode)code.Key).SecondPass(code.Value, assemblyContext);
                    if (error)
                    {
                        log.AddError(error.ErrorMessage);
                    }
                    else if (error.Result)
                    {
                        output.Seek(assemblyContext.Offset, SeekOrigin.Begin);
                    }
                }
                else if (code.Key is ICodeTemplate)
                {
                    output.Write(((ICodeTemplate)code.Key).GetData(code.Value, log));
                    assemblyContext.Offset = (int)output.BaseStream.Position;
                }
            }
        }
 private string[] HandleLabels(IPositionableInputStream input, Context assemblyContext, ILog log, string[] code)
 {
     string labelName = code[0].TrimEnd(':');
     if (IsValidLableName(labelName))
     {
         assemblyContext.AddLabel(labelName);
     }
     else
     {
         log.AddError(input.GetErrorString(
             string.Format("Invalid label name {0}", labelName)));
     }
     string[] temp = new string[code.Length - 1];
     Array.Copy(code, 1, temp, 0, temp.Length);
     code = temp;
     return code;
 }
        private IEnumerable<KeyValuePair<INamed<string>, string[]>> FirstPass(IPositionableInputStream input, 
            Context assemblyContext, ILog log)
        {
            while (true)
            {
                string line = input.ReadLine();
                if (line == null)
                    break;

                string[] code = Nintenlord.Utility.Parser.SplitToParameters(line);

                if (code.Length > 0)
                {
                    if (code[0].EndsWith(":"))
                    {
                        code = HandleLabels(input, assemblyContext, log, code);
                    }

                    if (code.Length == 0) continue;

                    IBuiltInCode builtIn;
                    if (buildInCodes.TryGetValue(code[0], out builtIn))
                    {
                        string error;
                        if (builtIn.Matches("Code " + code[0], code.Length - 1, out error))
                        {
                            var causedError = builtIn.FirstPass(code, assemblyContext);
                            if (causedError)
                            {
                                log.AddError(input.GetErrorString(causedError.ErrorMessage));
                            }
                            yield return new KeyValuePair<INamed<string>, string[]>(builtIn, code);
                        }
                        else
                        {
                            log.AddError(input.GetErrorString(error));
                        }
                    }
                    else
                    {
                        ICodeTemplate template = codeStorage.FindTemplate(code);

                        if (template != null)
                        {
                            if (assemblyContext.Offset % template.OffsetMod != 0)
                            {
                                log.AddError(input.GetErrorString(
                                    string.Format(
                                    "Code {0}'s offset {1} is not divisible by {2}",
                                    template.Name,
                                    assemblyContext.Offset,
                                    template.OffsetMod
                                    )));
                            }
                            assemblyContext.Offset += template.GetLengthBytes(code);
                            yield return new KeyValuePair<INamed<string>, string[]>(template, code);
                        }
                        else
                        {
                            log.AddError(input.GetErrorString(string.Format(
                                    "No code named {0} with {1} parameters found",
                                    code[0],
                                    code.Length - 1
                                    )));
                        }
                    }
                }
            }
        }