Ejemplo n.º 1
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            bool evaluateForSideEffectsOnly = false;

            switch (purpose)
            {
            case EvaluationIntention.SideEffectsOnly:
                evaluateForSideEffectsOnly = true;
                break;

            case EvaluationIntention.Value:
            case EvaluationIntention.ValueOrNode:
                break;

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }

            var what = Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.AddressOrNode);

            if (what == null)
            {
                // it is a temporary (and lvalue), so must be an address
                if (evaluateForSideEffectsOnly)
                {
                    // value not needed for other expression

                    // stack has: address
                    context.GenerateInstruction("IDEC");
                    // stack has: ...
                }
                else
                {
                    // stack has: address
                    context.GenerateInstruction("DUP");                                 // copy the address
                    // stack has: address, address
                    context.GenerateInstruction("Indirection");
                    // stack has: address, value
                    context.GenerateInstruction("SWAP");
                    // stack has: value, address
                    context.GenerateInstruction("IDEC");
                    // stack has: value
                }
            }
            else if (what is VariableTreeNode variable)
            {
                context.GenerateInstruction("PUSH", variable.Value.ToString( ));
                if (!evaluateForSideEffectsOnly)
                {
                    context.GenerateInstruction("DUP");                         // copy original value to leave on the stack
                }
                context.GenerateInstruction("DEC");
                context.GenerateInstruction("POP", variable.Value.ToString( ));
            }
            else
            {
                throw new AssertionFailedException("unexpected target" + what.ToString());
            }

            return(null);
        }
Ejemplo n.º 2
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            // NB: a C string's value is its address.
            //	(There is no notion of a string's address as that would be an address of an address.)
            switch (purpose)
            {
            case EvaluationIntention.Value:
            case EvaluationIntention.ValueOrNode:
                // might be a case of *(p+i), which can be done as p[i];
                if (Arg is AddressOfTreeNode addrOf1)
                {
                    // 3404
                    // 3401: collapse *&(expr) on RHS and just generate code for the underlying expr
                    context.SetPrettyPrintProlog("<skipped> ");
                    context.PrettyPrint(Arg);
                    return(addrOf1.Arg.GenerateCodeForValueWithPrettyPrint(context, purpose));
                }
                else
                {
                    if (Arg is AdditionTreeNode addition)
                    {
                        context.SetPrettyPrintProlog("<skipped> ");
                        context.PrettyPrint(Arg);
                        addition.Left.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                        addition.Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                        context.GenerateInstruction("Subscript");
                    }
                    else
                    {
                        Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                        context.GenerateInstruction("Indirection");
                    }
                }
                break;

            case EvaluationIntention.SideEffectsOnly:
                Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly);
                break;

            case EvaluationIntention.AddressOrNode:
                if (Arg is AddressOfTreeNode addrOf2)
                {
                    // 3401: collapse *&(expr) on LHS and just generate code for the underlying expr
                    context.SetPrettyPrintProlog("<skipped> ");
                    context.PrettyPrint(Arg);
                    return(addrOf2.Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.AddressOrNode));
                }
                else
                {
                    // NB: if we did ValueOrNode here, we'd have to handle Node results specially
                    //	as we cannot allow a Node from ValueOrNode unmodified as AddressOrNode
                    Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                }
                break;

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }

            return(null);
        }
Ejemplo n.º 3
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            bool so = false;

            switch (purpose)
            {
            case EvaluationIntention.SideEffectsOnly:
                so = true;
                break;

            case EvaluationIntention.Value:
            case EvaluationIntention.ValueOrNode:
                break;

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }
            var secondChoice = context.CreateLabel();

            Pre.GenerateCodeForConditionalBranchWithPrettyPrint(context, secondChoice, false);

            Mid.GenerateCodeForValueWithPrettyPrint(context, so ? EvaluationIntention.SideEffectsOnly : EvaluationIntention.Value);
            var joinPoint = context.CreateLabel();

            context.GenerateUnconditionalBranch(joinPoint);
            context.PlaceLabelHere(secondChoice);
            Post.GenerateCodeForValueWithPrettyPrint(context, so ? EvaluationIntention.SideEffectsOnly : EvaluationIntention.Value);
            context.PlaceLabelHere(joinPoint);
            return(null);
        }
Ejemplo n.º 4
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            // NB: a C string's value is its address.  (There is no notion of a string's address.)
            switch (purpose)
            {
            case EvaluationIntention.Value:
                context.GenerateInstruction("PUSH", string.Format("\"{0}\"", Value));
                break;

            case EvaluationIntention.SideEffectsOnly:
                break;

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }

            return(null);
        }
