Esempio n. 1
0
        public ValType CheckValueType(Node node, Scope inner, Scope outer)
        {
            switch (node.GetNodeType())
            {
            case NodeType.Variable:
                VariableNode variableNode = node as VariableNode;
                if (!inner.variables.TryGetValue(variableNode.name, out VariableNode val))
                {
                    if (!outer.variables.TryGetValue(variableNode.name, out val))
                    {
                        throw new SemanticException(SemanticErrorCode.UndeclaredVariable, "Variable \"" + variableNode.name + "\" is not declared.", node.Line);
                    }
                    else
                    {
                        variableNode.ValType    = val.ValType;
                        variableNode.LocalIndex = val.LocalIndex;
                    }
                }
                else
                {
                    variableNode.ValType    = val.ValType;
                    variableNode.LocalIndex = val.LocalIndex;
                }
                return(variableNode.ValType);

            case NodeType.Assign:
                AssignNode assignNode = node as AssignNode;
                ValType    left       = CheckValueType(assignNode.left, inner, outer);
                ValType    right      = CheckValueType(assignNode.right, inner, outer);
                if (assignNode.left.ValType != right && !(assignNode.left.ValType == ValType.Double && right == ValType.Int))
                {
                    throw new SemanticException(SemanticErrorCode.IllegalCast, "Cannot cast " + Enum.GetName(typeof(ValType), right) +
                                                " to " + Enum.GetName(typeof(ValType), assignNode.left.ValType) + ".", assignNode.right.Line);
                }
                if (right == ValType.Int && assignNode.left.ValType == ValType.Double)
                {
                    DoubleCastNode dcn = new DoubleCastNode(assignNode.right.Line);
                    dcn.content      = assignNode.right;
                    assignNode.right = dcn;
                }
                assignNode.ValType = left;
                return(left);

            case NodeType.Int:
                return(ValType.Int);

            case NodeType.Double:
                return(ValType.Double);

            case NodeType.Bool:
                return(ValType.Bool);

            case NodeType.BinaryOp:
                BinaryOpNode binaryOpNode = node as BinaryOpNode;
                ValType      l            = CheckValueType(binaryOpNode.left, inner, outer);
                ValType      r            = CheckValueType(binaryOpNode.right, inner, outer);
                int          v            = (int)l * (int)r;

                if (binaryOpNode.type == BinaryOpType.BitAnd || binaryOpNode.type == BinaryOpType.BitOr)
                {
                    if (v != 1)
                    {
                        throw new SemanticException(SemanticErrorCode.IllegalCast, "Expected Int value.", node.Line);
                    }
                    return(ValType.Int);
                }
                else
                {
                    if (v > 1 && v < 4)
                    {
                        if (l == ValType.Double)
                        {
                            DoubleCastNode dcn = new DoubleCastNode(binaryOpNode.right.Line);
                            dcn.content        = binaryOpNode.right;
                            binaryOpNode.right = dcn;
                        }
                        else
                        {
                            DoubleCastNode dcn = new DoubleCastNode(binaryOpNode.left.Line);
                            dcn.content       = binaryOpNode.left;
                            binaryOpNode.left = dcn;
                        }

                        binaryOpNode.ValType = ValType.Double;
                        return(ValType.Double);
                    }
                    else if (l == ValType.Bool || r == ValType.Bool)
                    {
                        throw new SemanticException(SemanticErrorCode.IllegalCast, "Expected Int or Double.", binaryOpNode.Line);
                    }
                }
                binaryOpNode.ValType = l;
                return(l);

            case NodeType.LogicOp:
                LogicOpNode logicOpNode = node as LogicOpNode;
                left  = CheckValueType(logicOpNode.left, inner, outer);
                right = CheckValueType(logicOpNode.right, inner, outer);
                if (left != ValType.Bool)
                {
                    string typeString = Enum.GetName(typeof(ValType), left);
                    throw new SemanticException(SemanticErrorCode.IllegalCast, "Expected Bool, but got " + typeString + ".", logicOpNode.left.Line);
                }

                if (right != ValType.Bool)
                {
                    string typeString = Enum.GetName(typeof(ValType), right);
                    throw new SemanticException(SemanticErrorCode.IllegalCast, "Expected Bool, but got " + typeString + ".", logicOpNode.right.Line);
                }
                logicOpNode.ValType = ValType.Bool;
                return(ValType.Bool);

            case NodeType.Comparison:
                ComparisonNode comparisonNode = node as ComparisonNode;
                left  = CheckValueType(comparisonNode.left, inner, outer);
                right = CheckValueType(comparisonNode.right, inner, outer);
                if (left != right)
                {
                    if (left == ValType.Bool || right == ValType.Bool)
                    {
                        throw new SemanticException(SemanticErrorCode.IllegalCast, "Comparison arguments are not the same type.", comparisonNode.Line);
                    }
                    else if (left == ValType.Int && right == ValType.Double)
                    {
                        DoubleCastNode dcn = new DoubleCastNode(comparisonNode.left.Line);
                        dcn.content         = comparisonNode.left;
                        comparisonNode.left = dcn;
                    }
                    else if (right == ValType.Int && left == ValType.Double)
                    {
                        DoubleCastNode dcn = new DoubleCastNode(comparisonNode.right.Line);
                        dcn.content          = comparisonNode.right;
                        comparisonNode.right = dcn;
                    }
                }
                comparisonNode.ValType = ValType.Bool;
                return(ValType.Bool);

            case NodeType.Parenthesis:
                ParenthesisNode parenthesisNode = node as ParenthesisNode;
                ValType         type            = CheckValueType(parenthesisNode.content, inner, outer);
                parenthesisNode.ValType = type;
                return(type);

            case NodeType.IntCast:
                IntCastNode intCastNode = node as IntCastNode;
                CheckInScope(intCastNode.content, inner, outer);
                intCastNode.ValType = ValType.Int;
                return(ValType.Int);

            case NodeType.DoubleCast:
                DoubleCastNode doubleCastNode = node as DoubleCastNode;
                CheckInScope(doubleCastNode.content, inner, outer);
                doubleCastNode.ValType = ValType.Double;
                return(ValType.Double);

            case NodeType.Not:
                NotNode notNode = node as NotNode;
                type = CheckValueType(notNode.content, inner, outer);
                if (type != ValType.Bool)
                {
                    string typeString = Enum.GetName(typeof(ValType), type);
                    throw new SemanticException(SemanticErrorCode.IllegalCast, "Expected Bool, but got " + typeString + ".", notNode.content.Line);
                }
                notNode.ValType = ValType.Bool;
                return(ValType.Bool);

            case NodeType.Minus:
                MinusNode minusNode = node as MinusNode;
                type = CheckValueType(minusNode.content, inner, outer);
                if (type == ValType.Bool)
                {
                    string typeString = Enum.GetName(typeof(ValType), type);
                    throw new SemanticException(SemanticErrorCode.IllegalCast, "Expected Int or Double.", minusNode.content.Line);
                }
                minusNode.ValType = type;
                return(type);

            case NodeType.Neg:
                NegNode negNode = node as NegNode;
                type = CheckValueType(negNode.content, inner, outer);
                if (type != ValType.Int)
                {
                    string typeString = Enum.GetName(typeof(ValType), type);
                    throw new SemanticException(SemanticErrorCode.IllegalCast, "Expected Int, but got " + typeString + ".", negNode.content.Line);
                }
                negNode.ValType = type;
                return(ValType.Int);
            }
            return(ValType.None);
        }
