Example #1
0
        void GenerateCode(Node node, Parser.ValueNode value)
        {
            // Push a value onto the stack

            switch (value.value.type) {
            case Value.Type.Number:
                Emit (node, ByteCode.PushNumber, value.value.numberValue);
                break;
            case Value.Type.String:
                var id = program.RegisterString (value.value.stringValue, node.name);
                Emit (node, ByteCode.PushString, id);
                break;
            case Value.Type.Bool:
                Emit (node, ByteCode.PushBool, value.value.boolValue);
                break;
            case Value.Type.Variable:
                Emit (node, ByteCode.PushVariable, value.value.variableName);
                break;
            case Value.Type.Null:
                Emit (node, ByteCode.PushNull);
                break;
            default:
                throw new ArgumentOutOfRangeException ();
            }
        }
Example #2
0
        void GenerateCode(Node node, Parser.AssignmentStatement statement)
        {
            // Is it a straight assignment?
            if (statement.operation == TokenType.EqualToOrAssign) {
                // Evaluate the expression, which will result in a value
                // on the stack
                GenerateCode (node, statement.valueExpression);

                // Stack now contains [destinationValue]
            } else {

                // It's a combined operation-plus-assignment

                // Get the current value of the variable
                Emit(node, ByteCode.PushVariable, statement.destinationVariableName);

                // Evaluate the expression, which will result in a value
                // on the stack
                GenerateCode (node, statement.valueExpression);

                // Stack now contains [currentValue, expressionValue]

                switch (statement.operation) {

                case TokenType.AddAssign:
                    Emit (node, ByteCode.CallFunc, TokenType.Add.ToString ());
                    break;
                case TokenType.MinusAssign:
                    Emit (node, ByteCode.CallFunc, TokenType.Minus.ToString ());
                    break;
                case TokenType.MultiplyAssign:
                    Emit (node, ByteCode.CallFunc, TokenType.Multiply.ToString ());
                    break;
                case TokenType.DivideAssign:
                    Emit (node, ByteCode.CallFunc, TokenType.Divide.ToString ());
                    break;
                default:
                    throw new ArgumentOutOfRangeException ();
                }

                // Stack now contains [destinationValue]
            }

            // Store the top of the stack in the variable
            Emit(node, ByteCode.StoreVariable, statement.destinationVariableName);

            // Clean up the stack
            Emit (node, ByteCode.Pop);
        }
Example #3
0
        void GenerateCode(Node node, Parser.Expression expression)
        {
            // Expressions are either plain values, or function calls
            switch (expression.type) {
            case Parser.Expression.Type.Value:
                // Plain value? Emit that
                GenerateCode (node, expression.value);
                break;
            case Parser.Expression.Type.FunctionCall:
                // Evaluate all parameter expressions (which will
                // push them to the stack)
                foreach (var parameter in expression.parameters) {
                    GenerateCode (node, parameter);
                }
                // If this function has a variable number of parameters, put
                // the number of parameters that were passed onto the stack
                if (expression.function.paramCount == -1) {
                    Emit (node, ByteCode.PushNumber, expression.parameters.Count);
                }

                // And then call the function
                Emit (node, ByteCode.CallFunc, expression.function.name);
                break;
            }
        }
Example #4
0
        void GenerateCode(Node node, Parser.IfStatement statement)
        {
            // We'll jump to this label at the end of every clause
            var endOfIfStatementLabel = RegisterLabel ("endif");

            foreach (var clause in statement.clauses) {
                var endOfClauseLabel = RegisterLabel ("skipclause");

                if (clause.expression != null) {

                    GenerateCode (node, clause.expression);

                    Emit (node, ByteCode.JumpIfFalse, endOfClauseLabel);

                }

                GenerateCode (node, clause.statements);

                Emit (node, ByteCode.JumpTo, endOfIfStatementLabel);

                if (clause.expression != null) {
                    Emit (node, ByteCode.Label, endOfClauseLabel);
                }
                // Clean up the stack by popping the expression that was tested earlier
                if (clause.expression != null) {
                    Emit (node, ByteCode.Pop);
                }
            }

            Emit (node, ByteCode.Label, endOfIfStatementLabel);
        }