Ejemplo n.º 5
0
        // NB: Short Circut Evaluation (Left || Right): if "Left" evaluates to true we must not evaluate "Right"

        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            switch (purpose)
            {
            case EvaluationIntention.SideEffectsOnly:
                // We have something like an expression statement:
                //		a || b;
                //	or perhaps a parameter as in
                //		f(a||b);
                //	This requires differentiated evaluation for left/first and right/second as follows:
                //		a's truth value determines whether b is executed or skipped (short-circuted).
                //			if a is false, then b is executed; otherwise if a is true, b is skipped.
                //		thus, we need to evaluate "a" for conditional branch, and to branch around "b"!
                //		however, b does not affect anything further (and we don't need a final value for (a||b) either).
                //		Thus, b is evaluated for side effects only.
                var joinPoint1 = context.CreateLabel();
                Left.GenerateCodeForConditionalBranchWithPrettyPrint(context, joinPoint1, true);
                Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly);
                context.PlaceLabelHere(joinPoint1);
                return(null);

            case EvaluationIntention.Value:
            case EvaluationIntention.ValueOrNode:
                // we have an expression like (a || b) + 3 so we treat that like: ((a || b) ? 1 : 0) + 3;
                var zero = context.CreateLabel();
                context.EvalEither(Left, Right, zero, false);
                // get temp, so easy on stack machine
                context.GenerateInstruction("PUSH", "#1");
                var joinPoint2 = context.CreateLabel();
                context.GenerateUnconditionalBranch(joinPoint2);
                context.PlaceLabelHere(zero);
                context.GenerateInstruction("PUSH", "#0");
                context.PlaceLabelHere(joinPoint2);
                return(null);

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }
        }
Ejemplo n.º 6
0
 // This on is to be invoked; it performs pretty printing, and then invokes the protected (real/overridden) one.
 public AbstractSyntaxTree GenerateCodeForValueWithPrettyPrint(CodeGenContext context, EvaluationIntention purpose)
 {
     context.PrettyPrint(this);
     return(GenerateCodeForValue(context, purpose));
 }
Ejemplo n.º 7
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            switch (purpose)
            {
            case EvaluationIntention.Value:
                context.GenerateInstruction("PUSH", Value.ToString());
                break;

            case EvaluationIntention.ValueOrNode:
                return(this);

            case EvaluationIntention.SideEffectsOnly:
                break;

            case EvaluationIntention.AddressOrNode:
                return(this);

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }

            return(null);
        }
Ejemplo n.º 8
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            switch (purpose)
            {
            case EvaluationIntention.SideEffectsOnly:
                Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly);
                return(null);

            case EvaluationIntention.Value:
            case EvaluationIntention.ValueOrNode:
                Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                if (Op != Operators.Operator.FixPoint)
                {
                    context.GenerateInstruction(Op.ToString());
                }
                return(null);

//				case EvaluationIntention.AddressOrNode:
//					Arg.GenerateCodeForValueWithPrettyPrint ( context, EvaluationIntention.Value );
//					return null;
            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }
        }
Ejemplo n.º 9
0
 /// <summary>
 ///		Generates code for the given tree node.
 /// </summary>
 /// <param name="context">
 ///		where the generated code is output to, and some helper functions
 /// </param>
 /// <param name="purpose">
 ///		A tree can be evalutated for code generation:
 ///			for side effects only:
 ///				used to evaluate statements that discard results
 ///				expect null for return value
 ///			for the value produced by the expression (unconditionally):
 ///				used to evaluate most operators in an expression context
 ///				expect null for return value meaning the result is in the "temporary" location
 ///			for the value produced by the expression when complex, or the node when a simple variable
 ///				used to evaluate function expressions
 ///				expect null meaning the result is in the "temporary" location, or,
 ///				a variable if the expression evaluates to a simple variable
 ///			for the address of the expression when complex, or the node when a simple variable
 ///				used to evaluate left-hand-side of assignment operators
 ///				expect null when the result is in the "temporary" location, or,
 ///				variable if the result is the address of a variable
 ///		Note: a tree can also be evalutated for conditional branch, but that is done with GenerateCodeForConditionalBranch, below.
 ///		See EvaluationIntention for more details.
 /// </param>
 /// <returns>
 ///		The return value takes on meaning in the context of the intended purpose of evaluation.
 ///		It is a tree node that captures the mode of the loaded value:
 ///			null		-- indicating the expression result is a "temporary", or is nothing
 ///			variable	-- if the temporary result is a variable or address
 /// </returns>
 /// This is meant to be overridden by subclasses, but not called; hence protected!
 protected abstract AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose);
Ejemplo n.º 10
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            Arg.GenerateCodeForValueWithPrettyPrint(context, purpose);
            switch (purpose)
            {
            case EvaluationIntention.SideEffectsOnly:
                Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly);
                return(null);

            case EvaluationIntention.Value:
            case EvaluationIntention.ValueOrNode:
                Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                context.GenerateInstruction("NEG");
                return(null);

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }
        }
