コード例 #1
0
        protected Expression ToExpression(DataElement element)
        {
            switch (element)
            {
            case DataElement.Ctrl ctrl:
                return(new JumpLabelExpr {
                    LabelStmt = new JumpLabelStmt {
                        Name = ctrl.Name.StringValue.EscapeIdentifier()
                    }
                });

            case DataElement.CInt cint when cint.Value.IsPointer:
                return(new PointerLiteral {
                    PointerId = cint.Value.PointerId
                });

            case DataElement.CInt cint:
                return(new IntegerLiteral {
                    Value = cint.Value.IntValue
                });

            case DataElement.CStr cstr:
                return(new StringLiteral {
                    Value = cstr.Value.StringValue
                });

            case DataElement.SStr sstr:
                return(new Variable {
                    VariableType = sstr.FlagType.StringValue
                });

            case DataElement.VInt vint when vint.FlagId.IsPointer:
                return(new VariablePointer {
                    VariableType = vint.FlagType.StringValue, PointerId = vint.FlagId.PointerId
                });

            case DataElement.VInt vint:
                return(new Variable {
                    VariableType = vint.FlagType.StringValue, VariableId = vint.FlagId.IntValue
                });

            case DataElement.VStr vstr when vstr.FlagId.IsPointer:
                return(new VariablePointer {
                    VariableType = vstr.FlagType.StringValue, PointerId = vstr.FlagId.PointerId
                });

            case DataElement.VStr vstr:
                return(new Variable {
                    VariableType = vstr.FlagType.StringValue, VariableId = vstr.FlagId.IntValue
                });

            case DataElement.VLoc vloc:
                if (!_locals.ContainsKey(vloc.Id))
                {
                    throw new FormatException("Use of undefined local variable");
                }
                var local = _locals[vloc.Id];
                if (local == null)
                {
                    throw new FormatException("Repeated use of the same local variable");
                }
                _locals[vloc.Id] = null;
                return(local);

            default:
                throw new FormatException("Invalid expression element: " + element.Type);
            }
        }
コード例 #2
0
 public AssignmentScriptElement(DataElement var, ScriptElement expression)
 {
     this.var        = var;
     this.expression = expression;
 }
コード例 #3
0
 public DataScriptElement(DataElement elem)
 {
     this.elem = elem;
 }
