Exemplo n.º 1
0
        public void WordWrap(string outputAinFilename)
        {
            var options       = new CodeDisplayOptions();
            var projectWriter = new AssemblerProjectWriter(ainFile, options);

            projectWriter.BeforeWritingInstruction += new EventHandler <InstructionInfoEventArgs>(projectWriter_BeforeWritingInstruction);


            string tempFile = Path.GetTempFileName();

            try
            {
                var saveProjectInBackground = new ExplorerForm.SaveProjectInBackground();
                saveProjectInBackground.SaveAsProject(projectWriter, tempFile, true);

                var buildProjectInBackground = new ExplorerForm.BuildProjectInBackground();
                buildProjectInBackground.Run(tempFile, outputAinFilename, true);

                //projectWriter.SaveAsProject(tempFile, true);
                //var projectReader = new AssemblerProjectReader();
                //projectReader.LoadProject(tempFile);
                //var outputAinFile = projectReader.MakeAinFile();
                //outputAinFile.WriteAndEncryptAinFile(outputAinFilename);
            }
            finally
            {
                File.Delete(tempFile);
            }
        }
Exemplo n.º 2
0
        //private List<object> GetFunctionsToOutput(List<TokenExpression> tokens)
        //{
        //    List<object> FunctionsToOutput = new List<object>();
        //    bool hasOutputZero = false;
        //    foreach (var function in ainFile.Functions)
        //    {
        //        if (function.Name == "NULL")
        //        {

        //        }
        //        else if (function.Name.EndsWith("@2"))
        //        {
        //            if (!hasOutputZero)
        //            {
        //                FunctionsToOutput.Add(ainFile.GetFunction("0"));
        //                hasOutputZero = true;
        //            }
        //            FunctionsToOutput.Add(function);
        //        }
        //        else if (function.Name == "0")
        //        {

        //        }
        //        else
        //        {
        //            FunctionsToOutput.Add(function);
        //        }
        //    }
        //    FunctionsToOutput.Add(ainFile.GetFunction("NULL"));

        //    return FunctionsToOutput;
        //}

        public void Test()
        {
            //List<TokenExpression> tokens = new List<TokenExpression>();
            ////string expression = "a - -obj.method()()[4] - -3;";
            ////string expression = "- -a - -obj.method()()[4] - -3;";
            ////string expression = "- -a - -obj.method()(-9*-8 + 5)[4 == 4 + 5 == 4] - -3;";
            ////string expression = "- -a - -obj.method()(-9*-8 + 5)[4 == 4 + 5 == 4] - -3;";
            //IncludeString(expression, tokens);
            //this.reader = new TokenReader(tokens);
            //var exp = ReadExpression();

            string projectFilename = @"<insert filename here>";

            Compile(projectFilename);

            string outputJamFileName = Path.Combine(Path.GetDirectoryName(projectFilename), "output\\main.jam");

            //string outputJamFileName = Path.Combine(Path.GetDirectoryName(projectFilename), "..\\DISASSEMBLED2\\main.jam");

            //string filename = @"<insert filename here>";
            //List<TokenExpression> tokens = new List<TokenExpression>();
            //IncludeFile(filename, tokens);

            //string libraryPath = @"<insert filename here>";
            //LoadHllFiles(libraryPath);

            ainFile.LoadAlternativeNames();
            ainFile.LoadMetadata();
            AssemblerProjectWriter writer = new AssemblerProjectWriter(ainFile);

            writer.Options.ShowGlobalPrefix = false;
            writer.SaveAsProject(outputJamFileName, false);

            //todo: fix _date_ macro, needs spaces instead of leading zeroes
        }
Exemplo n.º 3
0
 public override string ToString()
 {
     if (QuoteCharacter != 0)
     {
         return(AssemblerProjectWriter.EscapeString(Value, QuoteCharacter, true));
     }
     return(Value);
 }
Exemplo n.º 4
0
        public void CompileCodeInPlace(string[] fileNames)
        {
            StringBuilder sb = new StringBuilder();

            foreach (var fileName in fileNames)
            {
                sb.AppendLine("#include " + AssemblerProjectWriter.EscapeAndQuoteString(Path.GetFullPath(fileName)));
            }
            CompileCodeInPlace(sb.ToString());
        }