Ejemplo n.º 11
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            // To take the address of a child expression, we capitalize on having an evaluation intention mode that matches this.
            //	We have this mode to support assignment and address of operations.
            //		Note that we must have a notion of evaluating an expression for its location rather than for its value, as
            //			we could not evaluate the left hand side of an assignment for value, and then take its address -- that doesn't work!
            //	By using the address evaluation intention for the child, there is then sometimes no code to generate for this operator.
            //	When it does need to generate code, the case of &a, for example, the it uses the PEA instruction
            //	Also note that this approach automatically detects and optimizes a sequence like &*
            //
            // Contrast this above with the Indirection operator
            //		The other operator, Indirection, needs to special case *& to collapse these two.
            //		This is because we don't have an evaluation intention mode for indirection,
            //		Instead we generate the indirection's value and the use an Indirection instruction to dereference it.
            //
            switch (purpose)
            {
            case EvaluationIntention.SideEffectsOnly:
                Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly);
                break;

            case EvaluationIntention.Value:
                var ans = Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.AddressOrNode);

                if (ans != null)
                {
                    if (ans is VariableTreeNode variable)
                    {
                        // PEA == Push Effective Address
                        context.GenerateInstruction("PEA", variable.Value.ToString());
                    }
                    else
                    {
                        throw new AssertionFailedException("unexpected result for &");
                    }
                }
                break;

            case EvaluationIntention.ValueOrNode:
                return(Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.AddressOrNode));

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }
            return(null);
        }
Ejemplo n.º 12
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            switch (purpose)
            {
            case EvaluationIntention.SideEffectsOnly:
                Left.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly);
                Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly);
                return(null);

            case EvaluationIntention.Value:
            case EvaluationIntention.ValueOrNode:
                Left.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                context.GenerateInstruction(Op.ToString());
                return(null);

            case EvaluationIntention.AddressOrNode:
                Left.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);
                context.GenerateInstruction("AddIndex");
                return(null);

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }
        }
Ejemplo n.º 13
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            var functionToCall = Left.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.ValueOrNode);

            // NB: Function calls are binary operators in the sense that they have two arguments.
            // The first argument is the function to call, and the second is:
            //	possibly null -- if no arguments are supplied, or,
            //	a single parameter -- if one argument is supplied, or,
            //	a tree of ArgumentSeparator, whose left is
            //		a single parameter, or,
            //		a tree of ArugmentSeparator ...
            //		and whose Right is a single parameter.

            var argCount = context.EvaluateArgumentList(Right);

            if (functionToCall == null)
            {
                context.GenerateInstruction("ICALL", string.Format("#{0}", argCount));
            }
            else if (functionToCall is VariableTreeNode variable)
            {
                context.GenerateInstruction("CALL", variable.Value.ToString(), string.Format("#{0}", argCount));
            }
            else
            {
                throw new AssertionFailedException("unknown function");
            }

            if (purpose == EvaluationIntention.SideEffectsOnly)
            {
                context.GenerateInstruction("POP");
            }

            return(null);
        }
Ejemplo n.º 14
0
        protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose)
        {
            // When we ask for AddressOrNode, we will get either an address
            //		e.g. for a[i] += ..., we'll get a+i on the stack, or,
            //		for i += ..., we'll get nothing on the stack, so we can pop directly into i
            var target   = Left.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.AddressOrNode);
            var variable = target as VariableTreeNode;

            if (Op != Assignment)
            {
                GenerateLHSValue(context, target, variable);
            }

            Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value);

            var keep = false;

            switch (purpose)
            {
            case EvaluationIntention.Value:
            case EvaluationIntention.ValueOrNode:
                keep = true;
                break;

            case EvaluationIntention.SideEffectsOnly:
                break;

            default:
                throw new AssertionFailedException("unexpected evaluation intention" + purpose);
            }

            if (Op != Assignment)
            {
                GenerateAssignmentComputation(context);
            }

            if (target == null)
            {
                // this case is that we generated an address onto the stack for the target
                //	so, we need to use indirection operators
                if (keep)
                {
                    // Stack has LeftY | RightTop <-- stack top
                    //	This instruction does *LeftY = RightTop
                    //		and pops only Left off the stack, leaving Right
                    context.GenerateInstruction("ISTORE");
                }
                else
                {
                    // Stack has LeftY | RightTop <-- stack top
                    //	This instruction does *LeftYT = RightTop
                    //		and pops both Left and Right off the stack
                    context.GenerateInstruction("IPOP");
                }
            }
            else
            {
                // this case is that we generated nothing onto the stack for the left hand side
                //	so, we'll pop or store directly into
                if (keep)
                {
                    // Stack has RightTop <-- stack top
                    //	This instruction does var = RightTop
                    //		and does not pop Right
                    //	This form is used when the assignment is used
                    //		as in f(a=b); in which b is assigned into a, and the value is passed to f
                    context.GenerateInstruction("STORE", variable.Value.ToString());
                }
                else
                {
                    // Stack has RightTop <-- stack top
                    //	This instruction does var = RightTop
                    //		and does pop Right off the stack, because the value is not wanted.
                    context.GenerateInstruction("POP", variable.Value.ToString());
                }
            }

            return(null);
        }