示例#1
0
        static int Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("Error: First argument of program must be the script to be parsed");
                Console.WriteLine("\nI suggest using this script for testing: https://github.com/07th-mod/umineko-question/raw/master/InDevelopment/ManualUpdates/0.utf");
                Console.WriteLine("\nVisual Studio users can follow these instructions to set program arguments: https://stackoverflow.com/questions/298708/debugging-with-command-line-parameters-in-visual-studio");
                Console.ReadKey();
                return(-1);
            }

            // Read input script
            string inputFilePath = args[0];

            Console.WriteLine($"Processing input file [{inputFilePath}]");
            string[] lines = File.ReadAllLines(inputFilePath);

            // First pass of script is to build the function database
            SubroutineDatabase database = UserFunctionScanner.buildInitialUserList(lines, new SubroutineDatabase());

            // Add predefined functions. If a function already exists, it will be added with an '_' prefix
            PredefinedFunctionInfoLoader.load("function_list.txt", database);

            // Add some extra pre-defined functions
            database["langen"]     = new SubroutineInformation(false);
            database["langjp"]     = new SubroutineInformation(false);
            database["showlangen"] = new SubroutineInformation(false);
            database["showlangjp"] = new SubroutineInformation(false);
            database["langall"]    = new SubroutineInformation(false); //TODO: not sure if this is a real function or a typo. Only occurs once in umineko question script.

            database["endroll"]         = new SubroutineInformation(true);
            database["steamsetachieve"] = new SubroutineInformation(true);
            database["getreadlang"]     = new SubroutineInformation(true);
            database["say"]             = new SubroutineInformation(true);
            database["tachistate"]      = new SubroutineInformation(true);


            foreach (KeyValuePair <string, SubroutineInformation> kvp in database.GetRawDict())
            {
                Console.WriteLine($"{kvp.Key}: {kvp.Value.hasArguments}");
            }

            bool dumpNodes = true;
            bool error     = true;

            if (dumpNodes)
            {
                string savePath = @"ponscripter_script_nodes.txt";
                error = DumpTopLevelNodes(lines, database, savePath);
            }
            else
            {
                error = CompileScript(lines, database);
            }

            return(error ? -2 : 0);
        }
        public bool TryAdd(string sAnyCase, SubroutineInformation value)
        {
            string s = NormalizeKey(sAnyCase);

            if (subroutineInfoDict.ContainsKey(s))
            {
                //Console.WriteLine($"WARNING: duplicate defsub found for {s}");
                duplicateDefsubs.Add(s);
                return(false);
            }
            else
            {
                subroutineInfoDict.Add(s, value);
                return(true);
            }
        }
        public bool TryGetValue(string sAnyCase, out SubroutineInformation output)
        {
            if (InnerTryGetValue(sAnyCase, out SubroutineInformation subroutineInformation))
            {
                output = subroutineInformation;
                return(true);
            }
            else if (sAnyCase.StartsWith("_") && InnerTryGetValue(sAnyCase.Substring(1), out SubroutineInformation underscoreSubroutineInformation))
            {
                output = underscoreSubroutineInformation;
                Console.WriteLine($"WARNING: it appears the function {sAnyCase} is called with an underscore, even though it is not overriden");
                return(true);
            }

            output = null;
            return(false);
        }
        /// <summary>
        /// Scan the entire script for subroutine declarations and definitions
        /// </summary>
        /// <param name="allLines"></param>
        public static SubroutineDatabase buildInitialUserList(string[] allLines, SubroutineDatabase database)
        {
            List <LabelInfo> labels = new List <LabelInfo>();

            //scan for subroutines definitions and labels
            for (int i = 0; i < allLines.Length; i++)
            {
                string s = allLines[i];

                Match defsubMatch = defsubRegex.Match(s);
                Match labelMatch  = labelRegex.Match(s);

                if (defsubMatch.Success)
                {
                    //search the script for "defsub ut_mld2" type calls. store each in a hashmap
                    string subName = defsubMatch.Groups[1].Value;
                    Console.WriteLine($"Got sub definition {subName}");

                    if (!database.TryAdd(subName, null))
                    {
                        Console.WriteLine($"WARNING: duplicate defsub found for {subName}");
                    }
                }
                else if (labelMatch.Success)
                {
                    string labelName = labelMatch.Groups[1].Value;
                    Console.WriteLine($"Got label definition {labelName}");
                    labels.Add(new LabelInfo(labelName, i));
                }
            }

            //iterate starting at the label definition until (worst case) the end of file
            //when a getparam or return is found, the number of parameters is recorded
            SubroutineInformation GetSubroutineInformation(string[] linesToSearch, LabelInfo label)
            {
                for (int i = label.labelLineIndex; i < linesToSearch.Length; i++)
                {
                    string s = linesToSearch[i];

                    Match getParamMatch = getParamRegex.Match(s);
                    Match returnMatch   = returnRegex.Match(s);

                    if (getParamMatch.Success)
                    {
                        Console.WriteLine($"{label.labelName} arguments are {getParamMatch.Groups[0].Value} [{s}]");
                        return(new SubroutineInformation(getParamMatch.Groups[0].Value));
                    }
                    else if (returnMatch.Success)
                    {
                        Console.WriteLine($"{label.labelName} takes no arguments");
                        return(new SubroutineInformation(hasArguments: false));
                    }
                }

                //somehow reached end of the document
                return(null);
            }

            //For reach subroutine, determine what arguments (if any) it uses
            //May not work for all cases, but usually getparam is the first call
            //after the label def so use this method for now.
            foreach (LabelInfo label in labels)
            {
                //Only process subroutine definitions, not ordinary labels
                if (!database.InnerTryGetValue(label.labelName, out _))
                {
                    continue;
                }

                Console.WriteLine($"{label.labelName} is a subroutine");

                SubroutineInformation subInfo = GetSubroutineInformation(allLines, label);

                if (subInfo == null)
                {
                    Console.WriteLine($"ERROR: no return or getparam for subroutine {label.labelName}");
                }
                else
                {
                    database[label.labelName] = subInfo;
                }
            }

            return(database);
        }
 //TODO: tidy this up later...
 public bool InnerTryGetValue(string sAnyCase, out SubroutineInformation output)
 {
     return(subroutineInfoDict.TryGetValue(NormalizeKey(sAnyCase), out output));
 }