Exemple #1
0
        // Do type equalisation on the expression node and report an error if the
        // two operands types are mismatched (eg. string and integer)
        BinaryOpParseNode TypeEqualise(BinaryOpParseNode node)
        {
            // Don't check a bogus parse tree.
            if (node.Left == null || node.Right == null) {
                return node;
            }
            switch (node.ID) {
                case ParseID.ADD:
                case ParseID.SUB:
                case ParseID.MULT:
                case ParseID.DIVIDE:
                case ParseID.EXP:
                    return ArithmeticEqualise(node);

                case ParseID.CONCAT:
                    return StringEqualise(node);

                case ParseID.OR:
                case ParseID.AND:
                case ParseID.LE:
                case ParseID.LT:
                case ParseID.GE:
                case ParseID.GT:
                case ParseID.EQ:
                case ParseID.NE:
                case ParseID.EQV:
                case ParseID.NEQV:
                case ParseID.EQUOP:
                    return LogicalEqualise(node);
            }
            Debug.Assert(false, "Unhandled expression node token");
            return null;
        }
Exemple #2
0
 // Verify that both operands of a string operator are strings. This
 // is the only type that is permitted.
 BinaryOpParseNode StringEqualise(BinaryOpParseNode node)
 {
     SymType type1 = node.Left.Type;
     SymType type2 = node.Right.Type;
     if (type1 == SymType.CHAR && type2 == SymType.CHAR) {
         node.Type = SymType.CHAR;
         return node;
     }
     if (type1 == SymType.FIXEDCHAR || type2 == SymType.FIXEDCHAR) {
         if (Symbol.IsCharType(type2)) {
             node.Type = SymType.FIXEDCHAR;
             return node;
         }
     }
     _messages.Error(MessageCode.TYPEMISMATCH, "Character operands expected");
     return node;
 }
Exemple #3
0
        /// OPERATION                   OPERATOR     ORDER OF PRECEDENCE
        /// exponentiate                 **                8
        /// multiply                     *                 7
        /// divide                       /                 7
        /// add                          +                 6
        /// subtract                     -                 6
        /// less than                    .LT.              5
        /// less than or equal to        .LE.              5
        /// equal to                     .EQ.              5
        /// not equal to                 .NE.              5
        /// greater than or equal to     .GE.              5
        /// greater than                 .GT.              5
        /// not                          .NOT.             4
        /// and                          .AND.             3
        /// or                           .OR.              2
        /// xor                          .XOR.             1
        /// neqv                         .NEQV.            1
        /// eqv                          .EQV.             1
        /// Parse an expression.
        ParseNode ParseExpression(int level)
        {
            ParseNode op1 = Operand();
            bool done = false;

            while (!done) {
                SimpleToken token = _ls.GetToken();
                bool isRTL = false;
                ParseID parseID;

                int preced;
                switch (token.ID) {
                    case TokenID.KEQV:      parseID = ParseID.EQV;      preced = 1; break;
                    case TokenID.KNEQV:     parseID = ParseID.NEQV;     preced = 1; break;
                    case TokenID.KXOR:      parseID = ParseID.XOR;      preced = 1; break;

                    case TokenID.KOR:       parseID = ParseID.OR;       preced = 2; break;

                    case TokenID.KAND:      parseID = ParseID.AND;      preced = 3; break;

                    case TokenID.KGT:       parseID = ParseID.GT;       preced = 5; break;
                    case TokenID.KGE:       parseID = ParseID.GE;       preced = 5; break;
                    case TokenID.KLE:       parseID = ParseID.LE;       preced = 5; break;
                    case TokenID.KEQ:       parseID = ParseID.EQ;       preced = 5; break;
                    case TokenID.KNE:       parseID = ParseID.NE;       preced = 5; break;
                    case TokenID.EQUOP:     parseID = ParseID.EQ;       preced = 5; break;
                    case TokenID.KLT:       parseID = ParseID.LT;       preced = 5; break;

                    case TokenID.PLUS:      parseID = ParseID.ADD;      preced = 6; break;
                    case TokenID.MINUS:     parseID = ParseID.SUB;      preced = 6; break;

                    case TokenID.STAR:      parseID = ParseID.MULT;     preced = 7; break;
                    case TokenID.DIVIDE:    parseID = ParseID.DIVIDE;   preced = 7; break;

                    case TokenID.CONCAT:    parseID = ParseID.CONCAT;   preced = 8; break;

                    case TokenID.EXP:       parseID = ParseID.EXP;      preced = 10; isRTL = true; break;

                    default:
                        _ls.BackToken();
                        done = true;
                        continue;
                }
                if (level >= preced) {
                    _ls.BackToken();
                    done = true;
                } else {

                    // For operators that evaluate right to left (such as EXP), drop the
                    // precedence so that further occurrences of the same operator to
                    // the right are grouped together.
                    if (isRTL) {
                        --preced;
                    }
                    BinaryOpParseNode op = new BinaryOpParseNode(parseID);
                    op.Left = op1;
                    op.Right = ParseExpression(preced);
                    op1 = TypeEqualise(op);
                }
            }
            return op1;
        }