コード例 #4
0
        /**
         * Reads the next script element from the stream.
         * This could be an entire command or a single parameter.
         */
        ScriptElement NextScriptElement(Stream s)
        {
            BinaryReader  br   = new BinaryReader(s);
            ScriptElement elem = null;

            // read the next data element.
            DataElement cmd = NextDataElement(s);

            // if no data element could be found, ...
            if (cmd == null)
            {
                // ...return nothing.
                return(null);
            }

            // if the element is...
            switch (cmd.type)
            {
            // ...a function call, then...
            case DataElement.TYPE_FUNC: {
                // ...determine how many parameters the function call takes.
                int             paramCount = br.ReadInt32();
                ScriptElement[] parameters = new ScriptElement[paramCount];

                // for each parameter...
                for (var j = 0; j < paramCount; j++)
                {
                    // ...read it's value
                    DataElement param = NextDataElement(s);

                    // if the parameter is a temporary variable reference, then...
                    if (param is VarTempRefDataElement)
                    {
                        // ...replace it by the appropriate substitution expression.
                        parameters[j] = substituteExpressions[((VarTempRefDataElement)param).id];
                        // after that, continue with the next parameter.
                        continue;
                    }

                    // if the function is called...
                    // ..."StrOut" and this parameter is a string, ...
                    if ((((FuncDataElement)cmd).name.Equals("StrOut") || ((FuncDataElement)cmd).name.Equals("StrOutNW")) && param is StringDataElement)
                    {
                        // (...then this is a line of text to be displayed.)
                        // (we want to store those in a separate file to make it easier to translate them.)

                        // get the text
                        string line = ((StringDataElement)param).data;
                        // generate a new line number
                        string id = "L" + (++lineCount);
                        // add those to the list of known strings...
                        stringTable.Add(id, new ScriptLine(fontID, speaker, line));
                        // ...and replace the string parameter with reference to the line number
                        parameters[j] = new DataScriptElement(new ExternalStringDataElement(id, stringTable));
                    }
                    // ..."StrOutNWC", ...
                    else if (((FuncDataElement)cmd).name.Equals("StrOutNWC"))
                    {
                        // (...then this parameter represents a name.)
                        // if the parameter is...
                        // ...a string, then...
                        if (param is StringDataElement)
                        {
                            // (...we want to store it separately to make it easier to translate.)
                            string name = ((StringDataElement)param).data;
                            // set the current speaker to this name.
                            speaker = name;
                            string id = null;
                            // for each entry on our list of known strings...
                            foreach (var entry in stringTable)
                            {
                                // ...check if it is a name.
                                if (entry.Key[0] == 'N' && entry.Value.Text.Equals(name))
                                {
                                    // if it is, remember it's ID...
                                    id = entry.Key;
                                    // ...and stop searching.
                                    break;
                                }
                            }
                            // if you didn't find a matching ID, ...
                            if (id == null)
                            {
                                // generate a new one...
                                id = "N" + (++nameCount);
                                // ...and add it - together with the name - to the list of known strings.
                                stringTable.Add(id, new ScriptLine(-1, null, name));
                            }
                            // finally, replace the parameter by a reference to the name ID.
                            parameters[j] = new DataScriptElement(new ExternalStringDataElement(id, stringTable));
                        }
                        // ...a variable string reference, then...
                        else if (param is VarStringRefDataElement)
                        {
                            // ...set the current speaker to "me"...
                            speaker = "me";
                            // ...and keep the parameter as it is.
                            parameters[j] = new DataScriptElement(param);
                        }
                        // ...something else, ...
                        else
                        {
                            // ...then we just keep it as it is.
                            parameters[j] = new DataScriptElement(param);
                        }
                    }
                    // ...none of the above, ...
                    else
                    {
                        // ...then we just keep the parameter as it is.
                        parameters[j] = new DataScriptElement(param);
                    }
                }

                // if the function is called "PF" (PrintFlush?), then...
                if (((FuncDataElement)cmd).name.Equals("PF"))
                {
                    // ...reset the current speaker.
                    speaker = "";
                }

                // if the function is called "FontSet" and the second parameter is an integer, then...
                if (((FuncDataElement)cmd).name.Equals("FontSet") && parameters.Length >= 2 && parameters[1] is DataScriptElement dataElem && dataElem.elem is IntDataElement intElem)
                {
                    // ...keep track of the current font
                    fontID = intElem.data;
                }

                // save the current position in the code stream.
                long pos = s.Position;
                // read the next data element
                DataElement next = NextDataElement(s);
                // check if the next data element is a opening control flow element.
                // if it is, then...
                if (next is ControlDataElement && ((ControlDataElement)next).name.Equals("{"))
                {
                    // ...create an empty list of script elements.
                    List <ScriptElement> body = new List <ScriptElement>();

                    ScriptElement cur;
                    // (read script elements and add them to the list of commands until you encounter a closing flow control element.)
                    // repeat:
                    while (true)
                    {
                        // read the next script element.
                        cur = NextScriptElement(s);
                        // if it is a closing flow control element, ...
                        if (cur is JumpLabelScriptElement && ((JumpLabelScriptElement)cur).name.Equals("}"))
                        {
                            // ...stop repeating immediately
                            break;
                        }
                        // otherwise, add it to the list of commands.
                        body.Add(cur);
                    }

                    // if the function is a branching operation, then...
                    if (((FuncDataElement)cmd).name.Equals("if"))
                    {
                        // ...save the current position in the code stream.
                        pos = s.Position;
                        // read the next data element
                        next = NextDataElement(s);
                        // check if the next data element is a else clause.
                        // if it is, then...
                        if (next is ControlDataElement && ((ControlDataElement)next).name.Equals("else"))
                        {
                            // ...discard the opening flow control element.
                            NextDataElement(s);
                            // ...create an empty list of script elements.
                            List <ScriptElement> falsebody = new List <ScriptElement>();

                            // (read script elements and add them to the list of commands until you encounter a closing flow control element.)
                            // repeat:
                            while (true)
                            {
                                // read the next script element.
                                cur = NextScriptElement(s);
                                // if it is a closing flow control element, ...
                                if (cur is JumpLabelScriptElement && ((JumpLabelScriptElement)cur).name.Equals("}"))
                                {
                                    // ...stop repeating immediately
                                    break;
                                }
                                // otherwise, add it to the list of commands.
                                falsebody.Add(cur);
                            }
                            // use the first (and only) parameter of the function call as branching condition, wrap it - together with the code blocks - in a script element and save it as the result.
                            elem = new BranchScriptElement(parameters[0], body, falsebody);
                        }
                        // it it's not, then...
                        else
                        {
                            // ...jump back to the previously saved code position.
                            s.Seek(pos, SeekOrigin.Begin);
                            // use the first (and only) parameter of the function call as branching condition, wrap it - together with the code block - in a script element and save it as the result.
                            elem = new BranchScriptElement(parameters[0], body, null);
                        }
                    }
                    // if it it not, then
                    else
                    {
                        elem = new SwitchFunctionScriptElement(((FuncDataElement)cmd).name, parameters, body);
                    }
                }
                // if not, ...
                else
                {
                    // ...jump back to the previously saved code position.
                    s.Seek(pos, SeekOrigin.Begin);
                    // wrap the method name and and list of parameters in a script element and save it as the result.
                    elem = new FuncCallScriptElement(((FuncDataElement)cmd).name, parameters);
                }
                break;
            }

            // ...a flow control element, then...
            case DataElement.TYPE_CTRL: {
                // ...create a new jump label with the same name and save it as the result.
                elem = new JumpLabelScriptElement(((ControlDataElement)cmd).name);
                break;
            }

            // ...a variable int or string reference, then...
            case DataElement.TYPE_VINT:
            case DataElement.TYPE_VSTR: {
                // (...we expect an assignment operation to follow.)
                // read assigned expression.
                ScriptElement expression = NextAssignment(s);
                // wrap the variable int/string reference and the expression in a new script element and save it as the result.
                elem = new AssignmentScriptElement(cmd, expression);
                break;
            }

            // ...a temporary variable id, then...
            case DataElement.TYPE_VTMP: {
                // (...we expect an assignment operation to follow.)
                // (after that we expect a command which uses this temporary variable.)
                // read assigned expression.
                ScriptElement expression = NextAssignment(s);
                // set the current temp variable expression to the one we just read...
                substituteExpressions[((VarTempRefDataElement)cmd).id] = expression;
                // ...and return nothing this time.
                break;
            }

            // ...an integer constant, then...
            case DataElement.TYPE_CINT: {
                // (...we have reached a very confusing part of this binary script format.)
                // (we expect an assignment to follow, basically "0 = <something>".)
                // (this sets the current flag pointer (represented by the 0) to <something>.)
                // (the flag pointed to by the pointer can be a accessed by using flag_$, globalflag_$, str_$ or globalstr_$.)
                // read the next script element (the expected assignment).
                FuncCallScriptElement assignment = NextScriptElement(s) as FuncCallScriptElement;
                ScriptElement         expression = null;

                // if the assignment has...
                // ...more than 1 element, ...
                if (assignment.parameters.Length > 1)
                {
                    // ...then create an expression from those.
                    expression = new ExpressionScriptElement(assignment.parameters);
                }
                // ...exactly 1 element, ...
                else if (assignment.parameters.Length == 1)
                {
                    // ...then it already is a valid expression.
                    expression = assignment.parameters[0];
                }
                // ...no elements, ...
                else
                {
                    // ...then read the next script element and use it as expression.
                    expression = NextScriptElement(s);
                }

                // wrap the integer and the expression in a new script element and save it as the result.
                elem = new AssignmentScriptElement(cmd, expression);
                break;
            }

            // ...something else, ...
            default: {
                // the script is probably damaged, so we throw an error.
                throw new Exception("Script format invalid");
            }
            }

            // return the saved result
            return(elem);
        }