Exemplo n.º 5
0
        private static void CreateProject(string inputAinFilename, string outputProjectFilename)
        {
            var ainFile = new AinFile(inputAinFilename);

            ainFile.LoadAlternativeNames();
            //var alternativeNames = new AlternativeNames(inputAinFilename);
            var writer = new AssemblerProjectWriter(ainFile);

            //writer.AlternativeNames = alternativeNames;
            writer.SaveAsProject(outputProjectFilename, false);
        }
        public void SaveTextToMultipleFiles(string outputFileName, Encoding encoding)
        {
            this.IncludeMessages = true;
            this.IncludeStrings  = false;
            string baseDirectoryName = Path.GetDirectoryName(outputFileName);
            string textDirectory     = Path.Combine(baseDirectoryName, "text");
            string rootFileName      = Path.Combine(textDirectory, "root.txt");

            Directory.CreateDirectory(textDirectory);
            using (var rootFileStream = new FileStream(rootFileName, FileMode.Create, FileAccess.Write))
            {
                var rootTextWriter = new StreamWriter(rootFileStream, encoding);

                var enumerator = new FunctionEnumerator(ainFile);
                var results    = enumerator.GetFilesAndFunctions();
                foreach (var result1 in results)
                {
                    string jafFileName = result1.name;
                    foreach (var functionNode in result1.children)
                    {
                        var function = ainFile.GetFunction(functionNode.name);
                        var text     = GetTextFromFunction(function);

                        if (text.Count > 2)
                        {
                            string functionName = AssemblerProjectWriter.SanitizeVariableName(function.Name);
                            if (functionName.StartsWith("\""))
                            {
                            }
                            else
                            {
                                string includeFileName = Path.Combine(jafFileName, functionName + ".txt");
                                string fileName        = Path.Combine(textDirectory, includeFileName);
                                string outputDirectory = Path.GetDirectoryName(fileName);
                                Directory.CreateDirectory(outputDirectory);
                                File.WriteAllLines(fileName, text.ToArray(), encoding);
                                rootTextWriter.WriteLine("#include \"" + includeFileName + "\"");
                            }
                        }
                    }
                }
                rootTextWriter.Flush();
                rootFileStream.Flush();
                rootTextWriter.Close();
                rootFileStream.Close();
            }

            using (var textWriter2 = new StreamWriter(outputFileName, false, encoding))
            {
                textWriter2.WriteLine("#include \"text/root.txt\"");
                textWriter2.Flush();
                textWriter2.Close();
            }
        }