Example #5
0
        void GenerateCode(Node node, Parser.OptionStatement statement)
        {
            var destination = statement.destination;

            if (statement.label == null) {
                // this is a jump to another node
                Emit(node, ByteCode.RunNode, destination);
            } else {
                var stringID = program.RegisterString (statement.label, node.name);

                Emit (node, ByteCode.AddOption, stringID, destination);
            }
        }
Example #6
0
        void GenerateCode(Node node, Parser.ShortcutOptionGroup statement)
        {
            var endOfGroupLabel = RegisterLabel ("group_end");

            var labels = new List<string> ();

            int optionCount = 0;
            foreach (var shortcutOption in statement.options) {

                var optionDestinationLabel = RegisterLabel ("option_" + (optionCount+1));
                labels.Add (optionDestinationLabel);

                string endOfClauseLabel = null;

                if (shortcutOption.condition != null) {
                    endOfClauseLabel = RegisterLabel ("conditional_"+optionCount);
                    GenerateCode (node, shortcutOption.condition);

                    Emit (node, ByteCode.JumpIfFalse, endOfClauseLabel);
                }

                var labelStringID = program.RegisterString (shortcutOption.label, node.name);

                Emit (node, ByteCode.AddOption, labelStringID, optionDestinationLabel);

                if (shortcutOption.condition != null) {
                    Emit (node, ByteCode.Label, endOfClauseLabel);
                    Emit (node, ByteCode.Pop);
                }

                optionCount++;
            }

            Emit (node, ByteCode.ShowOptions);

            if (flags.DisableShuffleOptionsAfterNextSet == true) {
                Emit (node, ByteCode.PushBool, false);
                Emit (node, ByteCode.StoreVariable, VirtualMachine.SpecialVariables.ShuffleOptions);
                Emit (node, ByteCode.Pop);
                flags.DisableShuffleOptionsAfterNextSet = false;
            }

            Emit (node, ByteCode.Jump);

            optionCount = 0;
            foreach (var shortcutOption in statement.options) {

                Emit (node, ByteCode.Label, labels [optionCount]);

                if (shortcutOption.optionNode != null)
                    GenerateCode (node, shortcutOption.optionNode.statements);

                Emit (node, ByteCode.JumpTo, endOfGroupLabel);

                optionCount++;

            }

            // reached the end of the option group
            Emit (node, ByteCode.Label, endOfGroupLabel);

            // clean up after the jump
            Emit (node, ByteCode.Pop);
        }
Example #7
0
        void GenerateCode(Node node, IEnumerable<Yarn.Parser.Statement> statementList)
        {
            if (statementList == null)
                return;

            foreach (var statement in statementList) {
                GenerateCode (node, statement);
            }
        }
Example #8
0
        void GenerateCode(Node node, Parser.CustomCommand statement)
        {
            // If this command is an evaluable expression, evaluate it
            if (statement.expression != null) {
                GenerateCode (node, statement.expression);
            } else {
                switch (statement.clientCommand) {
                case "stop":
                    Emit (node, ByteCode.Stop);
                    break;
                case "shuffleNextOptions":
                    // Emit code that sets "VAR_SHUFFLE_OPTIONS" to true
                    Emit (node, ByteCode.PushBool, true);
                    Emit (node, ByteCode.StoreVariable, VirtualMachine.SpecialVariables.ShuffleOptions);
                    Emit (node, ByteCode.Pop);
                    flags.DisableShuffleOptionsAfterNextSet = true;
                    break;

                default:
                    Emit (node, ByteCode.RunCommand, statement.clientCommand);
                    break;
                }
            }
        }
Example #9
0
        void GenerateCode(Node node, string line)
        {
            var num = program.RegisterString (line, node.name);

            Emit (node, ByteCode.RunLine, num);
        }
Example #10
0
        // Statements
        void GenerateCode(Node node, Parser.Statement statement)
        {
            switch (statement.type) {
            case Parser.Statement.Type.CustomCommand:
                GenerateCode (node, statement.customCommand);
                break;
            case Parser.Statement.Type.ShortcutOptionGroup:
                GenerateCode (node, statement.shortcutOptionGroup);
                break;
            case Parser.Statement.Type.Block:

                // Blocks are just groups of statements
                foreach (var blockStatement in statement.block.statements) {
                    GenerateCode(node, blockStatement);
                }

                break;

            case Parser.Statement.Type.IfStatement:
                GenerateCode (node, statement.ifStatement);
                break;

            case Parser.Statement.Type.OptionStatement:
                GenerateCode (node, statement.optionStatement);
                break;

            case Parser.Statement.Type.AssignmentStatement:
                GenerateCode (node, statement.assignmentStatement);
                break;

            case Parser.Statement.Type.Line:
                GenerateCode (node, statement.line);
                break;

            default:
                throw new ArgumentOutOfRangeException ();
            }
        }
