public void ImportPexts(ArrayList pextsList)
 {
     Utilities.Utilities.VerbouseOut("PREPROCESSOR", "Reading pext list");
     foreach (pextData pextName in pextsList)
     {
         pexts = pexts.Concat(CodeIO.LoadPext(pextName.pextName, pextName.mountPoint)).GroupBy(i => i.Key).ToDictionary(group => group.Key, group => group.First().Value);
     }
 }
 public Preprocessor(ArrayList importsList)
 {
     Utilities.Utilities.VerbouseOut("PREPROCESSOR", "Reading macroses list");
     foreach (string macrosName in importsList)
     {
         imports = imports.Concat(CodeIO.LoadMacros(macrosName)).GroupBy(i => i.Key).ToDictionary(group => group.Key, group => group.First().Value);
     }
 }
        public Assembly(string programName)
        {
            this.programName = programName;

            string[] lines = CodeIO.LoadFile(programName);
            //Clearing Code
            //Removing comments and trimming
            Utilities.Utilities.VerbouseOut("-=-=Clearing code from comments=-=-");
            lines = ClearCode(lines);
            Utilities.Utilities.VerbouseOut("-=-=Parsing lines=-=-");
            parsed = SplitCode(lines);
            //Get hat
            Utilities.Utilities.VerbouseOut("-=-=Parsing libraries imports=-=-");
            ArrayList imports = GetImports(parsed);

            //Catching imports
            Utilities.Utilities.VerbouseOut("Importing");
            importManager = new Preprocessor(imports);
            //Calling preprocessor
            Utilities.Utilities.VerbouseOut("PREPROCESSOR", "Inserting macroses...");
            for (int i = 0; i < importManager.CountMacroses(); i++)
            {
                parsed = InsertAllMacro(parsed);
            }
            Utilities.Utilities.VerbouseOut("PREPROCESSOR", "Updated code: ");
            if (Program.verboseMode)
            {
                for (int j = 0; j < parsed.Length; j++)
                {
                    Console.Write(j + ":\t");
                    for (int k = 0; k < parsed[j].Length; k++)
                    {
                        Console.Write(parsed[j][k] + " ");
                    }
                    Console.WriteLine();
                }
            }
            Utilities.Utilities.VerbouseOut("PREPROCESSOR", "Finding definitions...");
            parsed = importManager.CatchDefines(parsed);
            var safer = new List <string[]>();

            for (int i = 0; i < parsed.Length; i++)
            {
                if (parsed[i] != null)
                {
                    safer.Add(parsed[i]);
                }
            }
            parsed = safer.ToArray();
            Utilities.Utilities.VerbouseOut("-=-=Parsing pExts=-=-");
            ArrayList pexts = GetPexts(parsed);

            importManager.ImportPexts(pexts);
            Utilities.Utilities.VerbouseOut("Removing preprocessor code from source...");
            parsed = ClearHatAfterImport(parsed);
            //Catching labels
            Utilities.Utilities.VerbouseOut("Parsing labels...");
            CodeLine[] code = LabelCatcher(parsed);
            //Converting code to object form

            Utilities.Utilities.VerbouseOut("PREPROCESSOR", "Cleared code: ");
            if (Program.verboseMode)
            {
                for (int j = 0; j < parsed.Length; j++)
                {
                    Console.Write(j + ":\t");
                    for (int k = 0; k < parsed[j].Length; k++)
                    {
                        Console.Write(parsed[j][k] + " ");
                    }
                    Console.WriteLine();
                }
            }

            Utilities.Utilities.VerbouseOut("Converting code to object form");
            for (int i = 0; i < code.Length; i++)
            {
                string opcode = code[i].code[0].ToLower();
                string label  = code[i].label;
                if (opcode == "add")
                {
                    program.Add(new Add(code[i].code[1], code[i].code[2]));
                }
                else if (opcode == "in")
                {
                    if (code[i].code.Length == 2)
                    {
                        program.Add(new In(code[i].code[1]));
                    }
                    else if (code[i].code.Length > 2)
                    {
                        program.Add(new In(code[i].code[1], code[i].code[2]));
                    }
                }
                else if (opcode == "jmp")
                {
                    program.Add(new Jmp(code[i].code[1]));
                }
                else if (opcode == "jnc")
                {
                    program.Add(new Jnc(code[i].code[1]));
                }
                else if (opcode == "ld")
                {
                    program.Add(new Ld(code[i].code[1]));
                }
                else if (opcode == "mov")
                {
                    if (code[i].code.Length == 3)
                    {
                        program.Add(new Mov(code[i].code[1], code[i].code[2]));
                    }
                    else if (code[i].code.Length > 3)
                    {
                        program.Add(new Mov(code[i].code[1], code[i].code[2], code[i].code[3]));
                    }
                }
                else if (opcode == "out")
                {
                    if (code[i].code.Length == 2)
                    {
                        program.Add(new Out(code[i].code[1]));
                    }
                    else if (code[i].code.Length > 2)
                    {
                        program.Add(new Out(code[i].code[1], code[i].code[2]));
                    }
                }
                else if (opcode == "st")
                {
                    program.Add(new St(code[i].code[1]));
                }
                else if (opcode == "swi")
                {
                    program.Add(new Swi(code[i].code[1]));
                }
                else if (opcode == "swm")
                {
                    program.Add(new Swm(code[i].code[1]));
                }
                else
                {
                    program.InsertSubTree(program.Count, importManager.LookUpPext(opcode, code[i].code));
                }
                if (label != null)
                {
                    program.AddLabel(label);
                }
            }
            Utilities.Utilities.VerbouseOut("Linking labels...");
            for (int i = 0; i <= program.Count; i++)
            {
                if (program[i].opcode is Jmp || program[i].opcode is Jnc)
                {
                    if (program[i].opcode.Arg1 == null)
                    {
                        ((PCChanger)program[i].opcode).Link = program[program[i].opcode.FastAdd.toInt() + 1];
                        Utilities.Utilities.VerbouseOut("LABEL_LINKER", "Linked: " + program[i].opcode.Name + " " + program[i].opcode.FastAdd.ToString() + " to " + ((PCChanger)program[i].opcode).Link.ToString());
                    }
                    else
                    {
                        ((PCChanger)program[i].opcode).Link = program.GetLabel(program[i].opcode.Arg1);
                        Utilities.Utilities.VerbouseOut("LABEL_LINKER", "Linked: " + program[i].opcode.Name + " " + program[i].opcode.Arg1.ToString() + " to " + ((PCChanger)program[i].opcode).Link.ToString());
                    }
                }
            }
            if (Program.verboseMode)
            {
                Console.WriteLine("---Final code---");
                int length = program.Count;
                for (int i = 1; i <= length; i++)
                {
                    Console.Write(i + ":\t");
                    IOpcode line = program.Get(i).opcode;
                    Console.Write(line.Name + "\t");
                    if (line.Arg1 != null)
                    {
                        Console.Write(line.Arg1 + "\t");
                    }
                    if (line is Mov)
                    {
                        if (line.Arg2 != null)
                        {
                            Console.Write(line.Arg2 + "\t");
                        }
                    }
                    if (line.FastAdd != null)
                    {
                        Console.Write(line.FastAdd.GetValue());
                    }
                    Console.WriteLine();
                }
            }
        }
        public string[][] CatchDefines(string[][] text)
        {
            for (int i = 0; i < text.Length; i++)
            {
                if (text[i] != null)
                {
                    if (text[i][0] == "#define")
                    {
                        AddDefinition(text[i][1], text[i][2]);
                        Utilities.Utilities.VerbouseOut("\tDefined: " + text[i][1] + " = " + text[i][2], ConsoleColor.Green);
                    }
                    else if (text[i][0] == "#ifdef")
                    {
                        string testval   = text[i][1];
                        int    cacheIter = i;
                        if (definitions.ContainsKey(testval))
                        {
                            text[i] = null;
                            i++;
                            while (text[i][0] != "#endif" && text[i][0] != "#else")
                            {
                                i++;
                            }
                            if (text[i][0] == "#else")
                            {
                                text[i] = null;
                                i++;
                                while (text[i][0] != "#endif")
                                {
                                    text[i] = null;
                                    i++;
                                }
                            }
                        }
                        else
                        {
                            text[i] = null;
                            i++;
                            while (text[i][0] != "#endif" && text[i][0] != "#else")
                            {
                                text[i] = null;
                                i++;
                            }
                            if (text[i][0] == "#else")
                            {
                                text[i] = null;
                                i++;
                                while (text[i][0] != "#endif")
                                {
                                    i++;
                                }
                            }
                        }
                        i = cacheIter;
                    }
                    else if (text[i][0] == "#ifndef")
                    {
                        string testval   = text[i][1];
                        int    cacheIter = i;
                        if (!definitions.ContainsKey(testval))
                        {
                            text[i] = null;
                            i++;
                            while (text[i][0] != "#endif" && text[i][0] != "#else")
                            {
                                i++;
                            }
                            if (text[i][0] == "#else")
                            {
                                text[i] = null;
                                i++;
                                while (text[i][0] != "#endif")
                                {
                                    text[i] = null;
                                    i++;
                                }
                            }
                        }
                        else
                        {
                            text[i] = null;
                            i++;
                            while (text[i][0] != "#endif" && text[i][0] != "#else")
                            {
                                text[i] = null;
                                i++;
                            }
                            if (text[i][0] == "#else")
                            {
                                text[i] = null;
                                i++;
                                while (text[i][0] != "#endif")
                                {
                                    i++;
                                }
                            }
                        }
                        i = cacheIter;
                    }
                    else if (text[i][0] == "#line")
                    {
                        int    stringNum = int.Parse(text[i][1]);
                        string filename  = text[i][2].Substring(1, text[i][2].Length - 2);
                        text[i] = Assembly.SplitCode(CodeIO.LoadFile(filename))[stringNum];
                    }
                    else if (text[i][0] == "#error")
                    {
                        Utilities.Utilities.Error("COMPILATION_WORKFLOW", text[i][1]);
                        Environment.Exit(1);
                    }
                    else if (text[i][0] == "#message")
                    {
                        Utilities.Utilities.Message(text[i][1]);
                    }
                    else if (text[i][0] == "#pragma")
                    {
                        switch (text[i][1])
                        {
                        case "8_BIT":
                            AddDefinition(text[i][1], "TRUE");
                            Program.eightBit = true;
                            break;

                        case "NO_OPT":
                            AddDefinition(text[i][1], "TRUE");
                            Program.optimize = false;
                            break;

                        case "4_BIT":
                            AddDefinition(text[i][1], "TRUE");
                            Program.eightBit = false;
                            break;

                        case "USE_TRACE":
                            AddDefinition(text[i][1], "TRUE");
                            Program.useTracer = true;
                            break;

                        case "NO_TRACE":
                            AddDefinition(text[i][1], "TRUE");
                            Program.useTracer = false;
                            break;

                        case "CONFIG":
                            if (!Program.configExists)
                            {
                                Utilities.Utilities.Error("PREPROCESSOR", "Configuration file was not specified.");
                            }
                            AddDefinition("HAS_CONFIG", "TRUE");
                            for (int j = 0; j < Program.config.Length; j++)
                            {
                                AddDefinition("config." + Program.config[j][0], Program.config[j][1]);
                            }
                            break;

                        case "UNDEF_ALL":
                            definitions.Clear();
                            break;

                        case "DEF_SYS":
                            if (Program.eightBit)
                            {
                                AddDefinition("8_BIT", "TRUE");
                            }
                            else
                            {
                                AddDefinition("4_BIT", "TRUE");
                            }
                            if (Program.makeBinary)
                            {
                                AddDefinition("BINARY", "TRUE");
                            }
                            else
                            {
                                AddDefinition("TEXT", "TRUE");
                            }
                            if (Program.optimize)
                            {
                                AddDefinition("OPTIMIZE", "TRUE");
                            }
                            else
                            {
                                AddDefinition("NO_OPT", "TRUE");
                            }
                            if (Program.useTracer)
                            {
                                AddDefinition("USE_TRACE", "TRUE");
                            }
                            else
                            {
                                AddDefinition("NO_TRACE", "TRUE");
                            }
                            break;
                        }
                    }
                    else if (text[i][0] == "#sumdef")
                    {
                        string val    = text[i][1];
                        string addval = text[i][2];
                        int    oldVal = FastAdd.IsFastAdd(val) ? int.Parse(val) : new FastAdd(definitions[val]).toInt();
                        int    toAdd  = FastAdd.IsFastAdd(addval) ? int.Parse(addval) : new FastAdd(definitions[addval]).toInt();
                        definitions[val] = (oldVal + toAdd).ToString();
                        Utilities.Utilities.VerbouseOut("\tRedefined: " + text[i][1] + ": " + (oldVal + toAdd).ToString(), ConsoleColor.Yellow);
                    }
                    else if (text[i][0] == "#resdef")
                    {
                        string val    = text[i][1];
                        string resval = text[i][2];
                        int    oldVal = FastAdd.IsFastAdd(val) ? int.Parse(val) : new FastAdd(definitions[val]).toInt();
                        int    toSub  = FastAdd.IsFastAdd(resval) ? int.Parse(resval) : new FastAdd(definitions[resval]).toInt();
                        definitions[val] = (oldVal - toSub).ToString();
                        Utilities.Utilities.VerbouseOut("\tRedefined: " + text[i][1] + ": " + (oldVal - toSub).ToString(), ConsoleColor.Yellow);
                    }
                    else if (text[i][0] == "#undef")
                    {
                        RemoveDefinition(text[i][1]);
                        Utilities.Utilities.VerbouseOut("\tUndefined: " + text[i][1], ConsoleColor.Red);
                    }
                    else if (text[i][0] == "#map")
                    {
                        if (text[i].Length > 3)
                        {
                            MapDefine(text[i][2], text[i][1], int.Parse(text[i][3]));
                        }
                        else
                        {
                            MapDefine(text[i][2], text[i][1], Program.eightBit ? 256 : 16);
                        }
                    }
                    else if (text[i][0] == "#fordef")
                    {
                        List <string[]> dictLocal    = new List <string[]>();
                        int             j            = i + 1;
                        int             pastePos     = i;
                        string          iterator     = text[i][1];
                        int             initialValue = FastAdd.IsFastAdd(text[i][2]) ? int.Parse(text[i][2]) : new FastAdd(definitions[text[i][2]]).toInt();
                        int             endingVale   = FastAdd.IsFastAdd(text[i][3]) ? int.Parse(text[i][3]) : int.Parse(definitions[text[i][3]]);
                        int             step         = int.Parse(text[i][4]);
                        text[i] = null;
                        while (text[j][0] != "#endfor")
                        {
                            dictLocal.Add(text[j]);
                            text[j] = null;
                            j++;
                        }
                        text[j] = null;
                        for (int l = initialValue; l < endingVale; l += step)
                        {
                            for (int k = 0; k < dictLocal.Count; k++)
                            {
                                text = InsertCopySplitLine(text, dictLocal[k], pastePos, iterator, l.ToString());
                                Assembly.InsertSplitLine(dictLocal[k], pastePos, iterator, l.ToString());
                                pastePos++;
                            }
                        }
                        i--;
                    }
                    else
                    {
                        for (int j = 0; j < text[i].Length; j++)
                        {
                            var toPaste = GetDefinition(text[i][j]);
                            if (toPaste != null)
                            {
                                text[i][j] = toPaste;
                                Assembly.ReplaceLexem(i, j, toPaste);
                            }
                        }
                    }
                }
            }
            if (Program.verboseMode)
            {
                if (definitions.Keys.Count > 0)
                {
                    Utilities.Utilities.Warning("PREPROCESSOR", "WARNING: NOT ALL DEFINITIONS WERE UNDEFINED");
                    foreach (string s in definitions.Keys)
                    {
                        Console.WriteLine("\t{0}\t:\t{1}", s, definitions[s]);
                    }
                    Utilities.Utilities.Warning("PREPROCESSOR", "Undefined variables may cause assembly errors");
                }
            }
            return(text);
        }
        static void Main(string[] args)
        {
            CommandLineApplication commandLine = new CommandLineApplication(throwOnUnexpectedArg: false)
            {
                Name        = "TD4",
                Description = "(c) 2019 JL Computer Inc. TD4++ CPU Developer Kit.\nOptimizing assembler"
            };

            string outputFile;
            string links;
            bool   optimize;

            var           argument     = commandLine.Argument("filename", "Source .s file", false);
            CommandOption output       = commandLine.Option("-o | --Output <output>", "Ouput file name", CommandOptionType.SingleValue);
            CommandOption target       = commandLine.Option("-t | --Target <target>", "Output target. \n\t\t\'td4e\' produces binary output for TD4+ processor. Classic TD4 programs should be assembled using this option. TD4+ is set by default. \n\t\t\'td4e8\' produces code for TD4++ which have 8bit Im. \n\t\t\'asm\' produces assembler code. \n\t\t\'asm8\' produces 8bit assembler code", CommandOptionType.SingleValue);
            CommandOption libraries    = commandLine.Option("-l | --Link <location>", "Libraries location (if not default)", CommandOptionType.SingleValue);
            CommandOption verbose      = commandLine.Option("-v | --Verbose", "Verbose mode", CommandOptionType.NoValue);
            CommandOption useTracerKey = commandLine.Option("-T | --Tracer", "Use code tracer", CommandOptionType.NoValue);
            CommandOption optimization = commandLine.Option("-O | --Optimize", "Optimize assembly (experimental)", CommandOptionType.NoValue);
            CommandOption configFile   = commandLine.Option("-c | --Configuration <file.conf>", "Machine configuration file", CommandOptionType.SingleValue);

            commandLine.HelpOption("-? | -h | --Help");
            commandLine.OnExecute(() =>
            {
                if (output.HasValue())
                {
                    outputFile = output.Value();
                    if (outputFile == null)
                    {
                        outputFile = "a.out";
                    }
                    Program.outputFile = outputFile;
                    verboseMode        = verbose.HasValue();
                    useTracer          = useTracerKey.HasValue();
                    if (target.HasValue())
                    {
                        if (target.Value() == "td4e")
                        {
                            makeBinary = true;
                            eightBit   = false;
                        }
                        else if (target.Value() == "td4e8")
                        {
                            makeBinary = true;
                            eightBit   = true;
                        }
                        else if (target.Value() == "asm")
                        {
                            makeBinary = false;
                            eightBit   = false;
                        }
                        else if (target.Value() == "asm8")
                        {
                            makeBinary = false;
                            eightBit   = true;
                        }
                        else
                        {
                            Console.WriteLine("Unknown target: \"{0}\". Aborting.", target.Value());
                            Environment.Exit(1);
                        }
                    }
                    if (configFile.HasValue())
                    {
                        configExists = true;
                        config       = CodeIO.LoadConfig(configFile.Value());
                    }
                    optimize = optimization.HasValue();
                    links    = libraries.Value();
                    if (links == null)
                    {
                        links = Directory.GetCurrentDirectory();
                    }
                    if (verboseMode)
                    {
                        Console.WriteLine("TD4++ Assembler v3.0");
                        Console.WriteLine("-=-=Session info=-=-");
                        Console.WriteLine("Source file: " + argument.Value);
                        Console.WriteLine("Output file: " + outputFile);
                        Console.WriteLine("Libraries location: " + links);
                        Console.WriteLine("Use optimizer: " + optimize.ToString());
                        Console.WriteLine("Use tracer: " + useTracer.ToString());
                        Console.WriteLine("Target: {0}", target.Value());
                        Console.WriteLine("---Verbose mode---");
                    }
                    Assembly assembly = new Assembly(argument.Value);
                    Utilities.Utilities.VerbouseOut("Parsing finished");
                    if (optimize)
                    {
                        Optimizer.Optimizer opt = new Optimizer.Optimizer(assembly);
                        Utilities.Utilities.VerbouseOut("Optimiztion finished");
                    }
                    //Output
                    Utilities.Utilities.VerbouseOut("-=-=Writing=-=-");
                    if (makeBinary)
                    {
                        CodeIO.WriteAssembly(assembly.Linker());
                    }
                    else
                    {
                        CodeIO.WriteSource(assembly.Linker());
                    }
                    Utilities.Utilities.VerbouseOut("DONE");
                }
                else
                {
                    commandLine.ShowHint();
                }
                return(0);
            });
            commandLine.Execute(args);
        }