Esempio n. 2
0
        public void CheckInScope(Node node, Scope inner, Scope outer)
        {
            switch (node.GetNodeType())
            {
            case NodeType.Block:
                Scope newOuter = new Scope(outer);
                newOuter.AddScope(inner);
                GoDeeperInScope(node as BlockNode, newOuter);
                break;

            case NodeType.If:
                IfNode  ifNode = node as IfNode;
                ValType type   = CheckValueType(ifNode.check, inner, outer);
                if (type == ValType.Bool)
                {
                    CheckInScope(ifNode.ifBlock, inner, outer);
                    if (!(ifNode.elseBlock is null))
                    {
                        CheckInScope(ifNode.elseBlock, inner, outer);
                    }
                }
                else
                {
                    string typeString = Enum.GetName(typeof(ValType), type);
                    throw new SemanticException(SemanticErrorCode.IllegalCast, "Expected Bool, but got " + typeString + ".", node.Line);
                }
                break;

            case NodeType.While:
                WhileNode whileNode = node as WhileNode;
                type = CheckValueType(whileNode.check, inner, outer);
                if (type == ValType.Bool)
                {
                    CheckInScope(whileNode.block, inner, outer);
                }
                else
                {
                    string typeString = Enum.GetName(typeof(ValType), type);
                    throw new SemanticException(SemanticErrorCode.IllegalCast, "Expected Bool, but got " + typeString + ".", node.Line);
                }
                break;

            case NodeType.Read:
                ReadNode readNode = node as ReadNode;
                CheckInScope(readNode.target, inner, outer);
                break;

            case NodeType.Write:
                WriteNode writeNode = node as WriteNode;
                if (!(writeNode.content is StringNode))
                {
                    CheckInScope(writeNode.content, inner, outer);
                }
                break;

            case NodeType.Variable:
                VariableNode variableNode = node as VariableNode;
                CheckValueType(variableNode, inner, outer);
                break;

            case NodeType.Init:
                InitNode initNode = node as InitNode;
                if (inner.variables.ContainsKey(initNode.variable.name))
                {
                    throw new SemanticException(SemanticErrorCode.VariableAlreadyDeclared, "Variable \"" + initNode.variable.name + "\" already declared in scope", initNode.variable.Line);
                }
                else
                {
                    inner.variables.Add(initNode.variable.name, initNode.variable);
                }
                initNode.variable.LocalIndex = locals.Count;
                locals.Add(new LocalVariable {
                    Name = initNode.variable.name, Type = initNode.variable.ValType
                });
                break;

            case NodeType.Assign:
                AssignNode assignNode = node as AssignNode;
                CheckValueType(assignNode, inner, outer);
                break;

            case NodeType.BinaryOp:
                BinaryOpNode binaryOpNode = node as BinaryOpNode;
                CheckValueType(binaryOpNode, inner, outer);
                break;

            case NodeType.Comparison:
                ComparisonNode comparisonNode = node as ComparisonNode;
                CheckValueType(comparisonNode, inner, outer);
                break;

            case NodeType.Parenthesis:
                ParenthesisNode parenthesisNode = node as ParenthesisNode;
                CheckInScope(parenthesisNode.content, inner, outer);
                break;

            case NodeType.Int:
            case NodeType.Double:
            case NodeType.Bool:
            case NodeType.String:
                break;

            case NodeType.LogicOp:
                LogicOpNode logicNode = node as LogicOpNode;
                CheckValueType(logicNode, inner, outer);
                break;

            case NodeType.IntCast:
                IntCastNode intCastNode = node as IntCastNode;
                CheckValueType(intCastNode, inner, outer);
                break;

            case NodeType.DoubleCast:
                DoubleCastNode doubleCastNode = node as DoubleCastNode;
                CheckValueType(doubleCastNode, inner, outer);
                break;

            case NodeType.Not:
                NotNode notNode = node as NotNode;
                CheckValueType(notNode, inner, outer);
                break;

            case NodeType.Minus:
                MinusNode minusNode = node as MinusNode;
                CheckValueType(minusNode, inner, outer);
                break;

            case NodeType.Neg:
                NegNode negNode = node as NegNode;
                CheckValueType(negNode, inner, outer);
                break;
            }
        }