Exemplo n.º 7
0
        public void CompileCode(string codeText, out byte[] codeBytes, out string disassembledCode, bool topLevel, Dictionary <string, string> codePatches)
        {
            int oldStructCount   = ainFile.Structs.Count;
            int oldFunctionCount = ainFile.Functions.Count;
            int oldSwitchCount   = ainFile.Switches.Count;
            int oldFunctypeCount = ainFile.FunctionTypes.Count;
            int oldDelegateCount = ainFile.Delegates.Count;
            int oldGlobalCount   = ainFile.Globals.Count;
            int oldLibraryCount  = ainFile.Libraries.Count;

            codeBytes        = null;
            disassembledCode = null;

            var lastDefaultAinFile = Expression.defaultAinFile;

            try
            {
                if (!topLevel)
                {
                    string dummyFunctionName = "DUMMY" + dummyFunctionNumber.ToString("0000");
                    codeText = "void " + dummyFunctionName + "()" + Environment.NewLine + "{" + Environment.NewLine + codeText + Environment.NewLine + "}" + Environment.NewLine;
                    dummyFunctionNumber++;
                }
                List <TokenExpression> tokens = new List <TokenExpression>();
                IncludeString(codeText, tokens);

                ainFile.Version           = this.AinVersion;
                ainFile.TargetVMVersion   = this.TargetVMVersion;
                ainFile.IsAi2File         = this.IsAi2File;
                ainFile.UsesMsg1          = this.UsesMsg1;
                ainFile.KeyCode           = this.KeyCode;
                ainFile.GameVersion       = this.gameVersion;
                ainFile.UseSimplifiedCode = this.UseSimplifiedCode;
                if (ainFile.Version >= 6)
                {
                    this.Messages.DoNotCombine = true;
                }

                var firstPass = new FirstPass();
                if (this.Error != null)
                {
                    firstPass.Error += this.Error;
                }

                var result = firstPass.CompileFirstPass(tokens);
                if (firstPass.Errors.Count > 0)
                {
                    this.Errors.AddRange(firstPass.Errors);
                    return;
                }

                bool createAdditionalFunctions = topLevel;
                var  symbolsCreated            = CreateSymbols(result, createAdditionalFunctions);
                var  functionsToOutput         = symbolsCreated.OfType <Function>().ToArray();
                var  structsCreated            = symbolsCreated.OfType <Struct>().ToArray();
                var  librariesToOutput         = symbolsCreated.OfType <HllLibrary>().ToArray();
                if (ainFile.Libraries.Count > oldLibraryCount + librariesToOutput.Length)
                {
                    //fix missing libraries
                    librariesToOutput = librariesToOutput.Concat(ainFile.Libraries.Skip(oldLibraryCount)).ToArray();
                }

                GetInitialValues(result);
                if (!CompileSecondPass())
                {
                    return;
                }
                GenerateExpressions();

                var codeGenerator = new CodeGenerator(ainFile);
                foreach (var function in functionsToOutput)
                {
                    var expression = this.FunctionDefinitions.GetOrNull(function);
                    function.Crc     = 0;
                    function.Address = codeGenerator.Address + 6;
                    codeGenerator.GenerateCodeForFunction(expression);
                }

                var writer = new AssemblerProjectWriter(ainFile);
                codeBytes = codeGenerator.Code.ToArray();

                StringWriter    sw = new StringWriter();
                List <Function> functionsToOutput2 = new List <Function>();

                foreach (var function in functionsToOutput)
                {
                    bool handled = false;
                    if (codePatches != null)
                    {
                        if (function.Index < oldFunctionCount)
                        {
                            disassembledCode           = writer.GetDisassembledCode(function, codeBytes);
                            codePatches[function.Name] = disassembledCode;
                            //writer.GetDisassembledCode(codeBytes, new Function[] { function }, ainFile.Structs.Count, ainFile.Delegates.Count, ainFile.FunctionTypes.Count, ainFile.Globals.Count);
                            handled = true;
                        }
                    }

                    if (!handled)
                    {
                        functionsToOutput2.Add(function);
                    }
                }

                writer.GetDisassembledCode(sw, codeBytes, functionsToOutput, functionsToOutput2.ToArray(), structsCreated, librariesToOutput, oldDelegateCount, oldFunctypeCount, oldGlobalCount);
                disassembledCode = sw.ToString();

                ainFile.MAIN = Functions.Contains("main") ? (Functions.Get("main").Index) : -1;
                ainFile.MSGF = Functions.Contains("message") ? (Functions.Get("message").Index) : -1;
                ainFile.OJMP = Functions.Contains("onjump") ? (Functions.Get("onjump").Index) : -1;
                RemoveFunctypes(ainFile);
                FixStructs(ainFile);
                ainFile.ComputeFunctionHashes();
                SortGlobalInitialValues(ainFile);
                SortSwitchCases(ainFile);

                if (!topLevel && Errors.Count > 0)
                {
                    disassembledCode = null;
                    codeBytes        = null;
                }
            }
            finally
            {
                Expression.defaultAinFile = lastDefaultAinFile;

                if (!topLevel)
                {
                    this.FunctionDeclarationTokens.Clear();
                    this.FunctionDefinitionTokens.Clear();
                    this.FunctionDefinitions.Clear();
                }
            }
        }
        static void ToStringReal(TokenExpression ex, MyIndentedTextWriter tw)
        {
            if (ex == null)
            {
                return;
            }
            switch (ex.TokenType)
            {
            default:
                if (!String.IsNullOrEmpty(ex.Token.Value) && ex.Token.Value != "...")
                {
                    tw.Write(ex.Token.Value);
                }
                if (ex.Subexpressions.Count > 0)
                {
                    tw.Write(" ");
                    ToStringReal(ex.Subexpressions, tw);
                }
                break;

            case TokenType.Array:
            case TokenType.AddressOf:
            case TokenType.At:
            case TokenType.Complement:
            case TokenType.Increment:
            case TokenType.Decrement:
                if (!String.IsNullOrEmpty(ex.Token.Value) && ex.Token.Value != "...")
                {
                    tw.Write(ex.Token.Value);
                }
                if (ex.Subexpressions.Count > 0)
                {
                    ToStringReal(ex.Subexpressions, tw);
                }
                break;

            case TokenType.Block:
                if (!tw.TabsPending)
                {
                    tw.WriteLine();
                }
                tw.WriteLine("{");
                tw.Indent++;
                ToStringReal(ex.Subexpressions, tw);
                tw.Indent--;
                if (!tw.TabsPending)
                {
                    tw.WriteLine();
                }
                tw.WriteLine("}");
                break;

            case TokenType.Statement:
                ToStringReal(ex.Subexpressions, tw);
                tw.WriteLine(";");
                break;

            case TokenType.StringLiteral:
                tw.Write(AssemblerProjectWriter.EscapeAndQuoteString(ex.Token.Value));
                break;

            case TokenType.CharLiteral:
            case TokenType.Message:
                tw.Write(AssemblerProjectWriter.EscapeAndQuoteMessage(ex.Token.Value));
                break;

            case TokenType.ArrayIndex:
                tw.Write("[");
                ToStringReal(ex.Subexpressions, tw);
                tw.Write("]");
                break;

            case TokenType.Assert:
                tw.Write("assert (");
                for (int i = 0; i < ex.Subexpressions.Count; i++)
                {
                    if (i != 0)
                    {
                        tw.Write(", ");
                    }
                    ToStringReal(ex.Subexpressions[i], tw);
                }
                tw.Write(")");
                break;

            case TokenType.For:
                tw.Write("for (");
                for (int i = 0; i < 3; i++)
                {
                    if (i != 0)
                    {
                        tw.Write("; ");
                    }
                    var subex = ex.Subexpressions.GetOrNull(i);
                    ToStringReal(subex, tw);
                }
                tw.WriteLine(")");
                ToStringReal(ex.Subexpressions.GetOrNull(3), tw);
                break;

            case TokenType.While:
                tw.Write("while (");
                ToStringReal(ex.Subexpressions.GetOrNull(0), tw);
                tw.WriteLine(")");
                ToStringReal(ex.Subexpressions.GetOrNull(1), tw);
                break;

            case TokenType.If:
                tw.Write("if (");
                ToStringReal(ex.Subexpressions.GetOrNull(0), tw);
                tw.WriteLine(")");
                ToStringReal(ex.Subexpressions.GetOrNull(1), tw);
                {
                    var subex = ex.Subexpressions.GetOrNull(2);
                    if (subex != null)
                    {
                        ToStringReal(subex, tw);
                    }
                }
                break;

            case TokenType.Switch:
                tw.Write("switch (");
                ToStringReal(ex.Subexpressions.GetOrNull(0), tw);
                tw.WriteLine(")");
                ToStringReal(ex.Subexpressions.Skip(1), tw);
                break;

            case TokenType.FunctionCall:
                ToStringReal(ex.Subexpressions.GetOrNull(0), tw);
                tw.Write("(");
                ToStringReal(ex.Subexpressions.Skip(1), tw);
                tw.Write(")");
                break;

            case TokenType.PostDecrement:
            case TokenType.PostIncrement:
                ToStringReal(ex.Subexpressions, tw);
                tw.Write(ex.Token.Value);
                break;

            //infix binary operators
            case TokenType.And:
            case TokenType.AndAssign:
            case TokenType.Assign:
            case TokenType.Colon:
            case TokenType.Comma:
            case TokenType.Divide:
            case TokenType.DivideAssign:
            case TokenType.Dot:
            case TokenType.EqualTo:
            case TokenType.LeftShift:
            case TokenType.LeftShiftAssign:
            case TokenType.LessThan:
            case TokenType.LessThanOrEqualTo:
            case TokenType.LogicalAnd:
            case TokenType.LogicalOr:
            case TokenType.Minus:
            case TokenType.MinusAssign:
            case TokenType.Modulo:
            case TokenType.ModuloAssign:
            case TokenType.Multiply:
            case TokenType.MultiplyAssign:
            case TokenType.NotEqualTo:
            case TokenType.Or:
            case TokenType.OrAssign:
            case TokenType.Plus:
            case TokenType.PlusAssign:
            case TokenType.QuestionMark:
            case TokenType.ReferenceAssign:
            case TokenType.ReferenceEqualTo:
            case TokenType.ReferenceNotEqualTo:
            case TokenType.ReferenceSwap:
            case TokenType.RightShift:
            case TokenType.RightShiftAssign:
            case TokenType.Xor:
            case TokenType.XorAssign:
                //output left side
                ToStringReal(ex.Subexpressions.GetOrNull(0), tw);

                if (ex.TokenType != TokenType.Comma && ex.TokenType != TokenType.Dot)
                {
                    tw.Write(" ");
                }

                if (String.IsNullOrEmpty(ex.Token.Value) || ex.Token.Value == "...")
                {
                    if (keywordTableInverse.ContainsKey(ex.TokenType))
                    {
                        tw.Write(keywordTableInverse[ex.TokenType]);
                    }
                }
                else
                {
                    tw.Write(ex.Token.Value);
                }
                if (ex.TokenType != TokenType.Dot)
                {
                    tw.Write(" ");
                }

                ToStringReal(ex.Subexpressions.Skip(1), tw);
                break;
            }



            //foreach (var ex in exBase.GetAllSubexpressionsRecursive())
            //{
            //    switch (ex.TokenType)
            //    {
            //        case TokenType.And:
            //            case TokenType.

            //        default:
            //            sb.Append(ex.Token.Value);
            //            break;
            //    }
            //}
            //return sb.ToString();
        }