コード例 #5
0
ファイル: Compiler.cs プロジェクト: wmltogether/yukatool
        /// <summary>
        /// Flattens nested script elements to a list
        /// </summary>
        /// <param name="elem">The element to flatten</param>
        /// <param name="nested">Whether this is NOT a top-level element</param>
        /// <returns>The flattened list of elements</returns>
        List <ScriptElement> Flatten(ScriptElement elem, bool nested)
        {
            List <ScriptElement> list = new List <ScriptElement>();

            if (elem is FuncCallScriptElement)
            {
                // new parameter array
                ScriptElement[] parameters = new ScriptElement[(elem as FuncCallScriptElement).parameters.Length];

                for (int i = 0; i < parameters.Length; i++)
                {
                    ScriptElement param = (elem as FuncCallScriptElement).parameters[i];
                    if (param is DataScriptElement)
                    {
                        parameters[i] = param;
                    }
                    else
                    {
                        // flatten all non-data parameters
                        list.AddRange(Flatten(param, true));
                        parameters[i] = new DataScriptElement(new VarTempRefDataElement(tempVarID - 1));
                    }
                }

                if (nested)
                {
                    list.Add(new DataScriptElement(new VarTempRefDataElement(tempVarID++)));
                    list.Add(new FuncCallScriptElement("=", new ScriptElement[0]));
                }
                list.Add(new FuncCallScriptElement((elem as FuncCallScriptElement).name, parameters));
            }
            else if (elem is ExpressionScriptElement)
            {
                ScriptElement[] parameters = new ScriptElement[(elem as ExpressionScriptElement).parameters.Length + (elem as ExpressionScriptElement).operators.Length];

                for (int i = 0; i < (elem as ExpressionScriptElement).parameters.Length; i++)
                {
                    if (i > 0)
                    {
                        string op = (elem as ExpressionScriptElement).operators[i - 1];
                        if (op.Equals("=="))
                        {
                            op = "=";
                        }
                        parameters[i * 2 - 1] = new DataScriptElement(new ControlDataElement(op));
                    }
                    ScriptElement param = (elem as ExpressionScriptElement).parameters[i];
                    if (param is DataScriptElement)
                    {
                        parameters[i * 2] = param;
                    }
                    else
                    {
                        // flatten all non-data parameters
                        list.AddRange(Flatten(param, true));
                        parameters[i * 2] = new DataScriptElement(new VarTempRefDataElement(tempVarID - 1));
                    }
                }

                list.Add(new DataScriptElement(new VarTempRefDataElement(tempVarID++)));
                list.Add(new FuncCallScriptElement("=", parameters));
            }
            else if (elem is BranchScriptElement)
            {
                ScriptElement cond = (elem as BranchScriptElement).condition;

                if (!(cond is DataScriptElement))
                {
                    list.AddRange(Flatten(cond, true));
                    cond = new DataScriptElement(new VarTempRefDataElement(tempVarID - 1));
                }

                ControlDataElement openingThen = new ControlDataElement("{"), closingThen = new ControlDataElement("}"), openingElse = null, closingElse = null;
                if ((elem as BranchScriptElement).falsebody != null)
                {
                    openingElse      = new ControlDataElement("{");
                    closingElse      = new ControlDataElement("}");
                    openingThen.link = openingElse;
                    closingThen.link = openingThen;
                    openingElse.link = closingElse;
                    closingElse.link = openingElse;
                }
                else
                {
                    openingThen.link = closingThen;
                    closingThen.link = openingThen;
                }

                list.Add(new FuncCallScriptElement("if", new ScriptElement[] { cond }));

                list.Add(new DataScriptElement(openingThen));
                foreach (ScriptElement cmd in (elem as BranchScriptElement).truebody)
                {
                    list.AddRange(Flatten(cmd, false));
                }
                list.Add(new DataScriptElement(closingThen));

                if ((elem as BranchScriptElement).falsebody != null)
                {
                    list.Add(new DataScriptElement(new ControlDataElement("else")));
                    list.Add(new DataScriptElement(openingElse));
                    foreach (ScriptElement cmd in (elem as BranchScriptElement).falsebody)
                    {
                        list.AddRange(Flatten(cmd, false));
                    }
                    list.Add(new DataScriptElement(closingElse));
                }
            }
            else if (elem is SwitchFunctionScriptElement)
            {
                // new parameter array
                ScriptElement[] parameters = new ScriptElement[(elem as SwitchFunctionScriptElement).parameters.Length];

                for (int i = 0; i < parameters.Length; i++)
                {
                    ScriptElement param = (elem as SwitchFunctionScriptElement).parameters[i];
                    if (param is DataScriptElement)
                    {
                        parameters[i] = param;
                    }
                    else
                    {
                        // flatten all non-data parameters
                        list.AddRange(Flatten(param, true));
                        parameters[i] = new DataScriptElement(new VarTempRefDataElement(tempVarID - 1));
                    }
                }

                list.Add(new FuncCallScriptElement((elem as SwitchFunctionScriptElement).name, parameters));
                ControlDataElement opening = new ControlDataElement("{");
                ControlDataElement closing = new ControlDataElement("}");
                opening.link = closing;
                closing.link = opening;

                list.Add(new DataScriptElement(opening));
                foreach (ScriptElement cmd in (elem as SwitchFunctionScriptElement).body)
                {
                    list.AddRange(Flatten(cmd, false));
                }
                list.Add(new DataScriptElement(closing));
            }
            else if (elem is AssignmentScriptElement)
            {
                ScriptElement expr = (elem as AssignmentScriptElement).expression;
                DataElement   var  = (elem as AssignmentScriptElement).var;

                if (expr is DataScriptElement)
                {
                    // special exception for the $ variable (e.g. clear_main.yks)
                    if (var is IntDataElement)
                    {
                        list.Add(new DataScriptElement(new VarTempRefDataElement(tempVarID++)));
                        list.Add(new FuncCallScriptElement("=", new[] { expr }));
                        list.Add(new DataScriptElement(var));
                        list.Add(new FuncCallScriptElement("=", new[] { new DataScriptElement(new VarTempRefDataElement(tempVarID - 1)) }));
                    }
                    else
                    {
                        list.Add(new DataScriptElement(var));
                        list.Add(new FuncCallScriptElement("=", new[] { expr }));
                    }
                }
                else
                {
                    List <ScriptElement> cmds = Flatten(expr, true);
                    // special exception for the $ variable (e.g. clear_main.yks)
                    if (var is IntDataElement)
                    {
                        list.AddRange(cmds);
                        list.Add(new DataScriptElement(var));
                        list.Add(new FuncCallScriptElement("=", new[] { new DataScriptElement(new VarTempRefDataElement(tempVarID - 1)) }));
                    }
                    else
                    {
                        // replace the last temp var reference by the variable
                        for (int i = cmds.Count - 1; i >= 0; i--)
                        {
                            if (cmds[i] is DataScriptElement && (cmds[i] as DataScriptElement).elem is VarTempRefDataElement)
                            {
                                cmds[i] = new DataScriptElement((elem as AssignmentScriptElement).var);
                                list.AddRange(cmds);
                                return(list);
                            }
                        }
                        throw new Exception("No VarTempRefDataElement found");
                    }
                }
            }
            else if (elem is JumpLabelScriptElement)
            {
                list.Add(new DataScriptElement(new ControlDataElement((elem as JumpLabelScriptElement).name)));
            }
            return(list);
        }