Exemple #4
0
        // Optimise an exponentation expression where both nodes are literal
        // values. Substitute the node with the result of the exponentation.
        ParseNode OptimiseExponentation(ParseNode node)
        {
            BinaryOpParseNode tokenNode = (BinaryOpParseNode)node;
            tokenNode.Left = OptimiseExpressionTree(tokenNode.Left);
            tokenNode.Right = OptimiseExpressionTree(tokenNode.Right);

            if (tokenNode.IsNumber) {
                NumberParseNode op1 = (NumberParseNode)tokenNode.Left;
                NumberParseNode op2 = (NumberParseNode)tokenNode.Right;
                node = new NumberParseNode(op1.Value.Pow(op2.Value));
            }

            // x raised to the powers of -1, 0 and 1 all yield constant expressions
            // so we can simplify that right now.
            if (tokenNode.Right.IsNumber) {
                Variant rightValue = tokenNode.Right.Value;
                if (rightValue.Compare(-1)) {
                    BinaryOpParseNode divNode = new BinaryOpParseNode(ParseID.DIVIDE);
                    divNode.Left = new NumberParseNode(new Variant(1));
                    divNode.Right = tokenNode.Left;
                    divNode.Type = tokenNode.Left.Type;
                    return divNode;
                }
                if (rightValue.IsZero) {
                    return new NumberParseNode(1);
                }
                if (rightValue.Compare(1)) {
                    return tokenNode.Left;
                }
            }
            return node;
        }
Exemple #5
0
        // Do type equalisation for arithmetic expressions. In this instance,
        // the type of the result is cast to the largest type that can
        // accommodate the two operands. Anything that evaluates to a non-
        // arithmetic value yields a type mismatch.
        BinaryOpParseNode ArithmeticEqualise(BinaryOpParseNode node)
        {
            SymType type1 = node.Left.Type;
            SymType type2 = node.Right.Type;

            if (type1 == SymType.INTEGER) {
                switch (type2) {
                    case SymType.DOUBLE:
                        node.Type = SymType.DOUBLE;
                        return node;

                    case SymType.FLOAT:
                        node.Type = SymType.FLOAT;
                        return node;

                    case SymType.COMPLEX:
                        node.Type = SymType.COMPLEX;
                        return node;

                    case SymType.INTEGER:
                        node.Type = SymType.INTEGER;
                        return node;
                }
            }
            if (type1 == SymType.FLOAT) {
                switch (type2) {
                    case SymType.DOUBLE:
                        node.Type = SymType.DOUBLE;
                        return node;

                    case SymType.COMPLEX:
                        node.Type = SymType.COMPLEX;
                        return node;

                    case SymType.FLOAT:
                    case SymType.INTEGER:
                        node.Type = SymType.FLOAT;
                        return node;
                }
            }
            if (type1 == SymType.DOUBLE) {
                switch (type2) {
                    case SymType.DOUBLE:
                    case SymType.FLOAT:
                    case SymType.INTEGER:
                        node.Type = SymType.DOUBLE;
                        return node;
                }
            }
            if (type1 == SymType.COMPLEX) {
                switch (type2) {
                    case SymType.INTEGER:
                    case SymType.FLOAT:
                    case SymType.COMPLEX:
                        node.Type = SymType.COMPLEX;
                        return node;
                }
            }
            if (type1 == SymType.FIXEDCHAR) {
                switch (type2) {
                    case SymType.FIXEDCHAR:
                        node.Type = SymType.FIXEDCHAR;
                        return node;
                }
            }
            _messages.Error(MessageCode.TYPEMISMATCH, "Type mismatch in expression");
            return node;
        }
Exemple #6
0
        // Do type equalisation for logical expressions. In this instance,
        // the two operands must match (numeric vs. numeric, char vs. char
        // or logical vs. logical). The result is always logical.
        BinaryOpParseNode LogicalEqualise(BinaryOpParseNode node)
        {
            SymType type1 = node.Left.Type;
            SymType type2 = node.Right.Type;

            if (type1 == SymType.INTEGER ||
                type1 == SymType.FLOAT ||
                type1 == SymType.DOUBLE) {
                switch (type2) {
                    case SymType.DOUBLE:
                    case SymType.FLOAT:
                    case SymType.INTEGER:
                        node.Type = SymType.BOOLEAN;
                        return node;
                }
            }
            if (Symbol.IsCharType(type1) && Symbol.IsCharType(type2)) {
                node.Type = SymType.BOOLEAN;
                return node;
            }
            if (Symbol.IsLogicalType(type1) && Symbol.IsLogicalType(type2)) {
                node.Type = SymType.BOOLEAN;
                return node;
            }
            _messages.Error(MessageCode.TYPEMISMATCH, "Type mismatch in expression");
            return node;
        }