Example #11
0
        void Emit(Node node, ByteCode code, object operandA = null, object operandB = null)
        {
            var instruction = new Instruction();
            instruction.operation = code;
            instruction.operandA = operandA;
            instruction.operandB = operandB;

            node.instructions.Add (instruction);

            if (code == ByteCode.Label) {
                // Add this label to the label table
                node.labels.Add ((string)instruction.operandA, node.instructions.Count - 1);
            }
        }
Example #12
0
        internal void CompileNode(Parser.Node node)
        {
            if (program.nodes.ContainsKey(node.name)) {
                throw new ArgumentException ("Duplicate node name " + node.name);
            }

            var compiledNode =  new Node();

            compiledNode.name = node.name;

            var startLabel = RegisterLabel ();
            Emit (compiledNode, ByteCode.Label, startLabel);

            foreach (var statement in node.statements) {
                GenerateCode (compiledNode, statement);
            }

            // Does this node end after emitting AddOptions codes
            // without calling ShowOptions?

            // Note: this only works when we know that we don't have
            // AddOptions and then Jump up back into the code to run them.
            // TODO: A better solution would be for the parser to flag
            // whether a node has Options at the end.
            var hasRemainingOptions = false;
            foreach (var instruction in compiledNode.instructions) {
                if (instruction.operation == ByteCode.AddOption) {
                    hasRemainingOptions = true;
                }
                if (instruction.operation == ByteCode.ShowOptions) {
                    hasRemainingOptions = false;
                }
            }

            // If this compiled node has no lingering options to show at the end of the node, then stop at the end
            if (hasRemainingOptions == false) {
                Emit (compiledNode, ByteCode.Stop);
            } else {
                // Otherwise, show the accumulated nodes and then jump to the selected node

                Emit (compiledNode, ByteCode.ShowOptions);

                if (flags.DisableShuffleOptionsAfterNextSet == true) {
                    Emit (compiledNode, ByteCode.PushBool, false);
                    Emit (compiledNode, ByteCode.StoreVariable, VirtualMachine.SpecialVariables.ShuffleOptions);
                    Emit (compiledNode, ByteCode.Pop);
                    flags.DisableShuffleOptionsAfterNextSet = false;
                }

                Emit (compiledNode, ByteCode.RunNode);
            }

            if (node.source != null) {
                compiledNode.sourceTextStringID = program.RegisterString (node.source, node.name);
            }

            program.nodes [compiledNode.name] = compiledNode;
        }
        public bool SetNode(string nodeName)
        {
            if (program.nodes.ContainsKey(nodeName) == false) {

                var error = "No node named " + nodeName;
                dialogue.LogErrorMessage(error);
                executionState = ExecutionState.Stopped;
                return false;
            }

            dialogue.LogDebugMessage ("Running node " + nodeName);

            // Clear the special variables
            dialogue.continuity.SetValue(SpecialVariables.ShuffleOptions, new Value(false));

            currentNode = program.nodes [nodeName];
            ResetState ();
            state.currentNodeName = nodeName;

            return true;
        }
Example #14
0
            internal ShortcutOption(int optionIndex, ParseNode parent, Parser p)
                : base(parent, p)
            {
                p.ExpectSymbol(TokenType.ShortcutOption);
                label = p.ExpectSymbol(TokenType.Text).value as string;

                // Parse the conditional ("<<if $foo>>") if it's there
                if (p.NextSymbolsAre(TokenType.BeginCommand, TokenType.If)) {
                    p.ExpectSymbol(TokenType.BeginCommand);
                    p.ExpectSymbol(TokenType.If);
                    condition = Expression.Parse(this, p);
                    p.ExpectSymbol(TokenType.EndCommand);
                }

                // Parse the statements belonging to this option if it has any
                if (p.NextSymbolIs(TokenType.Indent)) {
                    p.ExpectSymbol(TokenType.Indent);
                    optionNode = new Node(NodeParent().name + "." + optionIndex, this, p);
                    p.ExpectSymbol(TokenType.Dedent);
                }
            }