コード例 #6
0
ファイル: Compiler.cs プロジェクト: wmltogether/yukatool
        /// <summary>
        /// Compiles an entire script into a binary script file (.yks)
        /// </summary>
        /// <param name="script">The script instance to compile</param>
        /// <param name="s">The output stream</param>
        /// <returns>The number of bytes written</returns>
        public long ToBinary(YukaScript script, Stream s)
        {
            long offset = s.Position;

            List <ScriptElement> flattened = new List <ScriptElement>();

            Console.ForegroundColor = ConsoleColor.Cyan;

            foreach (ScriptElement elem in script.commands)
            {
                List <ScriptElement> cmds = Flatten(elem, false);
                flattened.AddRange(cmds);
                if (cmds.Count == 0 && FlagCollection.current.Has('v'))
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("?????????????");
                    Console.ForegroundColor = ConsoleColor.Cyan;
                }
                foreach (ScriptElement cmd in cmds)
                {
                    if (cmd is DataScriptElement dse && dse.elem is ControlDataElement cde)
                    {
                        string name = cde.name;
                        if (!"else".Equals(name) && !"{".Equals(name) && !"}".Equals(name))
                        {
                            jumpLabels.Add(name, cde);
                        }
                    }
                    //Console.WriteLine(cmd);
                }
            }

            List <DataElement> code = new List <DataElement>();
            Dictionary <string, FuncDataElement> functions = new Dictionary <string, FuncDataElement>();

            foreach (ScriptElement elem in flattened)
            {
                if (elem is FuncCallScriptElement)
                {
                    string          name       = (elem as FuncCallScriptElement).name;
                    ScriptElement[] parameters = (elem as FuncCallScriptElement).parameters;

                    if (!functions.ContainsKey(name))
                    {
                        functions[name] = new FuncDataElement(name);
                    }
                    functions[name].lastOffset = code.Count;

                    code.Add(functions[name]);
                    code.Add(new RawDataElement(parameters.Length));

                    foreach (ScriptElement param in parameters)
                    {
                        if (param is DataScriptElement)
                        {
                            code.Add((param as DataScriptElement).elem);
                        }
                        else
                        {
                            throw new Exception("Expected DataScriptElement, got " + param.GetType().Name);
                        }
                    }
                }
                else if (elem is DataScriptElement)
                {
                    DataElement data = (elem as DataScriptElement).elem;

                    if (data is ControlDataElement)
                    {
                        (data as ControlDataElement).codeOffset = code.Count;
                    }

                    code.Add(data);
                }
                else
                {
                }
                if (FlagCollection.current.Has('v'))
                {
                    Console.WriteLine(elem);
                }
            }
            Console.ForegroundColor = ConsoleColor.Yellow;

            DataManager dataManager = new DataManager();
            List <Tuple <int, int, int, int> > index = new List <Tuple <int, int, int, int> >();
            List <int> codeData = new List <int>();

            foreach (DataElement elem in code)
            {
                if (elem is ControlDataElement)
                {
                    string name = (elem as ControlDataElement).name;
                    if (jumpLabels.ContainsKey(name))
                    {
                        (elem as ControlDataElement).link = jumpLabels[name];
                    }
                }

                if (elem is RawDataElement)
                {
                    codeData.Add((elem as RawDataElement).value);
                }
                else
                {
                    elem.WriteData(dataManager);
                    Tuple <int, int, int, int> entry = elem.GetIndex();
                    if (FlagCollection.current.Has('v'))
                    {
                        Console.WriteLine(entry);
                    }
                    int i = index.IndexOf(entry);
                    if (i == -1)
                    {
                        i = index.Count;
                        index.Add(entry);
                    }
                    codeData.Add(i);
                }
            }
            Console.ResetColor();

            BinaryWriter bw = new BinaryWriter(s);

            // write header
            s.Write(new byte[] { 0x59, 0x4B, 0x53, 0x30, 0x30, 0x31, 0x01, 0x00 }, 0, 8);
            s.Write(new byte[] { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 8);

            bw.Write(0x30);
            bw.Write(codeData.Count);
            bw.Write(0x30 + codeData.Count * 4);
            bw.Write(index.Count);
            bw.Write(0x30 + codeData.Count * 4 + index.Count * 16);
            bw.Write(dataManager.offset);
            bw.Write(tempVarID);
            bw.Write(0);

            // write code sector
            foreach (int cmd in codeData)
            {
                bw.Write(cmd);
            }

            // write index
            foreach (Tuple <int, int, int, int> entry in index)
            {
                bw.Write(entry.Item1);
                bw.Write(entry.Item2);
                bw.Write(entry.Item3);
                bw.Write(entry.Item4);
            }

            // write data sector
            dataManager.WriteTo(s);
            return(s.Position - offset);
        }