Example #1
0
Value *VirtualMachine::evaluate(Instructions *instructions, Symbols *symbols) {
    if (instructions == nullptr) return nullptr;

    if (symbols == nullptr) {
        std::cerr << "Symbols table cannot be null" << std::endl;
        exit(1);   
    }

    std::stack<Value *> stack;

    for (auto i = instructions->begin(); i != instructions->end(); ++i) {
        switch (i->type) {
            case Instruction::JumpType:
                i += i->flags;
                break;

            case Instruction::TrueJumpType:
            case Instruction::FalseJumpType: {
                assert(stack.size() >= 1);

                Value *value = stack.top();

                assert(value);

                if (value->to_bool() == (i->type == Instruction::TrueJumpType)) {
                    i += i->flags;
                }

                break;
            }

            case Instruction::PrintType: {
                assert(stack.size() >= 1);

                Value *value = stack.top();
                stack.pop();

                assert(value);

                std::cout << value->to_string() << std::endl;

                break;
            }

            case Instruction::CallType:
                break;
            case Instruction::ReturnType:
                break;

            case Instruction::AssignType: {
                assert(stack.size() >= 1);

                (*symbols)[i->value->to_string()] = stack.top();
                stack.pop();

                break;
            }

            case Instruction::AndType: {
                assert(stack.size() >= 2);

                Value *right = stack.top();
                stack.pop();

                Value *left = stack.top();
                stack.pop();

                stack.push(new Value(left->to_bool() and right->to_bool()));
                break;
            }

            case Instruction::OrType: {
                assert(stack.size() >= 2);

                Value *right = stack.top();
                stack.pop();

                Value *left = stack.top();
                stack.pop();

                stack.push(new Value(left->to_bool() and right->to_bool()));
                break;
            }

            case Instruction::EqualsType:
            case Instruction::NEqualsType: {
                assert(stack.size() >= 2);

                Value *right = stack.top();
                stack.pop();

                Value *left = stack.top();
                stack.pop();

                assert(left);
                assert(right);

                bool result = false;

                switch (left->get_type()) {
                    case BooleanTypeValue:
                        result = left->to_bool() == right->to_bool();
                        break;
                    case IntegerTypeValue:
                        result = left->to_integer() == right->to_integer();
                        break;
                    case DoubleTypeValue:
                        result = left->to_double() == right->to_double();
                        break;
                    case StringTypeValue:
                        result = left->to_string() == right->to_string();
                        break;

                    case UnknownTypeValue:
                    case NullTypeValue:
                        result = left->get_type() == right->get_type();
                        break;

                    default:
                    case ArrayTypeValue:
                        std::cerr << "Attempting to compare uncomparable types." << std::endl;
                        exit(1);
                        break;
                }

                if (i->type == Instruction::NEqualsType) {
                    result = !result;
                }

                stack.push(new Value(result));
                break;
            }

            case Instruction::IncrementType:
            case Instruction::DecrementType: {
                assert(stack.size() >= 1);
                
                Value *result = nullptr;
                Value *value = stack.top();
                stack.pop();

                int offset = (i->type == Instruction::IncrementType) ? 1 : -1;

                if (value->get_type() & IntegerTypeValue) {
                    result = new Value(value->to_integer() + offset);
                }
                else {
                    result = new Value(value->to_double() + offset);
                }

                stack.push(result);
                break;
            }

            case Instruction::AddType:
            case Instruction::SubType:
            case Instruction::MultType:
            case Instruction::DivType:
            case Instruction::ModType: {
                assert(stack.size() >= 2);
                
                Value *right = stack.top();
                stack.pop();

                Value *left = stack.top();
                stack.pop();

                Value *result = nullptr;

                if (left->get_type() & DoubleTypeValue or right->get_type() & DoubleTypeValue) {
                    double lval = left->to_double();
                    double rval = right->to_double();

                    switch (i->type) {
                        case Instruction::AddType: {
                            result = new Value(lval + rval);
                            break;
                        }

                        case Instruction::SubType: {
                            result = new Value(lval - rval);
                            break;
                        }

                        case Instruction::MultType: {
                            result = new Value(lval * rval);
                            break;
                        }

                        case Instruction::DivType: {
                            result = new Value(lval / rval);
                            break;
                        }

                        case Instruction::ModType: {
                            std::cerr << "Invalid operands to mod expression." << std::endl;
                            exit(1);
                            break;
                        }

                        default:
                            std::cerr << "Invalid binary expression." << std::endl;
                            exit(1);
                            break;
                    }
                }
                else {
                    long lval = left->to_integer();
                    long rval = right->to_integer();

                    switch (i->type) {
                        case Instruction::AddType: {
                            result = new Value(lval + rval);
                            break;
                        }

                        case Instruction::SubType: {
                            result = new Value(lval - rval);
                            break;
                        }

                        case Instruction::MultType: {
                            result = new Value(lval * rval);
                            break;
                        }

                        case Instruction::DivType: {
                            result = new Value(lval / rval);
                            break;
                        }

                        case Instruction::ModType: {
                            result = new Value(lval % rval);
                            break;
                        }

                        default:
                            std::cerr << "Invalid binary expression." << std::endl;
                            exit(1);
                            break;
                    }
                }

                stack.push(result);

                break;
            }

            case Instruction::IdentifierType:
            case Instruction::ValueType: {
                Value *value = nullptr;

                if (i->type == Instruction::IdentifierType) {
                    value = (*symbols)[i->value->to_string()];
                }
                else {
                    value = i->value;
                }

                assert(value);

                stack.push(value);
                break;
            }

            case Instruction::EndType:
                break;
        }
    }

    if (stack.empty() == true) return nullptr;

    return stack.top();
}
Example #2
0
Value *VirtualMachine::evaluate(Node *node, Symbols *symbols) {
    if (node == nullptr) return nullptr;

    if (symbols == nullptr) {
        std::cerr << "Symbols table cannot be null" << std::endl;
        exit(1);
    }

    switch (node->type) {
        case Node::Compound: {
            Value *result = evaluate(node->left, symbols);
            
            if (state == ReturnState) {
                return result;
            }
            else {
                return evaluate(node->right, symbols);
            }

            break;
        }

        case Node::Print: {
            Value *expression = evaluate(node->left, symbols);

            if (expression == nullptr) {
                std::cerr << "Nothing to print." << std::endl;
                exit(1);
            }

            std::cout << expression->to_string() << std::endl;

            return nullptr;
            break;
        }

        case Node::Function: {
            if(node->left == nullptr or node->left->left == nullptr) {
                std::cerr << "Function has invalid prototype." << std::endl;
                exit(1);
            }
            else {
                std::vector<std::string> parameters;

                if (node->left->right) {
                    std::stack<Node *> nodes;
 
                    nodes.push(node->left->right);

                    while (nodes.empty() == false) {
                        Node *current = nodes.top();

                        if (current->type == Node::Separator) {
                            nodes.pop();

                            if (current->right) nodes.push(current->right);
                            if (current->left) nodes.push(current->left);
                        }
                        else {
                            parameters.push_back(current->value->to_string());

                            nodes.pop();
                        }
                    }
                }

                std::string function_name = node->left->left->value->to_string();

                functions[function_name] = {
                    function_name,
                    parameters,
                    node->right
                };
            }

            return nullptr;
            break;
        }

        case Node::Conditional: {
            if (node->left == nullptr or node->left->type != Node::Branch) {
                std::cerr << "Conditional must have a branch." << std::endl;
                exit(1);
            }

            if (node->left->left == nullptr) {
                std::cerr << "Conditional must have a condition." << std::endl;
                exit(1);
            }

            Value *condition = evaluate(node->left->left, symbols);

            if (condition->to_bool()) {
                return evaluate(node->left->right, symbols);
            }
            else {
                return evaluate(node->right, symbols);
            }

            break;
        }

        case Node::And: {
            if (node->left == nullptr or node->right == nullptr) {
                std::cout << "And statement requires two sub-expressions." << std::endl;
                exit(1);
            }

            Value *left = evaluate(node->left, symbols);

            if (left->to_bool()) {
                return evaluate(node->right, symbols);
            }

            return left;
        }

        case Node::Or: {
            if (node->left == nullptr or node->right == nullptr) {
                std::cout << "Or statement requires two sub-expressions." << std::endl;
                exit(1);
            }

            Value *left = evaluate(node->left, symbols);

            if (left->to_bool() == false) {
                return evaluate(node->right, symbols);
            }

            return left;
        }

        case Node::Loop: {
            bool done = false;

            while (done == false) {
                Value *condition = evaluate(node->left, symbols);

                if (condition == nullptr) {
                    std::cerr << "Loop condition cannot be null." << std::endl;
                    exit(1);
                }

                if (condition->to_bool()) {
                    Value *result = evaluate(node->right, symbols);

                    if (state == ReturnState) {
                        return result;
                    }
                }
                else {
                    done = true;
                }
            }

            return nullptr;
            break;
        }

        case Node::Equals:
        case Node::NEquals: {
            if (node->left == nullptr or node->right == nullptr) {
                std::cerr << "Must have two values to do a comparison." << std::endl;
                exit(1);
            }

            Value *left = evaluate(node->left, symbols);
            Value *right = evaluate(node->right, symbols);
            bool result = false;

            switch (left->get_type()) {
                case BooleanTypeValue:
                    result = left->to_bool() == right->to_bool();
                    break;
                case IntegerTypeValue:
                    result = left->to_integer() == right->to_integer();
                    break;
                case DoubleTypeValue:
                    result = left->to_double() == right->to_double();
                    break;
                case StringTypeValue:
                    result = left->to_string() == right->to_string();
                    break;

                case UnknownTypeValue:
                case NullTypeValue:
                    result = left->get_type() == right->get_type();
                    break;

                default:
                case ArrayTypeValue:
                    std::cerr << "Attempting to compare uncomparable types." << std::endl;
                    exit(1);
                    break;
            }

            if (node->type == Node::NEquals) {
                result = !result;
            }

            return new Value(result);
            break;
        }

        case Node::Call: {
            if (node->left == nullptr) {
                std::cerr << "Function cannot have an empty identifier." << std::endl;
                exit(1);
            }

            auto it = functions.find(node->left->value->to_string());

            if (it == functions.end()) {
                std::cerr << "Invalid function '" << node->left->value->to_string() << "'" << std::endl;
                exit(1);
            }

            Symbols *parameters = new Symbols;
            unsigned parameter_count = 0;

            if (node->right) {
                std::stack<Node *> nodes;

                nodes.push(node->right);

                while (nodes.empty() == false) {
                    Node *current = nodes.top();

                    if (current->type == Node::Separator) {
                        nodes.pop();

                        if (current->right) nodes.push(current->right);
                        if (current->left) nodes.push(current->left);
                    }
                    else {
                        if (it->second.parameters.size() <= parameter_count) {
                            std::cerr << "Too many parameters." << std::endl;
                            exit(1);
                        }

                        std::string name(it->second.parameters[parameter_count++]);

                        Value *value = evaluate(current, symbols);

                        if (value == nullptr) {
                            std::cerr << "Parameter cannot be null." << std::endl;
                            exit(1);
                        }

                        (*parameters)[name] = value;

                        nodes.pop();
                    }
                }
            }

            Value *result = evaluate(it->second.content, parameters);

            state = NormalState;

            delete parameters;

            return result;
            break;
        }

        case Node::Return: {
            Value *result = evaluate(node->left, symbols);

            if (result == nullptr) {
                std::cerr << "Must return a value." << std::endl;
                exit(1);
            }

            state = ReturnState;

            return result;
            break;
        }

        case Node::Assign: {
            if (node->left and node->right) {
                Value *value = evaluate(node->right, symbols);

                if (value) {
                    (*symbols)[node->left->value->to_string()] = value;
                }
                else {
                    std::cerr << "Value is a null pointer." << std::endl;
                    exit(1);
                }

                return nullptr;
            }
            else {
                std::cerr << "Missing left or right child for assignment." << std::endl;
                exit(1);
            }

            break;
        }

        case Node::Increment:
        case Node::Decrement: {
            std::string identifier = node->left->value->to_string();

            if (symbols->find(identifier) == symbols->end()) {
                std::cerr << "Variable '" << identifier << "' does not exit." << std::endl;
                exit(1);
            }

            Value *value = symbols->at(identifier);
            int d = (node->type == Node::Increment) ? 1 : -1;

            if (value->get_type() == IntegerTypeValue) {
                (*symbols)[identifier] = new Value(value->to_integer() + d);
            }
            else if (value->get_type() == DoubleTypeValue) {
                (*symbols)[identifier] = new Value(value->to_double() + d);
            }
            else {
                std::cerr << "Cannot perform arithmetic on value '" << identifier << "'." << std::endl;
                exit(1);
            }

            return symbols->at(identifier);
            break;
        }

        case Node::Add:
        case Node::Sub:
        case Node::Mult:
        case Node::Div:
        case Node::Mod: {
            Value *left = evaluate(node->left, symbols);

            if (left == nullptr) {
                std::cerr << "Left side cannot be null." << std::endl;
                exit(1);
            }

            if ((left->get_type() & (IntegerTypeValue | DoubleTypeValue)) == 0) {
                std::cout << "Type: " << left->get_type() << std::endl;
                std::cerr << "Cannot perform arithmetic on value '" << left->to_string() << "'." << std::endl;
                exit(1);         
            }

            Value *right = evaluate(node->right, symbols);

            if (right == nullptr) {
                std::cerr << "Left side cannot be null." << std::endl;
                exit(1);
            }
            
            if ((right->get_type() & (IntegerTypeValue | DoubleTypeValue)) == 0) {
                std::cerr << "Cannot perform arithmetic on value '" << left->to_string() << "'." << std::endl;
                exit(1);
            }

            // If one of these values is a double we will need to return a double.
            if (left->get_type() & DoubleTypeValue or right->get_type() & DoubleTypeValue) {
                double lval = left->to_double();
                double rval = right->to_double();
                double result;

                switch (node->type) {
                    case Node::Add:
                        result = lval + rval;
                        break;

                    case Node::Sub:
                        result = lval - rval;
                        break;

                    case Node::Mult:
                        result = lval * rval;
                        break;

                    case Node::Div:
                        result = lval / rval;
                        break;

                    case Node::Mod:
                        std::cerr << "Cannot calculate mod of double." << std::endl;
                        exit(1);
                        break;

                    default:
                        std::cerr << "Invalid type: " << node->type << std::endl;
                        exit(1);
                        break;
                }
            }
            else {
                long lval = left->to_integer();
                long rval = right->to_integer();
                long result;

                switch (node->type) {
                    case Node::Add:
                        result = lval + rval;
                        break;

                    case Node::Sub:
                        result = lval - rval;
                        break;

                    case Node::Mult:
                        result = lval * rval;
                        break;

                    case Node::Div:
                        result = lval / rval;
                        break;

                    case Node::Mod:
                        result = lval % rval;
                        break;

                    default:
                        std::cerr << "Invalid type: " << node->type << std::endl;
                        exit(1);
                        break;
                }

                return new Value(result);
            }

            return nullptr;
        }

        case Node::Identifier: {
            if (node->value == nullptr) {
                std::cerr << "Identifier cannot be null." << std::endl;
                exit(1);
            }
            else if ((node->value->get_type() & StringTypeValue) == 0) {
                std::cerr << "Identifier must be a string." << std::endl;
                exit(1);
            }

            std::string identifier = node->value->to_string();

            if (symbols->find(identifier) != symbols->end()) {
                return (*symbols)[identifier];
            }
            else {
                std::cerr << "Variable '" << identifier << "' does not exist." << std::endl;
                exit(1);               
            }

            break;
        }

        case Node::Integer:
        case Node::Double:
        case Node::String:
        case Node::Boolean:
            return node->value;
            break;

        default:
            return nullptr;
            break;
    }
}