Exemplo n.º 9
0
        private void HandleMessage(InstructionInfoEventArgs e, string messageText)
        {
            int indentSize        = GetIndentSize(messageText);
            int realSplitPosition = FindCharacterIndexOfRightMargin(messageText, maxCharactersPerLine);

            if (realSplitPosition < messageText.Length || e.Handled == true)
            {
                e.Handled = true;
                while (realSplitPosition < messageText.Length)
                {
                    int position = FindSplitPoint(messageText, realSplitPosition);
                    if (position <= indentSize)
                    {
                        //for really long lines - split them at the wrap position instead of an infinite loop
                        position = realSplitPosition;
                    }

                    string line = messageText.Substring(0, position);

                    e.WriteLine(" " + AssemblerProjectWriter.EscapeAndQuoteMessage(line) + " ");
                    GenerateNextLine(e);
                    e.WriteLine("");

                    messageText = messageText.Substring(position);

                    //eat spaces
                    position = 0;
                    while (position < messageText.Length && messageText[position] == ' ')
                    {
                        position++;
                    }
                    if (position > 0)
                    {
                        messageText = messageText.Substring(position);
                    }

                    //add indent if enabled
                    if (MaintainIndentation)
                    {
                        if (indentSize > 0)
                        {
                            messageText = "".PadLeft(indentSize, ' ') + messageText;
                        }
                    }

                    //find next split
                    realSplitPosition = FindCharacterIndexOfRightMargin(messageText, maxCharactersPerLine);
                }

                //remaining text is set to something if this is a "next message" call, so output any leftover text at that time.
                //Otherwise, if we have the leftover text feature disabled, output it now.
                if (!this.RemoveLineBreaksIfWordWrapping || this.remainingText != "")
                {
                    e.WriteText(" " + AssemblerProjectWriter.EscapeAndQuoteMessage(messageText) + " ");
                    this.remainingText = "";
                }
                else
                {
                    this.remainingText = messageText;
                }
            }
        }
            void writer_BeforeWritingInstruction(object sender, InstructionInfoEventArgs e)
            {
                var instructionInfo = e.InstructionInfo;
                var instruction     = instructionInfo.instruction;
                int word1           = instructionInfo.word1;

                if (InsideFunction)
                {
                    if (!hasOutputFunction)
                    {
                        if (this.CodePatches.ContainsKey(currentFunctionName))
                        {
                            var codePatch = this.CodePatches[currentFunctionName];
                            e.WriteLine(codePatch);
                        }
                        hasOutputFunction = true;
                    }

                    if (instruction == Instruction.FUNC || instruction == Instruction.ENDFUNC || instruction == Instruction.EOF)
                    {
                        //will emit the ENDFUNC or next FUNC instruction
                        InsideFunction     = false;
                        e.StopEmittingCode = false;
                    }
                    else
                    {
                        e.Handled          = true;
                        e.StopEmittingCode = true;
                        return;
                    }
                }


                if (instruction == Instruction.FUNC)
                {
                    int functionNumber = instructionInfo.word1;
                    var function       = ainFile.GetFunction(functionNumber);
                    if (function != null)
                    {
                        stringNumber        = 0;
                        messageNumber       = 0;
                        currentFunctionName = function.Name;
                        stringDictionary    = stringEntries.GetOrNull(currentFunctionName);
                        messageDictionary   = messageEntries.GetOrNull(currentFunctionName);

                        if (this.CodePatches.ContainsKey(currentFunctionName))
                        {
                            //var codePatch = this.CodePatches[currentFunctionName];
                            //e.WriteLine(codePatch);
                            e.Handled          = false;
                            e.StopEmittingCode = false;
                            //will emit the FUNC instruction, but then not the rest
                            this.InsideFunction    = true;
                            this.hasOutputFunction = false;
                        }
                    }
                }
                else /*if (stringDictionary != null || messageDictionary != null)*/
                {
                    if (instruction == Instruction.MSG)
                    {
                        string originalMessage = originalAinFile.GetMessage(word1);
                        string newMessage      = null;
                        if (messageDictionary != null)
                        {
                            newMessage = messageDictionary.GetOrNull(messageNumber);
                        }

                        if (newMessage != null && newMessage != originalMessage)
                        {
                            e.Text = newMessage;
                        }

                        if (this.WordWrap)
                        {
                            if (this.wordWrapper.HasRemainingText == false && e.Text == originalMessage)
                            {
                                //don't wrap text because we match the original and don't have remaining text
                            }
                            else
                            {
                                wordWrapper.projectWriter_BeforeWritingInstruction(sender, e);
                            }
                        }
                        if (e.Dirty && !e.Handled)
                        {
                            //recheck this!
                            newMessage = e.Text;
                            e.WriteLine("\tMSG " + AssemblerProjectWriter.EscapeAndQuoteMessage(newMessage));
                            e.Handled = true;
                        }
                        messageNumber++;
                    }
                    //string instructions are handled by writer_BeforeWritingString
                    else if (instruction == Instruction.CALLFUNC)
                    {
                        //for text wrapping (to do later)
                        if (this.WordWrap)
                        {
                            wordWrapper.projectWriter_BeforeWritingInstruction(sender, e);
                        }
                    }
                }
            }
            private void ExportAndMerge()
            {
                string newDisassembledCode = null;

                if ((this.CodePatches2 != null && this.CodePatches2.Length > 0) || numberedStrings.Count > 0)
                {
                    this.ainFile = ainFile.Clone();
                }


                if (this.CodePatches2 != null && this.CodePatches2.Length > 0)
                {
                    //this.ainFile = ainFile.Clone();
                    var    compiler = new Compiler.Compiler(ainFile);
                    byte[] codeBytes;
                    compiler.CompileCode(this.CodePatches2.ToString(), out codeBytes, out newDisassembledCode, true, this.CodePatches);
                    if (newDisassembledCode == null || compiler.Errors.Count > 0)
                    {
                        var errorsListForm = new ErrorsListForm();
                        errorsListForm.SetErrorList(compiler.Errors);
                        errorsListForm.Show();
                        return;
                    }

                    //foreach (var func in functionsToOutput)
                    //{
                    //    this.CodePatches[func.Name] = "";
                    //}
                }

                currentFunctionName = "";
                stringDictionary    = null;
                messageDictionary   = null;
                stringNumber        = 0;
                messageNumber       = 0;

                //var ainFile = this.ainFile;
                if (numberedStrings.Count > 0)
                {
                    //this.ainFile = ainFile.Clone();
                    var stringExportImport = new StringExportImport(ainFile);
                    int firstMessage       = stringExportImport.GetFirstMessageIdNumber();
                    int lastMessage        = firstMessage + ainFile.Messages.Count;
                    int firstString        = stringExportImport.GetFirstStringIdNumber();
                    int lastString         = firstString + ainFile.Strings.Count;

                    foreach (var pair in numberedStrings)
                    {
                        int    number  = pair.Key;
                        string message = pair.Value;
                        if (number >= firstMessage && number < lastMessage)
                        {
                            ainFile.Messages[number - firstMessage] = message;
                        }
                        else if (number >= firstString && number < lastString)
                        {
                            ainFile.Strings[number - firstString] = message;
                        }
                    }
                }

                using (TemporaryFile tempFile = new TemporaryFile("jam", true))
                {
                    var saver   = new ExplorerForm.SaveProjectInBackground();
                    var options = new CodeDisplayOptions();
                    options.AnnotateWithDecompiledCode = false;
                    options.MergeDuplicateStrings      = true;
                    options.MergeDuplicateMessages     = true;
                    var writer = new AssemblerProjectWriter(ainFile, options);
                    writer.BeforeWritingInstruction += new EventHandler <InstructionInfoEventArgs>(writer_BeforeWritingInstruction);
                    writer.BeforeWritingString      += new EventHandler <InstructionInfoEventArgs>(writer_BeforeWritingString);
                    saver.SaveAsProject(writer, tempFile.FileName, true);
                    if (newDisassembledCode != null)
                    {
                        using (var fs = new FileStream(tempFile.FileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                        {
                            using (var sw = new StreamWriter(fs, Extensions.TextEncoding))
                            {
                                sw.WriteLine();
                                sw.WriteLine(newDisassembledCode);
                                sw.Flush();
                                fs.Flush();
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }


                    //WaitForFileLock(tempFile.FileName, 2000);

                    //tempFile.FileName

                    var builder = new ExplorerForm.BuildProjectInBackground();
                    builder.ForceUniqueMessages = true;
                    builder.Run(tempFile.FileName, this.outputFileName, true);
                }
            }
            private void ReadReplacementFile(TextReaderWrapper tr, string textFileName)
            {
                textFileName = Path.GetFullPath(textFileName);
                if (IncludedFiles.Contains(textFileName.ToUpperInvariant()))
                {
                    return;
                }
                IncludedFiles.Set(textFileName.ToUpperInvariant());

                string line;

                while (true)
                {
                    line = tr.ReadLine();
                    if (line == null)
                    {
                        break;
                    }

                    //remove initial whitespace
                    line = line.TrimStart();

                    //check for "#include"
                    if (line.StartsWith("#include "))
                    {
                        string filenameToInclude = line.Substring("#include ".Length);
                        //check for quotes?
                        if (filenameToInclude.StartsWith("\"") && filenameToInclude.EndsWith("\""))
                        {
                            filenameToInclude = filenameToInclude.Substring(1, filenameToInclude.Length - 2);
                        }
                        string basePath = tr.DirectoryName;
                        filenameToInclude = Path.Combine(basePath, filenameToInclude);
                        if (!File.Exists(filenameToInclude))
                        {
                            throw new FileNotFoundException("Cannot find file: " + filenameToInclude, filenameToInclude);
                        }

                        if (File.Exists(filenameToInclude) && !IncludedFiles.Contains(filenameToInclude.ToUpperInvariant()))
                        {
                            IncludedFiles.Add(filenameToInclude.ToUpperInvariant());
                            var encoding = EncodingDetector.DetectEncoding(filenameToInclude);
                            tr.IncludeTextReader(new StreamReader(filenameToInclude, encoding));
                        }
                        continue;
                    }


                    //remove commented text
                    int indexOfComment = line.IndexOf('#');
                    if (indexOfComment >= 0)
                    {
                        line = line.Substring(0, indexOfComment);
                    }

                    //reading one of these lines:
                    //CODE
                    //function x functionName  (or func, f)
                    //string x text (or str, s)
                    //message x text (or msg, m)
                    //id x text (or i)
                    //x text (same as id x text)

                    string lineTrim = line.Trim();

                    if (lineTrim.Equals("CODE", StringComparison.OrdinalIgnoreCase) || lineTrim.Equals("CODE2", StringComparison.OrdinalIgnoreCase))
                    {
                        bool          isCode2  = lineTrim.Equals("CODE2", StringComparison.OrdinalIgnoreCase);
                        StringBuilder codeText = new StringBuilder();
                        while (true)
                        {
                            line     = tr.ReadLine();
                            lineTrim = line.Trim();
                            if (lineTrim.StartsWith("#include"))
                            {
                                string filenameToInclude = lineTrim.Substring("#include ".Length);
                                //check for quotes?
                                if (filenameToInclude.StartsWith("\"") && filenameToInclude.EndsWith("\""))
                                {
                                    filenameToInclude = filenameToInclude.Substring(1, filenameToInclude.Length - 2);
                                }
                                string basePath = tr.DirectoryName;
                                if (!Path.IsPathRooted(filenameToInclude))
                                {
                                    filenameToInclude = Path.Combine(basePath, filenameToInclude);
                                }
                                filenameToInclude = Path.GetFullPath(filenameToInclude);

                                if (!File.Exists(filenameToInclude))
                                {
                                    throw new FileNotFoundException("Cannot find file: " + filenameToInclude, filenameToInclude);
                                }

                                if (File.Exists(filenameToInclude) && !IncludedFiles.Contains(filenameToInclude.ToUpperInvariant()))
                                {
                                    IncludedFiles.Add(filenameToInclude.ToUpperInvariant());

                                    if (isCode2)
                                    {
                                        //replace with #include <fullpath>, let the compiler handle the actual include
                                        codeText.AppendLine("#include " + AssemblerProjectWriter.EscapeAndQuoteString(filenameToInclude));
                                    }
                                    else
                                    {
                                        var encoding = EncodingDetector.DetectEncoding(filenameToInclude);
                                        tr.IncludeTextReader(new StreamReader(filenameToInclude, encoding));
                                    }
                                }
                                continue;
                            }

                            if (lineTrim.ToUpperInvariant() == "ENDCODE")
                            {
                                if (isCode2)
                                {
                                    CodePatches2.AppendLine(codeText.ToString());
                                }
                                else
                                {
                                    CodePatches.Set(currentFunctionName, codeText.ToString());
                                }
                                break;
                            }
                            else
                            {
                                codeText.AppendLine(line);
                            }
                        }
                        continue;
                    }

                    //find first space
                    int spaceIndex = line.IndexOf(' ');
                    if (spaceIndex == -1)
                    {
                        continue;
                    }
                    string tagName = line.Substring(0, spaceIndex);
                    line = line.Substring(spaceIndex + 1);
                    int number;
                    //if it starts with a number, it's a legacy text replacement
                    if (IntUtil.TryParse(tagName, out number) == true)
                    {
                        tagName = "id";
                    }
                    else
                    {
                        bool   isFunction   = false;
                        string tagNameLower = tagName.ToLowerInvariant();
                        if (tagNameLower == "f" || tagNameLower == "func" || tagNameLower == "function")
                        {
                            isFunction = true;
                        }

                        line       = line.TrimStart();
                        spaceIndex = line.IndexOf(' ');
                        if (spaceIndex == -1)
                        {
                            if (isFunction)
                            {
                                number = -1;
                            }
                            else
                            {
                                continue;
                            }
                        }
                        else
                        {
                            string numberString = line.Substring(0, spaceIndex);
                            line = line.Substring(spaceIndex + 1);

                            if (IntUtil.TryParse(numberString, out number) == false)
                            {
                                if (isFunction)
                                {
                                    line   = numberString + " " + line;
                                    number = -1;
                                }
                                else
                                {
                                    continue;
                                }
                            }
                        }
                    }

                    line = StringExportImport.UnescapeText(line);

                    switch (tagName.ToLowerInvariant())
                    {
                    case "f":
                    case "func":
                    case "function":
                        string nextFunctionName = line.Trim();
                        var    function         = ainFile.GetFunction(number);
                        if (function == null)
                        {
                            function = ainFile.GetFunction(nextFunctionName);
                            if (function == null)
                            {
                                continue;
                            }
                        }
                        currentFunctionName = function.Name;
                        stringDictionary    = stringEntries.GetOrAddNew(currentFunctionName);
                        messageDictionary   = messageEntries.GetOrAddNew(currentFunctionName);
                        break;

                    case "string":
                    case "str":
                    case "s":
                        stringDictionary.Set(number, line);
                        break;

                    case "msg":
                    case "message":
                    case "m":
                        messageDictionary.Set(number, line);
                        break;

                    case "i":
                    case "id":
                        numberedStrings.Set(number, line);
                        break;
                    }
                }
            }
        private List <string> GetTextFromFunction(Function function)
        {
            int numberOfNonCommentedLines = 0;
            int numberOfStrings           = 0;
            int numberOfMessages          = 0;

            //Expression expression = null;
            //int expressionLastAddress = function.Address;

            useStringsToMatch = StringsToMatch != null && StringsToMatch.Count > 0;
            //List<string> strings = new List<string>();
            //List<string> messages = new List<string>();
            List <string> functionLines      = new List <string>();
            string        functionLineString = "FUNCTION " + /*function.Index.ToString() + " " + */ AssemblerProjectWriter.SanitizeVariableName(function.Name);

            functionLines.Add(functionLineString);
            functionLines.Add("#x strings, x messages");  //this line gets changed later (it's index 1)
            int    address  = function.Address;
            string lastName = null;

            while (address < ainFile.Code.Length)
            {
                var instructionInfo = ainFile.Peek(address);
                if (instructionInfo.instruction == Instruction.ENDFUNC || instructionInfo.instruction == Instruction.FUNC)
                {
                    break;
                }
                if (this.AnnotateEnumerationType != null && instructionInfo.instruction == Instruction.CALLFUNC)
                {
                    var func = ainFile.GetFunction(instructionInfo.word1);
                    if (VariablesUsingEnumerationType.Contains(func))
                    {
                        var parameters = GetParametersThatUsesEnumerationType(func);
                        if (parameters.FirstOrDefault() != null)
                        {
                            foreach (var parameter in parameters)
                            {
                                int i    = parameter.Index;
                                int addr = instructionInfo.CurrentAddress - (func.ParameterCount) * 6 + i * 6;
                                var ins2 = ainFile.Peek(addr);
                                if (ins2.instruction == Instruction.PUSH)
                                {
                                    string enumerationValue = this.AnnotateEnumerationType.GetOrDefault(ins2.word1, "");
                                    if (!String.IsNullOrEmpty(enumerationValue))
                                    {
                                        functionLines.Add("");
                                        functionLines.Add("#" + enumerationValue);
                                    }
                                }
                                else if (ins2.instruction == Instruction.S_PUSH)
                                {
                                    string str = ainFile.GetString(ins2.word1);
                                    if (!String.IsNullOrEmpty(str))
                                    {
                                        if (this.replacementStringsForAnnotations != null && this.replacementStringsForAnnotations.ContainsKey(str))
                                        {
                                            string nextStr = this.replacementStringsForAnnotations[str];
                                            if (!nextStr.StartsWith("*"))
                                            {
                                                str = nextStr;
                                            }
                                            else
                                            {
                                                str = lastName;
                                            }
                                        }
                                        else
                                        {
                                        }
                                        if (lastName != str)
                                        {
                                            lastName = str;
                                            functionLines.Add("");
                                            functionLines.Add("#" + str);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (instructionInfo.instruction == Instruction.MSG)
                {
                    //if (this.AnnotateEnumerationType != null)
                    //{
                    //    if (expression == null)
                    //    {
                    //        expression = ainFile.DecompiledCodeCache.GetDecompiledCode(function);
                    //    }
                    //    CatchUpToAddress(ref expression, functionLines, address);
                    //}
                    int    messageNumber = instructionInfo.word1;
                    string message       = ainFile.GetMessage(messageNumber);
                    if (message != null)
                    {
                        if (useStringsToMatch == false || StringsToMatch.Contains(message))
                        {
                            string messageLine = "m " + numberOfMessages.ToString("000") + " " + StringExportImport.EscapeText(message);
                            functionLines.Add(messageLine);
                        }
                        numberOfMessages++;
                        numberOfNonCommentedLines++;
                    }
                }
                else if (instructionInfo.instruction == Instruction.STRSWITCH)
                {
                    int switchBlockNumber = instructionInfo.word1;
                    var switchBlock       = ainFile.Switches.GetOrNull(switchBlockNumber);
                    if (switchBlock != null)
                    {
                        foreach (var switchCase in switchBlock.SwitchCases)
                        {
                            int    stringNumber = switchCase.Value;
                            string str          = ainFile.GetString(stringNumber);
                            if (str != null)
                            {
                                AddString(ref numberOfNonCommentedLines, ref numberOfStrings, functionLines, stringNumber, str);
                            }
                        }
                    }
                }
                else
                {
                    int indexOfStringArgument = instructionInfo.instruction.IndexOfStringArgument();
                    if (indexOfStringArgument != -1)
                    {
                        int    stringNumber = instructionInfo.words[indexOfStringArgument];
                        string str          = ainFile.GetString(stringNumber);
                        if (str != null)
                        {
                            AddString(ref numberOfNonCommentedLines, ref numberOfStrings, functionLines, stringNumber, str);
                        }
                    }
                }
                address = instructionInfo.nextAddress;
            }
            functionLines[1] = "#" + numberOfStrings.ToString() + " strings, " + numberOfMessages.ToString() + " messages";
            if (numberOfNonCommentedLines == 0)
            {
                functionLines.Clear();
            }
            return(functionLines);
        }