#ifndef PARSER_H_INCLUDED
#define PARSER_H_INCLUDED

#include "tokenizer.h"
#include "identifier.h"
#include "rc_global.h"
#include "constants.h"
#include <inttypes.h>

using namespace std;

int max_for_count = 0;

//vm registers
int max_n_reg = 0;
int max_s_reg = 0;
int max_u_reg = 0;
int n_reg = 0;
int s_reg = 0;
int u_reg = 0;

//expression result
string expr_result = "";
bool type_delete_flag = false;
string type_delete_arg = "";
int type_delete_arg_type = 0;
bool type_delete_arg_whole = false;

bool type_redim_flag = false;
string type_redim_arg = "";
int type_redim_arg_type = 0;
string type_redim_arg_utype = "";
string type_redim_dim[3];
int type_redim_dim_count = 0;

bool type_no_arg_exception_raised = false;

struct type_error_exception
{
    string error_log;
    string tk_reg;
    string resolve_reg;
    int num_args;
    bool exception_used;
};

vector<type_error_exception> byref_type_exception; //This will store the error that might be generated if a user type var is in an expression without its dimensions expressed


bool pre_parse(int start_token, int end_token, int pp_flags = 0, bool eval_udt = false); //puts number and string values and variables inside number and string registers
//void getBlock(int& start_block, int& end_block); //gets the start and end index of the next block to evaluate (first and last token if there isnt a block left to evaluate
bool eval_pow(int start_block, int end_block);
bool eval_muldiv(int start_block, int end_block); //MOD operator is also evaluated in this function
bool eval_addsub(int start_block, int end_block);
bool eval_tokens(); //evaluates the tokens and generates vm_asm opcodes

vector<string> n_tmp;
vector<string> s_tmp;
vector<string> u_tmp;


void inc_n(int x)
{
    n_reg += x;
    if( (n_reg+1) > max_n_reg)
        max_n_reg = n_reg + 1;
}

void inc_s(int x)
{
    s_reg += x;
    if( (s_reg+1) > max_s_reg)
        max_s_reg = s_reg + 1;
}

void inc_u(int x)
{
    u_reg += x;
    if( (u_reg+1) > max_u_reg)
        max_u_reg = u_reg + 1;
}

void debug_output_VMASM()
{
    for(int i = 0; i < vm_asm.vm_code.size(); i++)
        cout << vm_asm.vm_code[i] << endl;
}

void clear_asm()
{
    vm_asm.clear();
}

//end block will be set to -1 if a block was opened but wasn't closed
void getBlock(int start_token, int end_token, int& start_block, int& end_block)
{
    start_block = start_token; //start_block is set to 0, if there is no block started it will automatically start at the first token
    //end_block = token.size()-1; //end_block is set to the last token, if there is no block started or ended then it will be the last token

    if(end_token > 0)
        end_block = end_token;
    else
        end_block = token.size()-1;

    //this loop will go through every token until it finds a start_block and end_block
    for(int i = start_token; i <= end_token; i++)
    {
        //sets the start_block to the last open block token it discovers
        if(token[i].compare("<par>")==0 || token[i].compare("<square>")==0 || token[i].compare("<curly>")==0)
            start_block = i;

        //if an ending block was encountered and it matches the current start block then the current end_block will be set to the current token
        if( (token[i].compare("</par>")==0 && token[start_block].compare("<par>")==0) ||
            (token[i].compare("</square>")==0 && token[start_block].compare("<square>")==0) ||
            (token[i].compare("</curly>")==0 && token[start_block].compare("<curly>")==0))
        {
            end_block = i;

            //put a ! at the beginning of the start and end block tokens so that they won't be evaluated the next time this function is called
            token[start_block] = "!" + token[start_block];
            token[end_block] = "!" + token[end_block];

            return;
        }
        //if there is a ending block discovered that did not have a matching start block then we set end_block to -1 and set an error message
        else if(token[i].compare("</par>")==0 || token[i].compare("</square>")==0 || token[i].compare("</curly>")==0)
        {
            if(token[i].compare("</par>")==0)
                rc_setError("Found \")\" without \"(\"");
            else if(token[i].compare("</square>")==0)
                rc_setError("Found \"]\" without \"[\"");
            else if(token[i].compare("</curly>")==0)
                rc_setError("Found \"}\" without \"{\"");
            end_block = -1;
            return;
        }
    }
    //if start_block is a bracket and the closing bracket was not found before the end of the loop then end_block is set to -1 and we set an error message
    if(token[start_block].compare("<par>")==0)
    {
        rc_setError("Found \"(\" without \")\"");
        end_block = -1;
    }
    else if(token[start_block].compare("<square>")==0)
    {
        rc_setError("Found \"[\" without \"]\"");
        end_block = -1;
    }
    else if(token[start_block].compare("<curly>")==0)
    {
        rc_setError("Found \"{\" without \"}\"");
        end_block = -1;
    }

}

//This function checks to see if a token can be exempt from the token check that eval functions do
bool token_exemption(int i)
{
    if(token[i].compare("!<par>")==0 || token[i].compare("!</par>")==0 ||
       token[i].compare("!<square>")==0 || token[i].compare("!</square>")==0 ||
       token[i].compare("!<curly>")==0 || token[i].compare("!</curly>")==0)
        return true;
    return false;
}

//This function will clear every token from the first operand to the second operand and set the start operand token to solution
void set_op_solution(int start_op, int end_op, string solution)
{
    for(int i = start_op; i <= end_op; i++)
    {
        if(!token_exemption(i))
            token[i] = "";
    }
    token[start_op] = solution;
}

void getRegInfo(string r_reg, int &arg_type, int &arg_utype)
{
    for(int i = 0; i < resolveID_id_reg.size(); i++)
    {
        if(resolveID_id_reg[i].compare(r_reg)==0)
        {
            arg_type = resolveID_id_type[i];
            arg_utype = resolveID_id_ut_index[i];
            return;
        }
    }

    if(r_reg.substr(0,1).compare("s")==0)
    {
        arg_type = ID_TYPE_STR;
        arg_utype = 0;
    }
    else
    {
        arg_type = ID_TYPE_NUM;
        arg_utype = 0;
    }

    return;
}

bool eval_pow(int start_block, int end_block)
{
    int op_flag = 0;
    string operand1 = "";
    string operand2 = "";

    int op1_index = 0;
    int op2_index = 0;

    //cout << "debug_POW " << start_block << " " << end_block << endl;
    //cout << "t_size" << token.size() << endl;

    for(int i = start_block; i <= end_block; i++)
    {
        if(token_exemption(i))
        {
            //op_flag = 0;
            continue;
        }

        if(token[i].compare("")!=0 && token[i].compare("<pow>")!=0 && (op_flag == 0 || op_flag == 2))
        {
            switch(op_flag)
            {
                case 0:
                    operand1 = token[i];
                    //cout << "op1 = " << operand1 << endl;
                    op1_index = i;
                    op_flag = 1;
                    break;
                case 2:
                    operand2 = token[i];
                    //cout << "op2 = " << operand2 << endl;
                    op2_index = i;
                    op_flag = 3;
                    break;
            }
        }
        else if(token[i].compare("<pow>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for exponent operation");
                return false;
            }
            op_flag = 2;
        }
        else if(token[i].compare("")!=0)
        {
            //cout << "reset -- " << token[i] << endl;
            op_flag = 0;
        }

        if(op_flag==3)
        {
            if(operand1.substr(0,1).compare("n")!=0 || operand2.substr(0,1).compare("n")!=0)
            {
                rc_setError("Expected number operand for exponent operation");
                return false;
            }
            vm_asm.push_back("pow " + operand1 + " " + operand2);
            set_op_solution(op1_index, op2_index, operand1);
            op_flag = 0;
            i = start_block-1;
        }
    }

    if(op_flag == 2)
    {
        rc_setError("Expected operand for exponent operation");
        return false;
    }

    return true;
}

bool eval_muldiv(int start_block, int end_block)
{
    int op_flag = 0;
    string operand1 = "";
    string operand2 = "";

    int op1_index = 0;
    int op2_index = 0;
    int operation = 0; //0 - mul, 1 - div, 2 - mod

    //cout << "debug_MDM " << start_block << " " << end_block << endl;
    //cout << "t_size" << token.size() << endl;

    for(int i = start_block; i <= end_block; i++)
    {
        if(token_exemption(i))
        {
            //op_flag = 0;
            continue;
        }

        if(token[i].compare("")!=0 &&
           token[i].compare("<mul>")!=0 &&
           token[i].compare("<div>")!=0 &&
           token[i].compare("<mod>")!=0 &&
           (op_flag == 0 || op_flag == 2))
        {
            switch(op_flag)
            {
                case 0:
                    operand1 = token[i];
                    //cout << "op1 = " << operand1 << endl;
                    op1_index = i;
                    op_flag = 1;
                    break;
                case 2:
                    operand2 = token[i];
                    op2_index = i;
                    op_flag = 3;
                    break;
            }
        }
        else if(token[i].compare("<mul>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for mul/div operation");
                return false;
            }
            op_flag = 2;
            operation = 0;
        }
        else if(token[i].compare("<div>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for mul/div operation");
                return false;
            }
            op_flag = 2;
            operation = 1;
        }
        else if(token[i].compare("<mod>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for mul/div operation");
                return false;
            }
            op_flag = 2;
            operation = 2;
        }
        else if(token[i].compare("")!=0)
        {
            op_flag = 0;
        }

        if(op_flag==3)
        {
            if(operand1.substr(0,1).compare("n")!=0 || operand2.substr(0,1).compare("n")!=0)
            {
                rc_setError("Expected number operand for mul/div operation");
                return false;
            }
            switch(operation)
            {
                case 0:
                    vm_asm.push_back("mul " + operand1 + " " + operand2);
                    break;
                case 1:
                    vm_asm.push_back("div " + operand1 + " " + operand2);
                    break;
                case 2:
                    vm_asm.push_back("mod " + operand1 + " " + operand2);
                    break;
            }
            set_op_solution(op1_index, op2_index, operand1);
            op_flag = 0;
            i = start_block-1;
        }
    }

    if(op_flag == 2)
    {
        rc_setError("Expected operand for mul/div operation");
        return false;
    }

    return true;
}

bool eval_addsub(int start_block, int end_block)
{
    int op_flag = 0;
    string operand1 = "";
    string operand2 = "";

    int op1_index = 0;
    int op2_index = 0;
    int operation = 0; //0 - add, 1 - sub

    //cout << "\ndebug_AS " << start_block << " " << end_block << endl;
    //cout << "t_size" << token.size() << endl;
    //output_tokens();
    //cout << endl << "^^^^^^^^^^^^^^" << endl;

    for(int i = start_block; i <= end_block; i++)
    {
        if(token_exemption(i))
        {
            //cout << "hello: " << token[i] << endl;
            //op_flag = 0;
            continue;
        }

        if(token[i].compare("")!=0 &&
           token[i].compare("<add>")!=0 &&
           token[i].compare("<sub>")!=0 &&
           (op_flag == 0 || op_flag == 2))
        {
            switch(op_flag)
            {
                case 0:
                    operand1 = token[i];
                    //cout << "!!op1 = " << operand1 << endl;
                    op1_index = i;
                    op_flag = 1;
                    break;
                case 2:
                    operand2 = token[i];
                    //cout << "!!op2 = " << operand1 << endl;
                    op2_index = i;
                    op_flag = 3;
                    break;
            }
        }
        else if(token[i].compare("<add>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for add/sub operation : " + rc_intToString(op_flag) );
                return false;
            }
            op_flag = 2;
            operation = 0;

        }
        else if(token[i].compare("<sub>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for add/sub operation");
                return false;
            }
            op_flag = 2;
            operation = 1;
        }
        else if(token[i].compare("")!=0)
        {
            op_flag = 0;
        }

        if(op_flag==3)
        {
            switch(operation)
            {
                case 0:
                    if(operand1.substr(0,1).compare("n")==0 && operand2.substr(0,1).compare("n")==0)
                        vm_asm.push_back("add " + operand1 + " " + operand2);
                    else if(operand1.substr(0,1).compare("s")==0 && operand2.substr(0,1).compare("s")==0)
                        vm_asm.push_back("add$ " + operand1 + " " + operand2);
                    else
                    {
                        rc_setError("Incompatible operands for add operation: " + operand1 + ", " + operand2);
                        return false;
                    }
                    break;
                case 1:
                    if(operand1.substr(0,1).compare("n")==0 && operand2.substr(0,1).compare("n")==0)
                        vm_asm.push_back("sub " + operand1 + " " + operand2);
                    else
                    {
                        rc_setError("Incompatible operands for add operation");
                        return false;
                    }
                    break;
            }
            set_op_solution(op1_index, op2_index, operand1);
            op_flag = 0;
            i = start_block-1;
        }
    }

    if(op_flag == 2)
    {
        rc_setError("Expected operand for add/sub operation");
        return false;
    }

    return true;
}

bool eval_bitshift(int start_block, int end_block)
{
    int op_flag = 0;
    string operand1 = "";
    string operand2 = "";

    int op1_index = 0;
    int op2_index = 0;
    int operation = 0; //0 - add, 1 - sub

    //cout << "\ndebug_BS " << start_block << " " << end_block << endl;
    //cout << "t_size" << token.size() << endl;
    //output_tokens();
    //cout << endl << "^^^^^^^^^^^^^^" << endl;

    for(int i = start_block; i <= end_block; i++)
    {
        if(token_exemption(i))
        {
            //cout << "hello: " << token[i] << endl;
            //op_flag = 0;
            continue;
        }

        if(token[i].compare("")!=0 &&
           token[i].compare("<shl>")!=0 &&
           token[i].compare("<shr>")!=0 &&
           (op_flag == 0 || op_flag == 2))
        {
            switch(op_flag)
            {
                case 0:
                    operand1 = token[i];
                    //cout << "!!op1 = " << operand1 << endl;
                    op1_index = i;
                    op_flag = 1;
                    break;
                case 2:
                    operand2 = token[i];
                    //cout << "!!op2 = " << operand1 << endl;
                    op2_index = i;
                    op_flag = 3;
                    break;
            }
        }
        else if(token[i].compare("<shl>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for add/sub operation : " + rc_intToString(op_flag) );
                return false;
            }
            op_flag = 2;
            operation = 0;

        }
        else if(token[i].compare("<shr>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for add/sub operation");
                return false;
            }
            op_flag = 2;
            operation = 1;
        }
        else if(token[i].compare("")!=0)
        {
            op_flag = 0;
        }

        if(op_flag==3)
        {
            switch(operation)
            {
                case 0:
                    if(operand1.substr(0,1).compare("n")==0 && operand2.substr(0,1).compare("n")==0)
                        vm_asm.push_back("shl " + operand1 + " " + operand2);
                    else
                    {
                        rc_setError("Incompatible operands for shl operation");
                        return false;
                    }
                    break;
                case 1:
                    if(operand1.substr(0,1).compare("n")==0 && operand2.substr(0,1).compare("n")==0)
                        vm_asm.push_back("shr " + operand1 + " " + operand2);
                    else
                    {
                        rc_setError("Incompatible operands for shr operation");
                        return false;
                    }
                    break;
            }
            set_op_solution(op1_index, op2_index, operand1);
            op_flag = 0;
            i = start_block-1;
        }
    }

    if(op_flag == 2)
    {
        rc_setError("Expected operand for add/sub operation");
        return false;
    }

    return true;
}

bool eval_cmp(int start_block, int end_block)
{
    int op_flag = 0;
    string operand1 = "";
    string operand2 = "";

    int op1_index = 0;
    int op2_index = 0;
    int operation = 0; //0 - add, 1 - sub

    //cout << "\ndebug_AS " << start_block << " " << end_block << endl;
    //cout << "t_size" << token.size() << endl;
    //output_tokens();
    //cout << endl << "^^^^^^^^^^^^^^" << endl;

    for(int i = start_block; i <= end_block; i++)
    {
        if(token_exemption(i))
        {
            //cout << "hello: " << token[i] << endl;
            //op_flag = 0;
            continue;
        }

        if(token[i].compare("")!=0 &&
           token[i].compare("<less>")!=0 &&
           token[i].compare("<less_equal>")!=0 &&
           token[i].compare("<greater>")!=0 &&
           token[i].compare("<greater_equal>")!=0 &&
           token[i].compare("<equal>")!=0 &&
           token[i].compare("<not_equal>")!=0 &&
           (op_flag == 0 || op_flag == 2))
        {
            switch(op_flag)
            {
                case 0:
                    operand1 = token[i];
                    //cout << "!!op1 = " << operand1 << endl;
                    op1_index = i;
                    op_flag = 1;
                    break;
                case 2:
                    operand2 = token[i];
                    //cout << "!!op2 = " << operand1 << endl;
                    op2_index = i;
                    op_flag = 3;
                    break;
            }
        }
        else if(token[i].compare("<less>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for less operation : " + rc_intToString(op_flag) );
                return false;
            }
            op_flag = 2;
            operation = 0;

        }
        else if(token[i].compare("<less_equal>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for less/equal operation");
                return false;
            }
            op_flag = 2;
            operation = 1;
        }
        else if(token[i].compare("<greater>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for greater operation : " + rc_intToString(op_flag) );
                return false;
            }
            op_flag = 2;
            operation = 2;

        }
        else if(token[i].compare("<greater_equal>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for greater/equal operation");
                return false;
            }
            op_flag = 2;
            operation = 3;
        }
        else if(token[i].compare("<equal>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for equal operation : " + rc_intToString(op_flag) );
                return false;
            }
            op_flag = 2;
            operation = 4;

        }
        else if(token[i].compare("<not_equal>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for not equal operation");
                return false;
            }
            op_flag = 2;
            operation = 5;
        }
        else if(token[i].compare("")!=0)
        {
            op_flag = 0;
        }

        if(op_flag==3)
        {
            if(operand1.substr(0,1).compare("n")==0 && operand2.substr(0,1).compare("n")==0)
                vm_asm.push_back("cmp " + operand1 + " " + operand2);
            else if(operand1.substr(0,1).compare("s")==0 && operand2.substr(0,1).compare("s")==0)
                vm_asm.push_back("cmp$ " + operand1 + " " + operand2);
            else
            {
                rc_setError("Mismatch types in comparison operation");
                return false;
            }
            string solution = "n" + rc_intToString(n_reg);
            inc_n(1);
            switch(operation)
            {
                case 0:
                    vm_asm.push_back("mov " + solution + " %LESS_FLAG");
                    break;
                case 1:
                    vm_asm.push_back("mov " + solution + " %LESS_EQUAL_FLAG");
                    break;
                case 2:
                    vm_asm.push_back("mov " + solution + " %GREATER_FLAG");
                    break;
                case 3:
                    vm_asm.push_back("mov " + solution + " %GREATER_EQUAL_FLAG");
                    break;
                case 4:
                    vm_asm.push_back("mov " + solution + " %EQUAL_FLAG");
                    break;
                case 5:
                    vm_asm.push_back("mov " + solution + " %NOT_EQUAL_FLAG");
                    break;
            }
            set_op_solution(op1_index, op2_index, solution);
            op_flag = 0;
            i = start_block-1;
        }
    }

    if(op_flag == 2)
    {
        rc_setError("Expected operand for add/sub operation");
        return false;
    }

    return true;
}

bool eval_andor(int start_block, int end_block)
{
    int op_flag = 0;
    string operand1 = "";
    string operand2 = "";

    int op1_index = 0;
    int op2_index = 0;
    int operation = 0; //0 - add, 1 - sub

    //cout << "\ndebug_AND " << start_block << " " << end_block << endl;
    //cout << "t_size" << token.size() << endl;
    //output_tokens();
    //cout << endl << "^^^^^^^^^^^^^^" << endl;

    for(int i = start_block; i <= end_block; i++)
    {
        if(token_exemption(i))
        {
            //cout << "hello: " << token[i] << endl;
            //op_flag = 0;
            continue;
        }

        if(token[i].compare("")!=0 &&
           token[i].compare("<and>")!=0 &&
           token[i].compare("<or>")!=0 &&
           token[i].compare("<xor>")!=0 &&
           (op_flag == 0 || op_flag == 2))
        {
            switch(op_flag)
            {
                case 0:
                    operand1 = token[i];
                    //cout << "!!op1 = " << operand1 << endl;
                    op1_index = i;
                    op_flag = 1;
                    break;
                case 2:
                    operand2 = token[i];
                    //cout << "!!op2 = " << operand1 << endl;
                    op2_index = i;
                    op_flag = 3;
                    break;
            }
        }
        else if(token[i].compare("<and>")==0)
        {
            //cout << "AND OPERATION" << endl;
            if(op_flag != 1)
            {
                rc_setError("Missing operand for and operation : " + rc_intToString(op_flag) );
                return false;
            }
            op_flag = 2;
            operation = 0;

        }
        else if(token[i].compare("<or>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for or operation");
                return false;
            }
            op_flag = 2;
            operation = 1;
        }
        else if(token[i].compare("<xor>")==0)
        {
            if(op_flag != 1)
            {
                rc_setError("Missing operand for xor operation : " + rc_intToString(op_flag) );
                return false;
            }
            op_flag = 2;
            operation = 2;

        }
        else if(token[i].compare("")!=0)
        {
            op_flag = 0;
        }

        if(op_flag==3)
        {
            switch(operation)
            {
                case 0:
                    if(operand1.substr(0,1).compare("n")==0 && operand2.substr(0,1).compare("n")==0)
                        vm_asm.push_back("and " + operand1 + " " + operand2);
                    else
                    {
                        rc_setError("Incompatible operands for and operation");
                        return false;
                    }
                    break;
                case 1:
                    if(operand1.substr(0,1).compare("n")==0 && operand2.substr(0,1).compare("n")==0)
                        vm_asm.push_back("or " + operand1 + " " + operand2);
                    else
                    {
                        rc_setError("Incompatible operands for or operation");
                        return false;
                    }
                    break;
                case 2:
                    if(operand1.substr(0,1).compare("n")==0 && operand2.substr(0,1).compare("n")==0)
                        vm_asm.push_back("xor " + operand1 + " " + operand2);
                    else
                    {
                        rc_setError("Incompatible operands for xor operation");
                        return false;
                    }
                    break;
            }
            set_op_solution(op1_index, op2_index, operand1);
            op_flag = 0;
            i = start_block-1;
        }
    }

    if(op_flag == 2)
    {
        rc_setError("Expected operand for add/sub operation");
        return false;
    }

    return true;
}

bool eval_not(int start_block, int end_block)
{
    int op_flag = 0;
    string operand1 = "";
    string operand2 = "";

    int op1_index = 0;
    int op2_index = 0;
    int operation = 0; //0 - add, 1 - sub

    //cout << "\ndebug_AS " << start_block << " " << end_block << endl;
    //cout << "t_size" << token.size() << endl;
    //output_tokens();
    //cout << endl << "^^^^^^^^^^^^^^" << endl;

    for(int i = start_block; i <= end_block; i++)
    {
        if(token_exemption(i))
        {
            //cout << "hello: " << token[i] << endl;
            //op_flag = 0;
            continue;
        }

        if(token[i].compare("")!=0 &&
           token[i].compare("<not>")!=0 &&
           op_flag == 1)
        {

            operand1 = token[i];
            //cout << "!!op1 = " << operand1 << endl;
            op2_index = i;
            op_flag = 2;
        }
        else if(token[i].compare("<not>")==0)
        {
            op1_index = i;
            op_flag = 1;
        }
        else if(token[i].compare("")!=0)
        {
            op_flag = 0;
        }

        if(op_flag==2)
        {
            if(operand1.substr(0,1).compare("n")==0)
                vm_asm.push_back("not " + operand1);
            else
            {
                rc_setError("Incompatible operands for and operation");
                return false;
            }
            set_op_solution(op1_index, op2_index, operand1);
            op_flag = 0;
            i = start_block-1;
        }
    }

    if(op_flag == 2)
    {
        rc_setError("Expected operand for add/sub operation");
        return false;
    }

    return true;
}

//still need to store negative numbers properly
#define PP_FLAG_NONE 0
#define PP_FLAG_ARRAY 1

int getArrayObjStart(int arg_id)
{
    string start_arg = "n" + rc_intToString(n_reg);
    inc_n(1);
    vm_asm.push_back("mov " + start_arg + " 0");
    if(id[arg_id].type == ID_TYPE_ARR_NUM)
    {
        switch(id[arg_id].num_args)
        {
            case 1:
                vm_asm.push_back("obj_num1 !" + rc_intToString(id[arg_id].vec_pos) + " " + start_arg);
                break;
            case 2:
                vm_asm.push_back("obj_num2 !" + rc_intToString(id[arg_id].vec_pos) + " " + start_arg + " " + start_arg);
                break;
            case 3:
                vm_asm.push_back("obj_num3 !" + rc_intToString(id[arg_id].vec_pos) + " " + start_arg + " " + start_arg + " " + start_arg);
                break;
        }
        int obj_n = n_reg;
        inc_n(1);
        vm_asm.push_back("obj_get n" + rc_intToString(obj_n));
        return obj_n;
    }
    else if(id[arg_id].type == ID_TYPE_ARR_STR)
    {
        switch(id[arg_id].num_args)
        {
            case 1:
                vm_asm.push_back("obj_str1 !" + rc_intToString(id[arg_id].vec_pos) + " " + start_arg);
                break;
            case 2:
                vm_asm.push_back("obj_str2 !" + rc_intToString(id[arg_id].vec_pos) + " " + start_arg + " " + start_arg);
                break;
            case 3:
                vm_asm.push_back("obj_str3 !" + rc_intToString(id[arg_id].vec_pos) + " " + start_arg + " " + start_arg + " " + start_arg);
                break;
        }
        int obj_s = s_reg;
        inc_s(1);
        vm_asm.push_back("obj_get$ s" + rc_intToString(obj_s));
        return obj_s;
    }

    return 0;

}

bool byref_type_generic(string utype_name)
{
    if(utype_name.compare("empty")==0)
        return true;
    return false;
}


bool pre_parse(int start_token = 0, int end_token = -1, int pp_flags, bool eval_udt)
{

    if(end_token == -1)
    {
        end_token = token.size();
    }

    int n_flag = 0; // id num ] ) } ,
    string n = "";
    string s = "";
    string u = "";
    int expr_id = -1;
    string sdata = "";

    bool byref_type_flag = false;

    for(int i = start_token; i <= end_token; i++)
    {
        if(token[i].substr(0,5).compare("<num>")==0)
        {
            //cout << "WISHING FOR A MIRACLE" << endl;
            n = "n" + rc_intToString(n_reg);
            vm_asm.push_back("mov " + n + " " + token[i].substr(5));
            token[i] = n;
            inc_n(1);
        }
        else if(token[i].substr(0,8).compare("<string>")==0)
        {
            //store strings in data
            sdata = token[i].substr(8);
            int sdata_addr = data_segment.size();
            for(int n = 0; n < sdata.length(); n++)
            {
                data_segment.push_back(sdata[n]);
            }
            data_segment.push_back('\0');
            string token_replace = "s" + rc_intToString(s_reg);
            inc_s(1);
            vm_asm.push_back("mov$ " + token_replace + " @" + rc_intToString(sdata_addr));
            token[i] = token_replace;
        }
        else if(token[i].substr(0,4).compare("<id>")==0)
        {
            //cout << "ID: " << token[i].substr(4) << endl;
            //more needs to be done here
            n = "n" + rc_intToString(n_reg);
            s = "s" + rc_intToString(s_reg);
            u = "u" + rc_intToString(u_reg);

            expr_id = getIDInScope_ByIndex(token[i].substr(4));

            //cout << "expr = " << expr_id << endl;
            //cout << "TYPE: " << id[expr_id].type << endl << endl;

            bool is_udt_member = false;

            if(i > 0)
                if(token[i-1].compare("<child>")==0)
                    is_udt_member = true;

            if(is_udt_member)
                continue;


            if(expr_id < 0)
            {
                //rc_setError(token[i].substr(4) + " was not found in this scope+:  " + current_scope);
                rc_setError(token[i].substr(4) + " was not found in this scope");
                //output_vars();
                return false;
            }
//            else if(id[expr_id].type == ID_TYPE_BYREF_NUM)
//            {
//                vm_asm.push_back("mov " + n + " !" + rc_intToString(id[expr_id].vec_pos));
//                resolveID_id_reg.push_back(n);
//                resolveID_id_type.push_back(id[expr_id].type);
//                resolveID_id_ut_index.push_back(id[expr_id].type_index);
//                token[i] = n;
//                inc_n(1);
//            }
            else if(id[expr_id].type == ID_TYPE_NUM)
            {
                //cout << endl << "COME ON: " << id[expr_id].name << endl;
                vm_asm.push_back("mov " + n + " !" + rc_intToString(id[expr_id].vec_pos));
                resolveID_id_reg.push_back(n);
                resolveID_id_type.push_back(id[expr_id].type);
                resolveID_id_ut_index.push_back(id[expr_id].type_index);
                resolveID_id_vec_pos.push_back(expr_id);
                token[i] = n;
                inc_n(1);
            }
            else if(id[expr_id].type == ID_TYPE_STR)
            {
                vm_asm.push_back("mov$ " + s + " !" + rc_intToString(id[expr_id].vec_pos));
                resolveID_id_reg.push_back(s);
                resolveID_id_type.push_back(id[expr_id].type);
                resolveID_id_ut_index.push_back(id[expr_id].type_index);
                resolveID_id_vec_pos.push_back(expr_id);
                token[i] = s;
                inc_s(1);
            }
            else if( (id[expr_id].type == ID_TYPE_BYREF_NUM || id[expr_id].type == ID_TYPE_BYREF_STR) && pp_flags == PP_FLAG_ARRAY)
            {
                //cout << "found array: " << id[expr_id].name << endl << endl;
                int s_scope = 0;
                int arr_token_start = i;
                int arr_token_end = i;
                string args[512];
                int num_args = 0;

                int p_scope = 0;

                if( (i+1) <= end_token)
                {
                    if(token[i+1].compare("!<square>")==0)
                    {
                        s_scope = 1;
                        for(i += 2; (i <= end_token) && (s_scope != 0); i++)
                        {
                            if(token[i].compare("!</square>")==0)
                            {
                                s_scope--;
                                if(s_scope == 0)
                                {
                                    num_args++;
                                    arr_token_end = i;
                                }
                            }
                            else if(token[i].compare("!<square>")==0)
                                s_scope++;
                            else if(token[i].compare("!<comma>")==0)
                                num_args++;
                            else if(token[i].substr(0,1).compare("n")==0)
                                args[num_args] = token[i];
                            else if(token[i].compare("!<par>")==0)
                                p_scope++;
                            else if(token[i].compare("!</par>")==0)
                                p_scope--;
                            else if(token[i].compare("")!=0)
                            {
                                rc_setError("Expected number");
                                return false;
                            }
                        }
                        if(p_scope > 0)
                        {
                            rc_setError("Parenthesis Block was not closed");
                            return false;
                        }
                        else if(p_scope < 0)
                        {
                            rc_setError("Parenthesis Block was not opened");
                            return false;
                        }
                        if(s_scope != 0)
                        {
                            rc_setError("Expected closing ]");
                            return false;
                        }
                    }
                }

                if(num_args > 1)
                {
                    rc_setError("In " + id[expr_id].name + " Expected 0 to 1 dimensions and found " + rc_intToString(num_args));
                    return false;
                }

                if(id[expr_id].type == ID_TYPE_BYREF_NUM && num_args == 0)
                {
                    vm_asm.push_back("mov " + n + " !" + rc_intToString(id[expr_id].vec_pos));
                    resolveID_id_reg.push_back(n);
                    resolveID_id_type.push_back(id[expr_id].type);
                    resolveID_id_ut_index.push_back(id[expr_id].type_index);
                    resolveID_id_vec_pos.push_back(expr_id);
                    token[i] = n;
                    inc_n(1);
                    continue;
                }
                else if(id[expr_id].type == ID_TYPE_BYREF_STR && num_args == 0)
                {
                    vm_asm.push_back("mov$ " + s + " !" + rc_intToString(id[expr_id].vec_pos));
                    resolveID_id_reg.push_back(s);
                    resolveID_id_type.push_back(id[expr_id].type);
                    resolveID_id_ut_index.push_back(id[expr_id].type_index);
                    resolveID_id_vec_pos.push_back(expr_id);
                    token[i] = s;
                    inc_s(1);
                    continue;
                }



                if(args[0].substr(0,1).compare("n")!=0)
                {
                    rc_setError("Invalid number of args in array");
                    return false;
                }


                string token_replace = "";

                if(id[expr_id].type == ID_TYPE_BYREF_NUM)
                {
                    //vm_asm.push_back("clear_obj");
                    vm_asm.push_back("obj_num1 !" + rc_intToString(id[expr_id].vec_pos) + " " + args[0]);
                    token_replace = "n" + rc_intToString(n_reg);
                    inc_n(1);
                    vm_asm.push_back("obj_get " + token_replace);
                }
                else
                {
                    //vm_asm.push_back("clear_obj");
                    vm_asm.push_back("obj_str1 !" + rc_intToString(id[expr_id].vec_pos) + " " + args[0]);
                    token_replace = "s" + rc_intToString(s_reg);
                    inc_s(1);
                    vm_asm.push_back("obj_get$ " + token_replace);
                }


                resolveID_id_reg.push_back(token_replace);
                resolveID_id_type.push_back(id[expr_id].type);
                resolveID_id_ut_index.push_back(id[expr_id].type_index);
                resolveID_id_vec_pos.push_back(expr_id);

                for(int p = arr_token_start; p <= arr_token_end; p++)
                    token[p] = "";

                if(token_replace.compare("")==0)
                {
                    rc_setError("%%could not resolve array " + id[expr_id].name);
                    return false;
                }

                token[arr_token_start] = token_replace;

                //cout << "the end of array" << endl;

            }
            else if( ID_TYPE_USER_ALL(expr_id) && eval_udt )
            {
                //cout << "-Parsing User Variable: " << id[expr_id].name << endl;
                //cout << "----------------------------------------------- : " << eval_udt << endl;

                bool udt_id_init = true;

                string tmp_scope = id[expr_id].scope;


                /*for(int t = i; t < token.size(); t++)
                {
                    try
                    {
                        cout << t << ":" << token.at(t) << endl;
                    }
                    catch(out_of_range& e)
                    {
                        cout << "Token Out of Range Error: " << e.what() << endl;
                    }
                }*/


                int tmp_id = 0;
                bool has_child = false;

                int num_id_parents = 0;
                int num_id_children = 0;
                byref_type_flag = false;


                for(int t = i; t <= end_token; t++)
                {

                    if(token[t].substr(0,4).compare("<id>")==0)
                    {
                        if(num_id_parents != num_id_children)
                        {
                            rc_setError("Expected member separator or member ID");
                            return false;
                        }

                        num_id_parents++;
                        //cout << "FIGURE IT OUT: " << t  << endl;
                        string args[3];
                        int arg_count = 0;
                        string full_id = token[t].substr(4);
                        token[t] = "";
                        tmp_id = getIDInScope_ByIndex_TypeMatch(full_id, tmp_scope);
                        //cout << "\ntmp_id = " << tmp_id << endl;

                        if(tmp_id < 0)
                        {
                            rc_setError(tmp_scope.substr(5) + " does not have member [" + full_id + "]");
                            return false;
                        }

                        //cout << "Scope = " << tmp_scope << "  ID = " << full_id << "  --  " << tmp_id << endl << endl;

                        tmp_scope += "." + full_id;


                        //get arguments (ie. the dimensions of an array
                        int t2 = t+1;

                        if(t2 < end_token)
                        {
                            int arr_scope = 0;
                            if(token[t2].compare("!<square>")==0)
                            {
                                token[t2] = "";
                                args[0] = "";
                                args[1] = "";
                                args[2] = "";
                                arg_count = 0;
                                arr_scope = 1;
                                t2++;
                                //cout << "T2 = " << t2 << endl << endl;

                                for(; t2 <= end_token; t2++)
                                {
                                    //cout << "DBG ARR: " << t2 << ", " << end_token << " : " << token[t2] << endl;
                                    if(token[t2].compare("!</square>")==0)
                                        arr_scope--;
                                    else if(token[t2].compare("!<square>")==0)
                                        arr_scope++;
                                    else if(token[t2].compare("!<comma>")==0)
                                        arg_count++;
                                    else if(token[t2].substr(0,1).compare("n")==0)
                                    {
                                        if(args[arg_count].compare("")==0)
                                            args[arg_count] = token[t2];
                                        else
                                        {
                                            rc_setError("Error parsing array dimension: " + args[arg_count] + " :: " + token[t2] + " -- " + rc_intToString(t2) + ", " + rc_intToString(arg_count));
                                            return false;
                                        }
                                    }

                                    token[t2] = "";

                                    if(arg_count >= 3)
                                    {
                                        rc_setError("Too many dimensions in array");
                                        return false;
                                    }

                                    if(arr_scope == 0)
                                        break;

                                }

                                if(arr_scope > 0)
                                {
                                    rc_setError("Expected ]] in expression: " + rc_intToString(arr_scope));
                                    return false;
                                }

                                arg_count++;
                            }
                            else if(type_delete_flag || type_redim_flag)
                                t2--;

                        }


                        has_child = false;
                        if((t2+1) < token.size())
                        {
                            if(token[t2+1].compare("<child>")==0)
                            {
                                has_child = true;
                            }
                            //cout << "Has Child = " << has_child << ", " << t << ", " << t2 << endl;
                        }

                        if(type_delete_flag && (!has_child) && arg_count != 0)
                        {
                            rc_setError("Expected identifier without index");
                            return false;
                        }


                        if(arg_count != id[tmp_id].num_args)
                        {
                            if(type_redim_flag)
                            {
                                if(has_child)
                                {
                                    rc_setError("[1]Expected " + rc_intToString(id[tmp_id].num_args) + " dimension in " + id[tmp_id].name);
                                    return false;
                                }
                            }
                            else if(!type_delete_flag)
                            {
                                if(arg_count != 0)
                                {
                                    rc_setError("[0]Expected " + rc_intToString(id[tmp_id].num_args) + " dimension in " + id[tmp_id].name);
                                    return false;
                                }

                                //cout << "ID_TYPE = " << id[tmp_id].type << ", " << arg_count << ", " << (has_child ? "true" : "false")  << endl;

                                args[0] = "";
                                args[1] = "";
                                args[2] = "";

                                string tmp_instruction = "obj_usr_";

                                //trying stuff out
                                if(id[tmp_id].type == ID_TYPE_USER_NUM)
                                {
                                    vm_asm.push_back("mov " + n + " 0");
                                    tmp_instruction += "n" + ( id[tmp_id].num_args <= 0 ? "" : rc_intToString(id[tmp_id].num_args) );
                                    for(int tmp_arg_i = 0; tmp_arg_i < id[tmp_id].num_args; tmp_arg_i++)
                                        args[tmp_arg_i] = n;


                                    vm_asm.push_back(tmp_instruction + " !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                    byref_type_flag = true;
                                    break;
                                }
                                else if(id[tmp_id].type == ID_TYPE_USER_STR)
                                {
                                    vm_asm.push_back("mov " + n + " 0");
                                    tmp_instruction += "s" + ( id[tmp_id].num_args <= 0 ? "" : rc_intToString(id[tmp_id].num_args) );
                                    for(int tmp_arg_i = 0; tmp_arg_i < id[tmp_id].num_args; tmp_arg_i++)
                                        args[tmp_arg_i] = n;

                                    vm_asm.push_back(tmp_instruction + " !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                    byref_type_flag = true;
                                    break;
                                }
                                else if(id[tmp_id].type == ID_TYPE_USER)
                                {
                                    if(udt_id_init)
                                        tmp_instruction = "obj_usr_init";
                                    else
                                        tmp_instruction = "obj_usr";
                                    vm_asm.push_back("mov " + n + " 0");
                                    tmp_instruction += ( id[tmp_id].num_args <= 0 ? "" : rc_intToString(id[tmp_id].num_args) );
                                    for(int tmp_arg_i = 0; tmp_arg_i < id[tmp_id].num_args; tmp_arg_i++)
                                        args[tmp_arg_i] = n;

                                    vm_asm.push_back(tmp_instruction + " !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                    byref_type_flag = true;
                                    break;
                                }
                                //-------------------------------

                                return false;
                            }
                            else
                            {
                                if(has_child)
                                {
                                    rc_setError("[1]Expected " + rc_intToString(id[tmp_id].num_args) + " dimension in " + id[tmp_id].name);
                                    return false;
                                }

                                arg_count = id[tmp_id].num_args;
                                //vm_asm.push_back("mov n" + rc_intToString(n_reg) + " 0");
                                //args[0] = "n" + rc_intToString(n_reg);
                                //args[1] = args[0];
                                //args[2] = args[0];
                                //inc_n(1);
                            }
                        }

                        if(type_redim_flag && (!has_child))
                        {
                            //cout << "NO CHILD: " << id[tmp_id].name << " -- arg_count = " << arg_count << " -- arg[0] = " << args[0] << endl;
                            type_redim_dim_count = arg_count;
                            type_redim_dim[0] = args[0];
                            type_redim_dim[1] = args[1];
                            type_redim_dim[2] = args[2];

                            if(arg_count != id[tmp_id].num_args)
                            {
                                rc_setError("Expected " + rc_intToString(id[tmp_id].num_args) + " dimensions but found " + rc_intToString(arg_count));
                                return false;
                            }
                        }
                        else if(type_delete_flag && (!has_child))
                        {
                            //DO NOTHING
                            //cout << "NO CHILD: " << id[tmp_id].name << endl;
                        }
                        else
                        {
                            //if(type_delete_flag)
                                //cout << "TESTING STUFF" << endl;

                            switch(arg_count)
                            {
                                case 0:
                                    if(id[tmp_id].type == ID_TYPE_USER || id[tmp_id].type == ID_TYPE_BYREF_USER)
                                    {
                                        if(udt_id_init)
                                            vm_asm.push_back("obj_usr_init !" + rc_intToString(id[tmp_id].vec_pos));
                                        else
                                            vm_asm.push_back("obj_usr !" + rc_intToString(id[tmp_id].vec_pos));
                                    }
                                    else if(id[tmp_id].type == ID_TYPE_USER_NUM)
                                        vm_asm.push_back("obj_usr_n !" + rc_intToString(id[tmp_id].vec_pos));
                                    else if(id[tmp_id].type == ID_TYPE_USER_STR)
                                        vm_asm.push_back("obj_usr_s !" + rc_intToString(id[tmp_id].vec_pos));
                                    else
                                    {
                                        rc_setError("Invalid type in User Defined Type");
                                        return false;
                                    }
                                    break;
                                case 1:
                                    if(id[tmp_id].type == ID_TYPE_USER || id[tmp_id].type == ID_TYPE_BYREF_USER)
                                    {
                                        if(udt_id_init)
                                            vm_asm.push_back("obj_usr_init1 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0]);
                                        else
                                            vm_asm.push_back("obj_usr1 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0]);
                                    }
                                    else if(id[tmp_id].type == ID_TYPE_USER_NUM)
                                        vm_asm.push_back("obj_usr_n1 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0]);
                                    else if(id[tmp_id].type == ID_TYPE_USER_STR)
                                        vm_asm.push_back("obj_usr_s1 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0]);
                                    else
                                    {
                                        rc_setError("Invalid type in User Defined Type");
                                        return false;
                                    }
                                    break;
                                case 2:
                                    if(id[tmp_id].type == ID_TYPE_USER || id[tmp_id].type == ID_TYPE_BYREF_USER)
                                    {
                                        if(udt_id_init)
                                            vm_asm.push_back("obj_usr_init2 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1]);
                                        else
                                            vm_asm.push_back("obj_usr2 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1]);
                                    }
                                    else if(id[tmp_id].type == ID_TYPE_USER_NUM)
                                        vm_asm.push_back("obj_usr_n2 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1]);
                                    else if(id[tmp_id].type == ID_TYPE_USER_STR)
                                        vm_asm.push_back("obj_usr_s2 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1]);
                                    else
                                    {
                                        rc_setError("Invalid type in User Defined Type");
                                        return false;
                                    }
                                    break;
                                case 3:
                                    if(id[tmp_id].type == ID_TYPE_USER || id[tmp_id].type == ID_TYPE_BYREF_USER)
                                    {
                                        if(udt_id_init)
                                            vm_asm.push_back("obj_usr_init3 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                        else
                                            vm_asm.push_back("obj_usr3 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                    }
                                    else if(id[tmp_id].type == ID_TYPE_USER_NUM)
                                        vm_asm.push_back("obj_usr_n3 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                    else if(id[tmp_id].type == ID_TYPE_USER_STR)
                                        vm_asm.push_back("obj_usr_s3 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                    else
                                    {
                                        rc_setError("Invalid type in User Defined Type");
                                        return false;
                                    }
                                    break;
                            }

                            udt_id_init = false;
                        }



                    }
                    else if(token[t].compare("<child>")==0)
                    {
                        num_id_children++;
                        type_delete_arg_whole = false;
                        token[t] = "";
                        continue;
                    }
                    else if(token[t].compare("")!=0)
                    {
                        break;
                    }

                }


                //START HERE
                if(type_redim_flag && (!has_child))
                {
                    type_redim_arg = "!" + rc_intToString(id[tmp_id].vec_pos);
                    type_redim_arg_type = id[tmp_id].type;
                    type_redim_arg_utype = "!" + rc_intToString(id[tmp_id].type_index);
                }
                else if(type_delete_flag && (!has_child))
                {
                    //cout << "DELETE_VAR = " << id[tmp_id].name << endl;
                    type_delete_arg = "!" + rc_intToString(id[tmp_id].vec_pos);
                    type_delete_arg_type = id[tmp_id].type;
                }
                else
                switch(id[tmp_id].type)
                {
                    case ID_TYPE_USER:
                    case ID_TYPE_BYREF_USER:
                        //cout << "test --> " << u << ", " << id[tmp_id].name << endl;
                        vm_asm.push_back("obj_usr_get " + u);
                        token[i] = u;
                        resolveID_id_reg.push_back(token[i]);
                        resolveID_id_type.push_back(id[tmp_id].type);
                        resolveID_id_ut_index.push_back(id[tmp_id].type_index);
                        resolveID_id_vec_pos.push_back(tmp_id);
                        inc_u(1);
                        break;
                    case ID_TYPE_USER_NUM:
                        vm_asm.push_back("obj_usr_get " + n);
                        token[i] = n;

                        //cout << "GET N: " << n << ", " << id[tmp_id].scope << " :: " << id[tmp_id].name << endl;
                        resolveID_id_reg.push_back(token[i]);
                        resolveID_id_type.push_back(id[tmp_id].type);
                        resolveID_id_ut_index.push_back(id[tmp_id].type_index);
                        resolveID_id_vec_pos.push_back(tmp_id);

                        inc_n(1);
                        break;
                    case ID_TYPE_USER_STR:
                        vm_asm.push_back("obj_usr_get " + s);
                        token[i] = s;

                        resolveID_id_reg.push_back(token[i]);
                        resolveID_id_type.push_back(id[tmp_id].type);
                        resolveID_id_ut_index.push_back(id[tmp_id].type_index);
                        resolveID_id_vec_pos.push_back(tmp_id);

                        inc_s(1);
                        break;
                    default:
                        break;
                }

                if(byref_type_flag)
                {
                    type_error_exception tx;
                    tx.error_log = "[0]Expected " + rc_intToString(id[tmp_id].num_args) + " dimension in " + id[tmp_id].name;
                    tx.tk_reg = token[i];
                    tx.num_args = id[tmp_id].num_args;
                    tx.exception_used = false;
                    //cout << "!!!! type_no_arg_exception_raised = false;" << endl;
                    //cout << "store = " << id[tmp_id].name << " = " << tx.tk_reg << "   arg_count = " << arg_count << ", expected = " << id[tmp_id].num_args << endl;
                    byref_type_exception.push_back(tx);
                    byref_type_flag = false;
                    type_no_arg_exception_raised = true;
                }


                /*
                cout << "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl;

                for(int t = 0; t < token.size(); t++)
                {
                    try
                    {
                        cout << t << ":" << token.at(t) << endl;
                    }
                    catch(out_of_range& e)
                    {
                        cout << "Token Out of Range Error: " << e.what() << endl;
                    }
                }

                cout << "-----------------------------------------------" << endl;
                */


                //for(int t = 0; t < id.size(); t++)
                  //  if(id[t].type == ID_TYPE_USER) cout << "ID[" << id[t].name << "]  SCOPE=" << id[t].scope << "  --  " << id[t].vec_pos << endl;

            }
            else if( (id[expr_id].type == ID_TYPE_ARR_NUM || id[expr_id].type == ID_TYPE_ARR_STR) && pp_flags == PP_FLAG_ARRAY)
            {
                //cout << "found array: " << id[expr_id].name << endl << endl;
                int s_scope = 0;
                int arr_token_start = i;
                int arr_token_end = i;
                string args[3];
                int num_args = 0;

                int p_scope = 0;

                if( (i+1) <= end_token)
                {
                    if(token[i+1].compare("!<square>")==0)
                    {
                        s_scope = 1;
                        for(i += 2; (i <= end_token) && (s_scope != 0); i++)
                        {
                            if(token[i].compare("!</square>")==0)
                            {
                                s_scope--;
                                if(s_scope == 0)
                                {
                                    num_args++;
                                    arr_token_end = i;
                                }
                            }
                            else if(token[i].compare("!<square>")==0)
                                s_scope++;
                            else if(token[i].compare("!<comma>")==0)
                                num_args++;
                            else if(token[i].substr(0,1).compare("n")==0)
                                args[num_args] = token[i];
                            else if(token[i].compare("!<par>")==0)
                                p_scope++;
                            else if(token[i].compare("!</par>")==0)
                                p_scope--;
                            else if(token[i].compare("")!=0)
                            {
                                rc_setError("Expected number");
                                return false;
                            }
                        }
                        if(p_scope > 0)
                        {
                            rc_setError("Parenthesis Block was not closed");
                            return false;
                        }
                        else if(p_scope < 0)
                        {
                            rc_setError("Parenthesis Block was not opened");
                            return false;
                        }
                    }
                }
                //cout << endl << "ID_ARRAY: " << id[expr_id].name << endl;
                //cout << "NUM_ARGS_EXPECTED: " << id[expr_id].num_args << endl;
                //cout << "NUM_ARGS_FOUND: " << num_args << endl;

                if(id[expr_id].isArrayArg)
                {
                    //cout << "array arg found" << endl;
                    id[expr_id].isArrayArg = false;
                    string token_replace = "";
                    if(id[expr_id].type == ID_TYPE_ARR_NUM)
                    {
                        token_replace = "n" + rc_intToString(n_reg);
                        inc_n(1);
                        vm_asm.push_back("mov_arr " + token_replace + " !" + rc_intToString(id[expr_id].vec_pos));

                    }
                    else
                    {
                        token_replace = "s" + rc_intToString(s_reg);
                        inc_s(1);
                        vm_asm.push_back("mov_arr$ " + token_replace + " !" + rc_intToString(id[expr_id].vec_pos));
                    }

                    resolveID_id_reg.push_back(token_replace);
                    resolveID_id_type.push_back(id[expr_id].type);
                    resolveID_id_ut_index.push_back(id[expr_id].type_index);
                    resolveID_id_vec_pos.push_back(expr_id);

                    for(int p = arr_token_start; p <= arr_token_end; p++)
                        token[p] = "";

                    token[arr_token_start] = token_replace;
                    continue;
                }

                if(id[expr_id].num_args != num_args)
                {
                    if(num_args == 0)
                        continue;

                    rc_setError("In " + id[expr_id].name + " Expected " + rc_intToString(id[expr_id].num_args) + " dimensions and found " + rc_intToString(num_args));
                    return false;
                }

                for(int n = 0; n < id[expr_id].num_args; n++)
                {
                    //cout << "arg " << n << ": " << args[n] << endl;
                    if(args[n].substr(0,1).compare("n")!=0)
                    {
                        rc_setError("Invalid number of args in array");
                        return false;
                    }
                }

                string token_replace = "";

                switch(num_args)
                {

                    case 1:
                        if(id[expr_id].type == ID_TYPE_ARR_NUM)
                        {
                            //vm_asm.push_back("clear_obj");
                            vm_asm.push_back("obj_num1 !" + rc_intToString(id[expr_id].vec_pos) + " " + args[0]);
                            token_replace = "n" + rc_intToString(n_reg);
                            inc_n(1);
                            vm_asm.push_back("obj_get " + token_replace);
                        }
                        else
                        {
                            //vm_asm.push_back("clear_obj");
                            vm_asm.push_back("obj_str1 !" + rc_intToString(id[expr_id].vec_pos) + " " + args[0]);
                            token_replace = "s" + rc_intToString(s_reg);
                            inc_s(1);
                            vm_asm.push_back("obj_get$ " + token_replace);
                        }
                        break;
                    case 2:
                        if(id[expr_id].type == ID_TYPE_ARR_NUM)
                        {
                            //vm_asm.push_back("clear_obj");
                            vm_asm.push_back("obj_num2 !" + rc_intToString(id[expr_id].vec_pos) + " " + args[0] + " " + args[1]);
                            token_replace = "n" + rc_intToString(n_reg);
                            inc_n(1);
                            vm_asm.push_back("obj_get " + token_replace);
                        }
                        else
                        {
                            //vm_asm.push_back("clear_obj");
                            vm_asm.push_back("obj_str2 !" + rc_intToString(id[expr_id].vec_pos) + " " + args[0] + " " + args[1]);
                            token_replace = "s" + rc_intToString(s_reg);
                            inc_s(1);
                            vm_asm.push_back("obj_get$ " + token_replace);
                        }
                        break;
                    case 3:
                        if(id[expr_id].type == ID_TYPE_ARR_NUM)
                        {
                            //vm_asm.push_back("clear_obj");
                            vm_asm.push_back("obj_num3 !" + rc_intToString(id[expr_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                            token_replace = "n" + rc_intToString(n_reg);
                            inc_n(1);
                            vm_asm.push_back("obj_get " + token_replace);
                        }
                        else
                        {
                            //vm_asm.push_back("clear_obj");
                            vm_asm.push_back("obj_str3 !" + rc_intToString(id[expr_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                            token_replace = "s" + rc_intToString(s_reg);
                            inc_s(1);
                            vm_asm.push_back("obj_get$ " + token_replace);
                        }
                        break;
                    default:
                        rc_setError("Invalid number of dimensions in array");
                        return false;
                }

                resolveID_id_reg.push_back(token_replace);
                resolveID_id_type.push_back(id[expr_id].type);
                resolveID_id_ut_index.push_back(id[expr_id].type_index);
                resolveID_id_vec_pos.push_back(expr_id);

                for(int p = arr_token_start; p <= arr_token_end; p++)
                    token[p] = "";

                if(token_replace.compare("")==0)
                {
                    rc_setError("Could not resolve array " + id[expr_id].name);
                    return false;
                }

                token[arr_token_start] = token_replace;

                //cout << "the end of array" << endl;

            }
            else if( (id[expr_id].type == ID_TYPE_FN_NUM || id[expr_id].type == ID_TYPE_FN_STR || id[expr_id].type == ID_TYPE_FN_USER || id[expr_id].type == ID_TYPE_SUB) && pp_flags == PP_FLAG_ARRAY)
            {
                //cout << "FUNCTION: " << id[expr_id].name << endl;

                //output_tokens();
                //cout << "found function: " << id[expr_id].name << " " << current_block_state << endl << endl;
                //cout << "fn ids = " << id[expr_id].fn_var.size() << endl;

                //push all current function ids onto stack before setting them with the expression function values
//                if(isInFunctionScope)
//                {
//                    for(int n = 0; n < id[expr_id].fn_var.size(); n++)
//                    {
//                        cout << "fid[" << n << "] = " << id[expr_id].fn_var[n].vec_str << endl;
//                        if(id[expr_id].fn_var[n].type == ID_TYPE_NUM || id[expr_id].fn_var[n].type == ID_TYPE_BYREF_NUM || id[expr_id].fn_var[n].type == ID_TYPE_ARR_NUM)
//                        {
//                            vm_asm.push_back("push " + id[expr_id].fn_var[n].vec_str);
//                        }
//                        else
//                        {
//                            vm_asm.push_back("push$ " + id[expr_id].fn_var[n].vec_str);
//                        }
//                    }
//
//                }
                //cout << "debug 1" << endl;

                int s_scope = 0;
                int arr_token_start = i;
                int arr_token_end = i;
                string args[1024];
                args[0] = "";
                int num_args = 0;
                int arg_size = 0; //this variable counts the number of tokens in a argument; used to fix multiple tokens in 1 argument (ie. abs(5 7) should not compile)
                if( (i+1) <= end_token)
                {
                    //cout << "DBG #1: " << id[expr_id].name << endl;
                    if(token[i+1].compare("!<par>")==0)
                    {
                        //cout << "DBG #2" <<endl;
                        s_scope = 1;
                        for(i += 2; (i <= end_token) && (s_scope != 0); i++)
                        {
                            //cout << "DBG Token[" << i << "] = " << token[i] << endl;
                            //cout << "loop " << i << endl;
                            if(token[i].compare("!</par>")==0)
                            {
                                //cout << "DBG #4: " << s_scope << endl;
                                s_scope--;
                                if(s_scope == 0)
                                {
                                    //num_args++;
                                    if(num_args > 0 || args[0].compare("") != 0)
                                        num_args++;
                                    arr_token_end = i;
                                }
                            }
                            else if(token[i].compare("!<par>")==0)
                                s_scope++;
                            else if(token[i].compare("!<comma>")==0)
                            {
                                num_args++;
                                arg_size = 0;
                            }
                            else if(token[i].substr(0,1).compare("n")==0 || token[i].substr(0,1).compare("s")==0 || token[i].substr(0,1).compare("u")==0 || token[i].substr(0,4).compare("<id>")==0)
                            {
                                //cout << id[expr_id].name << "->DBG #3:" << num_args << "  " << token[i] << endl;
                                args[num_args] = token[i];

                                arg_size++;
                                if(arg_size > 1)
                                {
                                    rc_setError("Expected Operator in expression");
                                    return false;
                                }
                            }
                            else if(token[i].compare("")!=0)
                            {
                                rc_setError("Invalid argument in function: "+token[i]);
                                return false;
                            }
                        }
                    }
                }
                //cout << endl << "ID_ARRAY: " << id[expr_id].name << endl;
                //cout << "NUM_ARGS_EXPECTED: " << id[expr_id].num_args << endl;
                //cout << "NUM_ARGS_FOUND: " << num_args << endl;

                if(id[expr_id].num_args != num_args)
                {
                    rc_setError("In " + id[expr_id].name + " Expected " + rc_intToString(id[expr_id].num_args) + " arguments and found " + rc_intToString(num_args));
                    //rc_setError("arg[0]=" + args[0]);
                    //cout <<"TOEK" << endl;
                    output_tokens();
                    return false;
                }

                int resolve_index = -1;
                int resolve_index2 = -1;
                int resolve_id = -1;
                int resolve_id2 = -1;
                int arg_index = -1;



                bool local_state_is_pushed = false; //this variable checks will be set to true if the following function call is recursive
                if(block_state.size() > 0)
                {
                    if(current_scope.substr(0, ("main."+id[expr_id].name).length()).compare("main."+id[expr_id].name)==0)
                    {
                        local_state_is_pushed = true;
                        //cout << "DEBUG: local_state_is_pushed=" << (local_state_is_pushed ? "TRUE":"FALSE") << endl;
                        //push all variables that were made in current function
                        string tmp_type_scope = "_";
                        for(uint32_t fn_var_id = current_fn_index+1; fn_var_id < id.size(); fn_var_id++)
                        {
                            switch(id[fn_var_id].type)
                            {
                                case ID_TYPE_NUM:
                                    vm_asm.push_back("push !" + rc_intToString(id[fn_var_id].vec_pos));
                                    n_tmp.push_back("!" + rc_intToString(id[fn_var_id].vec_pos) );
                                    //cout << "push -- " << id[fn_var_id].name << endl;
                                    break;
                                case ID_TYPE_STR:
                                    vm_asm.push_back("push$ !" + rc_intToString(id[fn_var_id].vec_pos));
                                    s_tmp.push_back("!" + rc_intToString(id[fn_var_id].vec_pos) );
                                    break;
                                //TODO: NEED TO ADD CASE TO PUSH USER TYPES HERE
                                case ID_TYPE_USER:
                                    if(id[fn_var_id].scope.substr(0, tmp_type_scope.length()).compare(tmp_type_scope)==0)
                                        break;

                                    tmp_type_scope = id[fn_var_id].scope + "." + id[fn_var_id].name;
                                    //cout << "TYPE Push: " << id[fn_var_id].name << " : SCOPE=" << tmp_type_scope << endl;

                                    vm_asm.push_back("push_t !" + rc_intToString(id[fn_var_id].vec_pos));
                                    u_tmp.push_back("!" + rc_intToString(id[fn_var_id].vec_pos) );
                                    break;
                            }
                        }
                    }
                }


                for(int n = 0; n < id[expr_id].num_args; n++)
                {
                    //cout << "args: " << args[n] << endl;
                    if(args[n].substr(0,1).compare("n")!=0 && args[n].substr(0,1).compare("s")!=0 && args[n].substr(0,1).compare("u")!=0 && args[n].substr(0,4).compare("<id>")!=0)
                    {
                        rc_setError("--Invalid number of args in function: " + args[n]);
                        return false;
                    }

                    if(id[expr_id].fn_arg_type[n] == ID_TYPE_BYREF_NUM || id[expr_id].fn_arg_type[n] == ID_TYPE_BYREF_STR)
                    {
                        resolve_index = getResolveReg(args[n]);
                        if(args[n].substr(0,4).compare("<id>")==0)
                        {
                            //cout << "found id: " << args[n] << " in " << id[expr_id].name << endl;
                            string t_replace = "";
                            int arg_id = getIDInScope_ByIndex(args[n].substr(4));
                            if(arg_id < 0)
                            {
                                rc_setError("Identifier was not declared in ByRef argument");
                                return false;
                            }
                            if(id[arg_id].type == ID_TYPE_ARR_NUM)
                            {
                                t_replace = "n" + rc_intToString( getArrayObjStart(arg_id));
                                //t_replace = "n" + rc_intToString(n_reg);
                                //inc_n(1);
                                //vm_asm.push_back("mov " + t_replace + " !" + rc_intToString(id[arg_id].vec_pos));

                                resolveID_id_reg.push_back(t_replace);
                                resolveID_id_type.push_back(id[arg_id].type);
                                resolveID_id_ut_index.push_back(id[arg_id].type_index);
                                resolveID_id_vec_pos.push_back(arg_id);
                                resolve_index = resolveID_id_reg.size()-1;
                            }
                            else if(id[arg_id].type == ID_TYPE_ARR_STR)
                            {
                                t_replace = "s" + rc_intToString( getArrayObjStart(arg_id));
                                //t_replace = "s" + rc_intToString(s_reg);
                                //inc_s(1);
                                //vm_asm.push_back("mov$ " + t_replace + " !" + rc_intToString(id[arg_id].vec_pos));

                                resolveID_id_reg.push_back(t_replace);
                                resolveID_id_type.push_back(id[arg_id].type);
                                resolveID_id_ut_index.push_back(id[arg_id].type_index);
                                resolveID_id_vec_pos.push_back(arg_id);
                                resolve_index = resolveID_id_reg.size()-1;
                            }
                            else
                            {
                                rc_setError("Could not resolve Identifier in ByRef argument");
                                return false;
                            }
                        }
                        else if( (args[n].substr(0,1).compare("n")==0 || args[n].substr(0,1).compare("s")==0) && resolve_index >= 0 )
                        {
                            //string t_replace = args[n];
                        }

                        //check if byref_type_exception
                        bool type_exception_found = false;
                        int type_exception_index = -1;
                        //cout << "CHECK EXCEPTION: " << args[n] << endl;
                        for(int bt_i = 0; bt_i < byref_type_exception.size(); bt_i++)
                        {
                            if(args[n].compare(byref_type_exception[bt_i].tk_reg)==0)
                            {
                                //cout << "FOUND EXCEPTION: " << args[n] << endl;
                                byref_type_exception[bt_i].tk_reg = "";
                                type_exception_found = true;
                                type_exception_index = bt_i;
                            }
                            //else
                                //cout << "NO MATCH (" << args[n] << ", " << byref_type_exception[bt_i].tk_reg << ")" << endl;
                        }
                        //----------------

                        if(resolve_index < 0 && (!type_exception_found))
                        {
                            rc_setError("[4]Expected identifier for ByRef argument");
                            return false;
                        }

                        /*arg_index = getIDInScope_ByIndex(resolveID_id_reg[resolve_index]);

                        if(arg_index < 0)
                        {
                            rc_setError("Identifier " + resolveID_id_reg[resolve_index] + " was not defined in this scope");
                            return false;
                        }*/

                        //Array Functions
                        string tmp_fn_name = StringToLower(id[expr_id].name);
                        if(tmp_fn_name.compare("arraydim")==0)
                        {
                            //cout << "found array dim" << endl;
                            int tmp_id_type = -1;

                            if(args[n].substr(0,4).compare("<id>")==0)
                            {
                                int tmp_id = getIDInScope_ByIndex(args[n].substr(4));

                                if(tmp_id >= 0)
                                    tmp_id_type = id[tmp_id].type;
                            }


                            if(args[n].substr(0,1).compare("n")==0 || tmp_id_type == ID_TYPE_NUM || tmp_id_type == ID_TYPE_ARR_NUM || tmp_id_type == ID_TYPE_BYREF_NUM)
                                expr_id = getIDInScope_ByIndex("numberarraydim");
                            else if(args[n].substr(0,1).compare("s")==0 || tmp_id_type == ID_TYPE_STR || tmp_id_type == ID_TYPE_ARR_STR || tmp_id_type == ID_TYPE_BYREF_STR)
                                expr_id = getIDInScope_ByIndex("stringarraydim");
                            else if(args[n].substr(0,1).compare("u")==0 || tmp_id_type == ID_TYPE_USER || tmp_id_type == ID_TYPE_BYREF_USER)
                                expr_id = getIDInScope_ByIndex("typearraydim");
                            else
                            {
                                rc_setError("Expected valid array identifier: " + args[n]);
                                expr_id = -1;
                            }

                            if(expr_id < 0)
                            {
                                rc_setError("ArrayDim macro function does not exists for variable type");
                                return false;
                            }
                        }
                        else if(tmp_fn_name.compare("arraysize")==0)
                        {
                            //cout << "found array size: " << args[0] << endl;
                            int tmp_id_type = -1;

                            if(args[0].substr(0,4).compare("<id>")==0) // arg[0] is what determines the macro function used
                            {
                                int tmp_id = getIDInScope_ByIndex(args[n].substr(4));

                                if(tmp_id >= 0)
                                    tmp_id_type = id[tmp_id].type;
                            }


                            if(args[0].substr(0,1).compare("n")==0 || tmp_id_type == ID_TYPE_NUM || tmp_id_type == ID_TYPE_ARR_NUM || tmp_id_type == ID_TYPE_BYREF_NUM)
                                expr_id = getIDInScope_ByIndex("numberarraysize");
                            else if(args[0].substr(0,1).compare("s")==0 || tmp_id_type == ID_TYPE_STR || tmp_id_type == ID_TYPE_ARR_STR || tmp_id_type == ID_TYPE_BYREF_STR)
                                expr_id = getIDInScope_ByIndex("stringarraysize");
                            else if(args[0].substr(0,1).compare("u")==0 || tmp_id_type == ID_TYPE_USER || tmp_id_type == ID_TYPE_BYREF_USER)
                                expr_id = getIDInScope_ByIndex("typearraysize");
                            else
                            {
                                rc_setError("Expected valid array identifier: " + args[0]);
                                expr_id = -1;
                            }

                            if(expr_id < 0)
                            {
                                rc_setError("ArraySize macro function does not exists for variable type");
                                return false;
                            }
                        }
                        else if(tmp_fn_name.compare("arraycopy")==0)
                        {
                            //cout << "found array copy: " << args[0] << endl;
                            int tmp_id_type = -1;

                            if(args[0].substr(0,4).compare("<id>")==0) // arg[0] is what determines the macro function used
                            {
                                int tmp_id = getIDInScope_ByIndex(args[n].substr(4));

                                if(tmp_id >= 0)
                                    tmp_id_type = id[tmp_id].type;
                            }


                            if(args[0].substr(0,1).compare("n")==0 || tmp_id_type == ID_TYPE_NUM || tmp_id_type == ID_TYPE_ARR_NUM || tmp_id_type == ID_TYPE_BYREF_NUM)
                                expr_id = getIDInScope_ByIndex("numberarraycopy");
                            else if(args[0].substr(0,1).compare("s")==0 || tmp_id_type == ID_TYPE_STR || tmp_id_type == ID_TYPE_ARR_STR || tmp_id_type == ID_TYPE_BYREF_STR)
                                expr_id = getIDInScope_ByIndex("stringarraycopy");
                            else if(args[0].substr(0,1).compare("u")==0 || tmp_id_type == ID_TYPE_USER || tmp_id_type == ID_TYPE_BYREF_USER)
                                expr_id = getIDInScope_ByIndex("typearraycopy");
                            else
                            {
                                rc_setError("Expected valid array identifier: " + args[0]);
                                expr_id = -1;
                            }

                            if(expr_id < 0)
                            {
                                rc_setError("ArrayCopy macro function does not exists for variable type");
                                return false;
                            }
                        }
                        else if(tmp_fn_name.compare("arrayfill")==0)
                        {
                            //cout << "found array fill: " << args[0] << endl;
                            int tmp_id_type = -1;

                            if(args[0].substr(0,4).compare("<id>")==0) // arg[0] is what determines the macro function used
                            {
                                int tmp_id = getIDInScope_ByIndex(args[n].substr(4));

                                if(tmp_id >= 0)
                                    tmp_id_type = id[tmp_id].type;
                            }


                            if(args[0].substr(0,1).compare("n")==0 || tmp_id_type == ID_TYPE_NUM || tmp_id_type == ID_TYPE_ARR_NUM || tmp_id_type == ID_TYPE_BYREF_NUM)
                                expr_id = getIDInScope_ByIndex("numberarrayfill");
                            else if(args[0].substr(0,1).compare("s")==0 || tmp_id_type == ID_TYPE_STR || tmp_id_type == ID_TYPE_ARR_STR || tmp_id_type == ID_TYPE_BYREF_STR)
                                expr_id = getIDInScope_ByIndex("stringarrayfill");
                            else if(args[0].substr(0,1).compare("u")==0 || tmp_id_type == ID_TYPE_USER || tmp_id_type == ID_TYPE_BYREF_USER)
                                expr_id = getIDInScope_ByIndex("typearrayfill");
                            else
                            {
                                rc_setError("Expected valid array identifier: " + args[0]);
                                expr_id = -1;
                            }

                            //cout << "dbg data: " << expr_id << "  arg = " << args[0] << "  type = " << tmp_id_type << "  name = " << id[expr_id].name << endl;

                            if(expr_id < 0)
                            {
                                rc_setError("ArrayFill macro function does not exists for variable type");
                                return false;
                            }
                        }
                        //--------------------------------

                        if(type_exception_found)
                        switch(id[expr_id].fn_arg_type[n])
                        {
                            case ID_TYPE_BYREF_NUM:
                                if(args[n].substr(0,1).compare("n")!=0)
                                {
                                    rc_setError("Expected number identifier for argument in " + id[expr_id].name);
                                    return false;
                                }
                                byref_type_exception[type_exception_index].exception_used = true;
                                vm_asm.push_back("ptr !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + args[n]);
                                break;
                            case ID_TYPE_BYREF_STR:
                                if(args[n].substr(0,1).compare("s")!=0)
                                {
                                    rc_setError("Expected string identifier for argument");
                                    return false;
                                }
                                byref_type_exception[type_exception_index].exception_used = true;
                                vm_asm.push_back("ptr$ !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + args[n]);
                                break;
                            case ID_TYPE_BYREF_USER:
                                //cout << "start up" << endl;
                                if(args[n].substr(0,1).compare("u")!=0)
                                {
                                    rc_setError("Expected defined type identifier for argument: " + rc_intToString(id[expr_id].fn_arg_utype[n]));
                                    return false;
                                }
                                //cout << "yolo: " << expr_id << " ~ " << id.size() << "  --  " << id[expr_id].num_args << endl;
                                byref_type_exception[type_exception_index].exception_used = true;
                                vm_asm.push_back("uref_ptr !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + args[n]);
                                //cout << "testing" << endl;
                                break;
                        }
                        else
                        switch(id[expr_id].fn_arg_type[n])
                        {
                            case ID_TYPE_BYREF_NUM:
                                if(resolveID_id_type[resolve_index] != ID_TYPE_NUM && resolveID_id_type[resolve_index] != ID_TYPE_ARR_NUM && resolveID_id_type[resolve_index] != ID_TYPE_BYREF_NUM && resolveID_id_type[resolve_index] != ID_TYPE_USER_NUM && resolveID_id_type[resolve_index] != ID_TYPE_USER_NUM_ARRAY)
                                {
                                    rc_setError("Expected number identifier for argument");
                                    return false;
                                }
                                vm_asm.push_back("ptr !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + resolveID_id_reg[resolve_index]);
                                break;
                            case ID_TYPE_BYREF_STR:
                                if(resolveID_id_type[resolve_index] != ID_TYPE_STR && resolveID_id_type[resolve_index] != ID_TYPE_ARR_STR && resolveID_id_type[resolve_index] != ID_TYPE_BYREF_STR && resolveID_id_type[resolve_index] != ID_TYPE_USER_STR && resolveID_id_type[resolve_index] != ID_TYPE_USER_STR_ARRAY)
                                {
                                    rc_setError("Expected string identifier for argument");
                                    return false;
                                }
                                vm_asm.push_back("ptr$ !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + resolveID_id_reg[resolve_index]);
                                break;
                            case ID_TYPE_BYREF_USER:
                                if(resolveID_id_type[resolve_index] != ID_TYPE_USER && resolveID_id_type[resolve_index] != ID_TYPE_BYREF_USER)
                                {
                                    rc_setError("Expected defined type identifier for argument: " + rc_intToString(id[expr_id].fn_arg_utype[n]));
                                    return false;
                                }
                                vm_asm.push_back("uref_ptr !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + resolveID_id_reg[resolve_index]);
                                break;
                        }
                    }
                    else if(id[expr_id].fn_arg_type[n] == ID_TYPE_BYREF_USER)
                    {
                        //cout << "BYREF USER TYPE CHECK" << endl;

                        //check if byref_type_exception
                        bool type_exception_found = false;
                        //cout << "CHECK EXCEPTION: " << args[n] << endl;
                        for(int bt_i = 0; bt_i < byref_type_exception.size(); bt_i++)
                        {
                            if(args[n].compare(byref_type_exception[bt_i].tk_reg)==0)
                            {
                                //cout << "FOUND EXCEPTION: " << args[n] << endl;
                                byref_type_exception[bt_i].tk_reg = "";
                                type_exception_found = true;
                            }
                            //else
                                //cout << "NO MATCH (" << args[n] << ", " << byref_type_exception[bt_i].tk_reg << ")" << endl;
                        }
                        //----------------

                        int ut_info = -1;
                        int ut_index = -1;
                        getRegInfo(args[n], ut_info, ut_index);

                        if(n==1 && StringToLower(id[expr_id].name).compare("typearraycopy")==0)
						{
							int uti_1 = -1;
							int utx_1 = -1;
							getRegInfo(args[0], uti_1, utx_1);

							if(byref_type_exception.size()>=2)
							{
								byref_type_exception[0].exception_used = true;
								byref_type_exception[1].exception_used = true;
							}

							if(utx_1 < 0 || (uti_1 != ID_TYPE_USER && uti_1 != ID_TYPE_BYREF_USER) || (ut_info != ID_TYPE_USER && ut_info != ID_TYPE_BYREF_USER) )
							{
								rc_setError("Invalid identifier for ByRef argument");
								return false;
							}

							//cout << id[expr_id].name << " ARGS = " << ut_index << ", " << utx_1 << endl;
							if(ut_index != utx_1)
							{
								rc_setError("Expected \"" + utype[utx_1].name + "\" identifier for ByRef argument");
								return false;
							}
						}

                        if(ut_index != id[expr_id].fn_arg_utype[n] && (!byref_type_generic(utype[id[expr_id].fn_arg_utype[n]].name)))
                        {
                            rc_setError("Expected \"" + utype[id[expr_id].fn_arg_utype[n]].name + "\" identifier for ByRef argument");
                            return false;
                        }
                        //cout << "BYREF USER MATCH ID: " << id[expr_id].fn_arg[n] << " ==> " << args[n] << endl;
                        vm_asm.push_back("uref_ptr !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + args[n]);
                    }
                    else if(id[expr_id].fn_arg_type[n] == ID_TYPE_NUM)
                    {
                        if(args[n].substr(0,1).compare("n")!=0)
                        {
                            rc_setError("Expected number expression for argument");
                            return false;
                        }
                        //vm_asm.push_back("mov " + id[expr_id].fn_arg[n] + "->" + id[expr_id].fn_reg[n] + " " + args[n]);
                        vm_asm.push_back("mov !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + args[n]);
                    }
                    else if(id[expr_id].fn_arg_type[n] == ID_TYPE_STR)
                    {
                        if(args[n].substr(0,1).compare("s")!=0)
                        {
                            rc_setError("Expected string expression for argument");
                            return false;
                        }
                        //vm_asm.push_back("mov " + id[expr_id].fn_arg[n] + "->" + id[expr_id].fn_reg[n] + " " + args[n]);
                        vm_asm.push_back("mov$ !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + args[n]);
                    }
                    else if(id[expr_id].fn_arg_type[n] == ID_TYPE_USER)
                    {
                        //TODO: NEED TO CHECK UTYPE FOR ARG
                        if(args[n].substr(0,1).compare("u")!=0)
                        {
                            rc_setError("Expected expression of type \"" + utype[id[expr_id].fn_arg_utype[n]].name + "\" for argument");
                            return false;
                        }

                        int ut_info = -1;
                        int ut_index = -1;
                        getRegInfo(args[n], ut_info, ut_index);
                        if(ut_index != id[expr_id].fn_arg_utype[n] && (!byref_type_generic(utype[id[expr_id].fn_arg_utype[n]].name)))
                        {
                            rc_setError("Expected \"" + utype[id[expr_id].fn_arg_utype[n]].name + "\" identifier for argument");
                            return false;
                        }

                        //vm_asm.push_back("mov " + id[expr_id].fn_arg[n] + "->" + id[expr_id].fn_reg[n] + " " + args[n]);

                        vm_asm.push_back("mov_type !" + rc_intToString(id[expr_id].fn_arg_vec[n]) + " " + args[n]);
                    }
                }

                //check if any exceptions weren't used and return error if there are any left
                for(int bt_i = 0; bt_i < byref_type_exception.size(); bt_i++)
                {
                    if(byref_type_exception[bt_i].tk_reg.compare("")!=0)
                    {
                        rc_setError(byref_type_exception[bt_i].error_log);
                        return false;
                    }
                }
                //-----------------------------------------------------------------------------

                string token_replace = "";

                if(id[expr_id].isBuiltin)
                    vm_asm.push_back("func !" + rc_intToString(id[expr_id].vmFunctionIndex));
                else
                {
                    for(int n = 0; n < n_reg; n++)
                    {
                        vm_asm.push_back("push n" + rc_intToString(n));
                        n_tmp.push_back("n"+rc_intToString(n));
                    }
                    for(int n = 0; n < s_reg; n++)
                    {
                        vm_asm.push_back("push$ s" + rc_intToString(n));
                        s_tmp.push_back("s" + rc_intToString(n));
                    }
                    for(int n = 0; n < u_reg; n++)
                    {
                        vm_asm.push_back("push_t u" + rc_intToString(n));
                        u_tmp.push_back("u" + rc_intToString(n));
                    }

                    vm_asm.push_back("gosub @" + id[expr_id].name);
                }

                int ptr_count = 0;
                for(int n = 0; n < id[expr_id].fn_arg.size(); n++)
                {
                    if(id[expr_id].fn_arg_type[n] == ID_TYPE_BYREF_NUM || id[expr_id].fn_arg_type[n] == ID_TYPE_BYREF_STR || id[expr_id].fn_arg_type[n] == ID_TYPE_BYREF_USER)
                        ptr_count++;
                }

                if(ptr_count > 0)
                {
                    vm_asm.push_back("pop_ptr !" + rc_intToString(ptr_count));
                }

                if(id[expr_id].type == ID_TYPE_FN_NUM)
                {
                    token_replace = "n" + rc_intToString(n_reg);
                    vm_asm.push_back("pop " + token_replace);
                    inc_n(1);
                }
                else if(id[expr_id].type == ID_TYPE_FN_STR)
                {
                    token_replace = "s" + rc_intToString(s_reg);
                    vm_asm.push_back("pop$ " + token_replace);
                    inc_s(1);
                }
                else if(id[expr_id].type == ID_TYPE_FN_USER)
                {
                    token_replace = "u" + rc_intToString(u_reg);
                    //vm_asm.push_back("dim_type " + token_replace + " " + rc_intToString(id[expr_id].type_index)); NOTE: I decided to have pop_t free the memory for the variable before setting it
                    vm_asm.push_back("pop_t " + token_replace);
                    resolveID_id_reg.push_back(token_replace);
                    resolveID_id_type.push_back(ID_TYPE_USER);
                    resolveID_id_ut_index.push_back(id[expr_id].type_index);
                    resolveID_id_vec_pos.push_back(expr_id);
                    inc_u(1);
                }
                else if(id[expr_id].type == ID_TYPE_SUB)
                {
                    token_replace = "?";
                }

                //cout << "start_dbg USER DT" << endl;

                if(!id[expr_id].isBuiltin)
                {
                    for(int n = n_tmp.size()-1; n >= 0; n--)
                    {
                        vm_asm.push_back("pop " + n_tmp[n]);
                    }
                    for(int n = s_tmp.size()-1; n >= 0; n--)
                    {
                        vm_asm.push_back("pop$ " + s_tmp[n]);
                    }
                    for(int n = u_tmp.size()-1; n >= 0; n--)
                    {
                        vm_asm.push_back("pop_t " + u_tmp[n]);
                    }
                    n_tmp.clear();
                    s_tmp.clear();
                    u_tmp.clear();
                }

                //cout << "end dbg" << endl;

//                if(isInFunctionScope)
//                {
//                    for(int n = id[expr_id].fn_var.size()-1; n >= 0;  n--)
//                    {
//                        if(id[expr_id].fn_var[n].type == ID_TYPE_NUM || id[expr_id].fn_var[n].type == ID_TYPE_BYREF_NUM || id[expr_id].fn_var[n].type == ID_TYPE_ARR_NUM)
//                        {
//                            vm_asm.push_back("pop " + id[expr_id].fn_var[n].vec_str);
//                        }
//                        else
//                        {
//                            vm_asm.push_back("pop$ " + id[expr_id].fn_var[n].vec_str);
//                        }
//                    }
//                }

                for(int p = arr_token_start; p <= arr_token_end; p++)
                    token[p] = "";

                if(token_replace.compare("")==0)
                {
                    rc_setError("Could not resolve function " + id[expr_id].name);
                    return false;
                }

                token[arr_token_start] = token_replace;

                //cout << "the end of function: " << i << ", " << end_token << " ---> " << token[i] << endl;

                //if token is <child> then I am going to subtract 1 from i so that  when it goes back through the loop and increments i, it will be child
                i--;

            }
        }
        else if(token[i].compare("<child>")==0)
        {
            //cout << "USER DEFINED TYPE REGISTER ARGUMENT" << endl;

            n = "n" + rc_intToString(n_reg);
            s = "s" + rc_intToString(s_reg);
            u = "u" + rc_intToString(u_reg);

            string expr_ureg = "";
            bool should_eval = false;
            string expr_member = "";
            if(i < end_token)
                expr_member = token[i+1];

            if(expr_member.find_first_of(">") != string::npos)
                expr_member = expr_member.substr(expr_member.find_first_of(">")+1);

            for(int t = i-1; t >= 0; t--)
            {
                if(token[t].compare("")!=0)
                {
                    if(token[t].substr(0,1).compare("u")==0)
                    {
                        expr_ureg = token[t];
                        should_eval = true;
                        token[t] = "";
                    }
                    //cout << "break token = " << token[t] << " :: " << should_eval << endl;
                    break;
                }
            }

            if(!should_eval)
            {
                continue;
            }
            else
            {
                //cout << "EVAL SUPER UDT" << endl;
                //continue;
            }

            //user type expression from another user type expression (ie. something already stored in u register)
            //cout << "-Parsing User Variable: " << id[expr_id].name << endl;
              //  cout << "----------------------------------------------- : " << eval_udt << endl;

                bool udt_id_init = false;


                vm_asm.push_back("obj_usr_init " + expr_ureg);
                token[i] = "";
                int ureg_index = getResolveReg(expr_ureg);
                int ureg_id = resolveID_id_vec_pos[ureg_index];
                string tmp_scope = id[ureg_id].scope + "." + id[ureg_id].name;

                /*
                cout << "Resolve = " << ureg_id << ": " << tmp_scope << endl;

                for(int t = i; t < token.size(); t++)
                {
                    try
                    {
                        cout << t << ":" << token.at(t) << endl;
                    }
                    catch(out_of_range& e)
                    {
                        cout << "Token Out of Range Error: " << e.what() << endl;
                    }
                }
                */

                int tmp_id = 0;
                bool has_child = false;


                for(int t = i+1; t <= end_token; t++)
                {

                    if(token[t].substr(0,4).compare("<id>")==0)
                    {
                        //cout << "FIGURE IT OUT: " << t << token[t] << endl;
                        string args[3];
                        int arg_count = 0;
                        string full_id = token[t].substr(4);
                        token[t] = "";
                        tmp_id = getIDInScope_ByIndex_TypeMatch(full_id, tmp_scope);
                        //cout << "\ntmp_id = " << tmp_id << endl;

                        if(tmp_id < 0)
                        {
                            rc_setError(tmp_scope.substr(5) + " does not have member \"" + full_id + "\"");
                            return false;
                        }

                        //cout << "Scope = " << id[tmp_id].scope << "  ID = " << full_id << "  --  " << tmp_id << endl << endl;

                        tmp_scope += "." + full_id;


                        //get arguments (ie. the dimensions of an array
                        int t2 = t+1;

                        if(t2 < end_token)
                        {
                            int arr_scope = 0;
                            if(token[t2].compare("!<square>")==0)
                            {
                                token[t2] = "";
                                args[0] = "";
                                args[1] = "";
                                args[2] = "";
                                arg_count = 0;
                                arr_scope = 1;
                                t2++;
                                //cout << "T2 = " << t2 << endl << endl;

                                for(; t2 <= end_token; t2++)
                                {
                                    //cout << "DBG ARR: " << t2 << ", " << end_token << " : " << token[t2] << endl;
                                    if(token[t2].compare("!</square>")==0)
                                        arr_scope--;
                                    else if(token[t2].compare("!<square>")==0)
                                        arr_scope++;
                                    else if(token[t2].compare("!<comma>")==0)
                                        arg_count++;
                                    else if(token[t2].substr(0,1).compare("n")==0)
                                    {
                                        if(args[arg_count].compare("")==0)
                                            args[arg_count] = token[t2];
                                        else
                                        {
                                            rc_setError("Error parsing array dimension: " + args[arg_count] + " :: " + token[t2] + " -- " + rc_intToString(t2) + ", " + rc_intToString(arg_count));
                                            return false;
                                        }
                                    }

                                    token[t2] = "";

                                    if(arg_count >= 3)
                                    {
                                        rc_setError("Too many dimensions in array");
                                        return false;
                                    }

                                    if(arr_scope == 0)
                                        break;

                                }

                                if(arr_scope > 0)
                                {
                                    rc_setError("Expected ]] in expression: " + rc_intToString(arr_scope));
                                    return false;
                                }

                                arg_count++;
                            }

                        }


                        has_child = false;
                        if((t2+1) < token.size())
                        {
                            if(token[t2+1].compare("<child>")==0)
                            {
                                has_child = true;
                            }
                        }


                        if(arg_count != id[tmp_id].num_args)
                        {
                            if(!type_delete_flag)
                            {
                                rc_setError("[0]Expected " + rc_intToString(id[tmp_id].num_args) + " dimension in " + id[tmp_id].name);
                                return false;
                            }
                            else
                            {
                                if(has_child)
                                {
                                    rc_setError("[1]Expected " + rc_intToString(id[tmp_id].num_args) + " dimension in " + id[tmp_id].name);
                                    return false;
                                }

                                arg_count = id[tmp_id].num_args;
                                //vm_asm.push_back("mov n" + rc_intToString(n_reg) + " 0");
                                //args[0] = "n" + rc_intToString(n_reg);
                                //args[1] = args[0];
                                //args[2] = args[0];
                                //inc_n(1);
                            }
                        }

                        if(type_delete_flag && (!has_child))
                        {
                            //DO NOTHING
                            //cout << "NO CHILD: " << id[tmp_id].name << endl;
                        }
                        else
                        {
                            //if(type_delete_flag)
                              //  cout << "TESTING STUFF" << endl;

                            switch(arg_count)
                            {
                                case 0:
                                    if(id[tmp_id].type == ID_TYPE_USER || id[tmp_id].type == ID_TYPE_BYREF_USER)
                                    {
                                        if(udt_id_init)
                                            vm_asm.push_back("obj_usr_init !" + rc_intToString(id[tmp_id].vec_pos));
                                        else
                                            vm_asm.push_back("obj_usr !" + rc_intToString(id[tmp_id].vec_pos));
                                    }
                                    else if(id[tmp_id].type == ID_TYPE_USER_NUM)
                                        vm_asm.push_back("obj_usr_n !" + rc_intToString(id[tmp_id].vec_pos));
                                    else if(id[tmp_id].type == ID_TYPE_USER_STR)
                                        vm_asm.push_back("obj_usr_s !" + rc_intToString(id[tmp_id].vec_pos));
                                    else
                                    {
                                        rc_setError("Invalid type in User Defined Type");
                                        return false;
                                    }
                                    break;
                                case 1:
                                    if(id[tmp_id].type == ID_TYPE_USER || id[tmp_id].type == ID_TYPE_BYREF_USER)
                                    {
                                        if(udt_id_init)
                                            vm_asm.push_back("obj_usr_init1 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0]);
                                        else
                                            vm_asm.push_back("obj_usr1 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0]);
                                    }
                                    else if(id[tmp_id].type == ID_TYPE_USER_NUM)
                                        vm_asm.push_back("obj_usr_n1 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0]);
                                    else if(id[tmp_id].type == ID_TYPE_USER_STR)
                                        vm_asm.push_back("obj_usr_s1 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0]);
                                    else
                                    {
                                        rc_setError("Invalid type in User Defined Type");
                                        return false;
                                    }
                                    break;
                                case 2:
                                    if(id[tmp_id].type == ID_TYPE_USER || id[tmp_id].type == ID_TYPE_BYREF_USER)
                                    {
                                        if(udt_id_init)
                                            vm_asm.push_back("obj_usr_init2 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1]);
                                        else
                                            vm_asm.push_back("obj_usr2 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1]);
                                    }
                                    else if(id[tmp_id].type == ID_TYPE_USER_NUM)
                                        vm_asm.push_back("obj_usr_n2 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1]);
                                    else if(id[tmp_id].type == ID_TYPE_USER_STR)
                                        vm_asm.push_back("obj_usr_s2 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1]);
                                    else
                                    {
                                        rc_setError("Invalid type in User Defined Type");
                                        return false;
                                    }
                                    break;
                                case 3:
                                    if(id[tmp_id].type == ID_TYPE_USER || id[tmp_id].type == ID_TYPE_BYREF_USER)
                                    {
                                        if(udt_id_init)
                                            vm_asm.push_back("obj_usr_init3 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                        else
                                            vm_asm.push_back("obj_usr3 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                    }
                                    else if(id[tmp_id].type == ID_TYPE_USER_NUM)
                                        vm_asm.push_back("obj_usr_n3 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                    else if(id[tmp_id].type == ID_TYPE_USER_STR)
                                        vm_asm.push_back("obj_usr_s3 !" + rc_intToString(id[tmp_id].vec_pos) + " " + args[0] + " " + args[1] + " " + args[2]);
                                    else
                                    {
                                        rc_setError("Invalid type in User Defined Type");
                                        return false;
                                    }
                                    break;
                            }

                            udt_id_init = false;
                        }



                    }
                    else if(token[t].compare("<child>")==0)
                    {
                        token[t] = "";
                        continue;
                    }
                    else if(token[t].compare("")!=0)
                    {
                        break;
                    }

                }


                //START HERE
                if(type_delete_flag && (!has_child))
                {
                    //cout << "DELETE_VAR = " << id[tmp_id].name << endl;
                    type_delete_arg = "!" + rc_intToString(id[tmp_id].vec_pos);
                }
                else
                switch(id[tmp_id].type)
                {
                    case ID_TYPE_USER:
                    case ID_TYPE_BYREF_USER:
                        vm_asm.push_back("obj_usr_get " + u);
                        token[i] = u;
                        resolveID_id_reg.push_back(token[i]);
                        resolveID_id_type.push_back(id[tmp_id].type);
                        resolveID_id_ut_index.push_back(id[tmp_id].type_index);
                        resolveID_id_vec_pos.push_back(tmp_id);
                        inc_u(1);
                        break;
                    case ID_TYPE_USER_NUM:
                        vm_asm.push_back("obj_usr_get " + n);
                        token[i] = n;
                        inc_n(1);
                        break;
                    case ID_TYPE_USER_STR:
                        vm_asm.push_back("obj_usr_get " + s);
                        token[i] = s;
                        inc_s(1);
                        break;
                    default:
                        break;
                }

                /*
                cout << "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl;

                for(int t = 0; t < token.size(); t++)
                {
                    try
                    {
                        cout << t << ":" << token.at(t) << endl;
                    }
                    catch(out_of_range& e)
                    {
                        cout << "Token Out of Range Error: " << e.what() << endl;
                    }
                }

                cout << "-----------------------------------------------" << endl;
                */

                //for(int t = 0; t < id.size(); t++)
                  //  if(id[t].type == ID_TYPE_USER) cout << "ID[" << id[t].name << "]  SCOPE=" << id[t].scope << "  --  " << id[t].vec_pos << endl;
        }
    }
    return true;
}

// I really hate Wal-Mart

struct block_argument
{
    int arg_start = -1;
    int arg_end = -1;
};

vector<block_argument> block_args;
vector<string> block_arg_data;

bool getArgBlockStuff(int start_block, int& arg_count)
{
    block_args.clear();
    int end_block = -1;
    arg_count = 0;
    //string block_type = token[start_block];
    //string block_end_type = "";
    block_argument b_arg;

//    if(block_type.compare("<square>")==0)
//        block_end_type = "</square>";
//    else if(block_type.compare("<par>")==0)
//        block_end_type = "</par>";
//    else if(block_type.compare("<curly>")==0)
//        block_end_type = "</curly>";
//    else
//    {
//        rc_setError("Expected Start of Control Block");
//        return false;
//    }

    if(token.size() > start_block)
    {
        //if its not a bracketed block then there is no need to check for arguments
        if(token[start_block].compare("!<par>")!=0 && token[start_block].compare("!<square>")!=0 && token[start_block].compare("!<curly>")!=0)
        {
            arg_count = 0;
            return true;
        }

        int scope = 1;
        b_arg.arg_start = start_block + 1;
        for(int i = start_block+1; i < token.size(); i++)
        {
            if(token[i].compare("!<par>")==0 || token[i].compare("!<square>")==0 || token[i].compare("!<curly>")==0)
                scope++;
            else if(token[i].compare("!</par>")==0 || token[i].compare("!</square>")==0 || token[i].compare("!</curly>")==0)
                scope--;

            if(scope == 0)
            {
                //getBlock should take care of this check already
                //
                //if(token[i].compare(block_end_type)!=0)
                //{
                //    rc_setError("Block was not ended correctly");
                //    return false;
                //}
                //else
                //    end_block = i;

                arg_count++;
                b_arg.arg_end = i - 1;
                block_args.push_back(b_arg);
                break;
            }
            else if(scope == 1)
            {
                if(token[i].compare("<comma>")==0)
                {
                    token[i] = "!" + token[i];
                    arg_count++;

                    b_arg.arg_end = i-1;
                    block_args.push_back(b_arg);
                    b_arg.arg_start = i + 1;
                }
            }
        }
    }

    return true;
}

bool getBlockArg(int arg_num, int& start_arg, int& end_arg)
{
    if(arg_num < block_args.size())
    {
        start_arg = block_args[arg_num].arg_start;
        end_arg = block_args[arg_num].arg_end;
    }
    else
    {
        start_arg = -1;
        end_arg = -1;
        return false;
    }
    return true;
}

string multi_arg[64];
int multi_arg_count = 0;

bool eval_expression(int start_token = 0, int end_token = 0, bool allow_multi_arg = false)
{
    int start_block = start_token; //will hold the index of the token the current block starts on
    int end_block = end_token; //will hold the index of the token the current block ends on
    int arg_start = 0;
    int arg_end = 0;
    int arg_count = 0;

    multi_arg[0] = "";
    multi_arg[1] = "";
    multi_arg[2] = "";

    expr_result = "";

    int current_block_start = 0;
    int current_block_end = 0;

    if(end_token==0)
        end_token = token.size()-1;

    pre_parse(start_token, end_token);

    //cout << "EXPRESSION" << endl;
    //output_tokens();
    //cout << "------------------------" << endl;

    //cout << "POST PRE_PARSE" << endl;
    //for(int i = start_token; i <= end_token; i++)
    //cout << "Token[" << i << "]= " << token[i] << endl;

    string arg_result = "";

    multi_arg_count = 0;

    do
    {
        getBlock(start_token, end_token, start_block, end_block); //sets the current start_block and end_block

        //cout << "\nstart pp" << endl;
        if(!pre_parse(start_block, end_block, PP_FLAG_ARRAY, true))
        {
            return false;
        }
        //cout << "end pp" << endl;

        getArgBlockStuff(start_block, arg_count);

        //cout << "block arg count --> " << arg_count << endl;

        //cout << "start block = " << start_token << endl << endl; cout << "end block = " << end_token << endl;

        if(end_block < 0) //if end_block is less than 0 then an error occurred so this function will return false
        {
            //cout << "End block < 0" << endl;
            //rc_setError("Could not evaluate expression");
            return false;
        }

        /* ORDER OF OPERATIONS
        1. powers
        2. multiplication, division, modulous
        3. addition, subtraction
        */
        if(arg_count > 1)
        {
            //cout << "arg_count = " << arg_count << endl;
            for(int i = 0; i < arg_count; i++)
            {
                getBlockArg(i, arg_start, arg_end);

                if(!eval_not(start_block, end_block))
                    return false;
                if(!eval_pow(arg_start, arg_end))
                    return false;
                if(!eval_muldiv(arg_start, arg_end))
                    return false;
                if(!eval_addsub(arg_start, arg_end))
                    return false;
                if(!eval_bitshift(arg_start, arg_end))
                    return false;
                if(!eval_cmp(arg_start, arg_end))
                    return false;
                if(!eval_andor(arg_start, arg_end))
                    return false;
                arg_result = "";

                for(int n = arg_start; n <= arg_end; n++)
                {
                    if(token[n].size()>0)
                    {
                        if(token[n].substr(0,1).compare("n")==0 || token[n].substr(0,1).compare("s")==0 || token[n].substr(0,1).compare("u")==0 || token[n].substr(0,4).compare("<id>") == 0)
                        {
                            if(arg_result.compare("")==0)
                                arg_result = token[n];
                            else
                            {
                                rc_setError("Found multiple args not separated by a comma");
                                return false;
                            }
                        }
                    }
                    token[n] = "";
                }
                token[arg_start] = arg_result;
            }
        }
        else
        {
            //cout << "start" << endl;
            if(!eval_not(start_block, end_block))
                return false;
            if(!eval_pow(start_block, end_block))
                return false;
            if(!eval_muldiv(start_block, end_block))
                return false;
            if(!eval_addsub(start_block, end_block))
                return false;
            if(!eval_bitshift(start_block, end_block))
                return false;
            if(!eval_cmp(start_block, end_block))
                return false;
            if(!eval_andor(start_block, end_block))
                return false;
            //cout << "end here" << endl;
        }

        //cout << "start block end = " << start_token << endl;

    }while(!(start_block==start_token && end_block==end_token));

    int result_count = 0;
    //cout << "Get RESULTS" << endl;

    for(int i = start_token; i <= end_token; i++)
    {
        //cout << "TOK[" << i << "] = " << token[i] << endl;
        if(token[i].length()>0)
        {
            if(token[i].substr(0,1).compare("n")==0 || token[i].substr(0,1).compare("s")==0 ||
               token[i].substr(0,1).compare("u")==0 || token[i].substr(0,1).compare("?")==0)
            {
                expr_result = token[i];
                multi_arg[multi_arg_count] = token[i];
                multi_arg_count++;
                result_count++;
            }
            else if(token[i].substr(0,1).compare("!")!=0)
            {
                rc_setError("--Could not evaluate expression: " + token[i]);
                return false;
            }
        }

        if(result_count > 1 && !allow_multi_arg)
        {
            //cout << "ST:ET = " << start_block << ", " << end_block << endl;
            rc_setError("++Could not evaluate expression");
            return false;
        }
    }

    return true;
}

int constant_arg[64];
int constant_arg_count = 0;

bool eval_constantExpression(int start_token, int end_token)
{
    //cout << "constant_start = " << token[start_token] << endl;
    //cout << "constant_end = " << token[end_token] << endl;
    constant_arg_count = 0;
    constant_arg[0] = 0;
    constant_arg[1] = 0;
    constant_arg[2] = 0;
    for(int i = start_token; i <= end_token; i++)
    {
        if(rc_substr(token[i], 0, 5).compare("<num>")==0)
        {
            constant_arg[constant_arg_count] = rc_stringToInt(token[i].substr(5));
            //cout << "array dim[" << constant_arg_count << "] = " << constant_arg[constant_arg_count] << endl;
            if(token.size() > (i+1))
            {
                if(token[i+1].compare("<comma>")!=0 && token[i+1].compare("</square>")!=0)
                {
                    //cout << "Next token is " << token[i+1] << endl;
                    rc_setError("Expected <comma> after number constant");
                    return false;
                }
            }
        }
        else if(rc_substr(token[i],0, 7).compare("<comma>")==0)
        {
            constant_arg_count++;
            if(constant_arg_count >= 3)
            {
                rc_setError("Too many arguments in member definition");
                return false;
            }
        }
        else
        {
            rc_setError("Expected constant in member definition");
            return false;
        }

    }
    constant_arg_count++;
    return true;
}

int findFirstDelimiter(string line)
{
    for(int i = 0; i < line.length(); i++)
    {
        if(line[i] == '.' || line[i] == '[' || line[i] == ']' || line[i] == ' ')
            return i;
    }
    return line.length()-1;
}

bool isDelimiter(char c)
{
    switch(c)
    {
        case '+':
        case '-':
        case '*':
        case '/':
        case '^':
        case ',':
        case '=':
        case '<':
        case '>':
        case ' ':
            return true;
            break;
    }
    return false;
}

void clearRegs()
{
    n_reg = 0;
    s_reg = 0;
    u_reg = 0;
    resolveID_id_reg.clear();
    resolveID_id_type.clear();
    resolveID_id_ut_index.clear();
    resolveID_id_vec_pos.clear();
}

bool check_rule()
{
    if(token.size()>0)
    {
        if(current_block_state == BLOCK_STATE_TYPE)
        {
            if(token[0].compare("<dim>")!=0 && token[0].compare("<end>")!=0)
            {
                rc_setError("Expected DIM in TYPE definition");
                return false;
            }
        }
        else if(current_block_state != BLOCK_STATE_MAIN)
        {
            if(token[0].compare("<type>")==0)
            {
                rc_setError("TYPE cannot be declared in the current scope");
                return false;
            }
            else if(token[0].compare("<function>")==0)
            {
                rc_setError("FUNCTION cannot be declared in the current scope");
                return false;
            }
            else if(token[0].compare("<subp>")==0)
            {
                rc_setError("SUB ROUTINE cannot be declared in the current scope");
                return false;
            }
        }

        if(token[0].compare("<const>")==0)
        {
            if(token.size() < 3)
            {
                rc_setError("Incomplete Constant Expression");
                return false;
            }

            if(token[1].substr(0,4).compare("<id>")!=0)
            {
                rc_setError("Expected Identifier after CONST");
                return false;
            }

            string id_name = token[1].substr(4);

            if(!isValidIDName(id_name))
            {
                rc_setError("Invalid Identifier after CONST");
                return false;
            }

            if(token[2].compare("<equal>")!=0)
            {
                rc_setError("Expected \"=\" in CONST expression");
                return false;
            }

            int c_id = create_constant(StringToUpper(id_name));
            if(c_id < 0)
            {
                rc_setError("CONST identifier already exists");
                return false;
            }

            for(int i = 3; i < token.size(); i++)
                add_const_token(c_id, token[i]);

            return true;
        }
        else if(token[0].compare("<dim>")==0)
        {
            //cout << "DIM RULE FOUND" << endl;  //'DIM' [ID]; '[' #; #; # ']' ; 'AS' [TYPE]; '=' (VALUE)

            string id_name = "";
            int id_type = ID_TYPE_NUM;
            string id_type_name = "";
            int dimensions = 0;

            //check if the next token is a identifier
            if(token.size() > 1)
            {
                if(token[1].substr(0,4).compare("<id>")==0)
                {
                    //if the identifier is not a valid name then return false
                    id_name = token[1].substr(4);
                    id_type = ID_TYPE_NUM;
                    id_type_name = "";
                    dimensions = 0;

                    if(!isValidIDName(id_name))
                    {
                        rc_setError("Invalid Identifier name");
                        return false;
                    }

                    //check if the data type is a string
                    if(id_name.substr(id_name.length()-1).compare("$")==0)
                        id_type = ID_TYPE_STR;

                    //if the identifier already exists and current_block state is not type then return false
                    if(idExistsInScope(id_name))
                    {
                        rc_setError("Identifier already defined in current scope");
                        return false;
                    }

                    //cout << "db1\n";

                    //if there are only two tokens then return here because there is nothing left to check
                    if(token.size()==2)
                    {
                        if(current_block_state == BLOCK_STATE_TYPE)
                        {
                            //cout << "adding type member" << endl;
                            if(!add_type_member(id_name, id_type, "", 0))
                            {
                                //cout << rc_getError() << endl;
                                return false;
                            }
                        }
                        else if(isInFunctionScope)
                        {
                            if(!create_function_variable(id_name, id_type, ""))
                            {
                                //cout << rc_getError() << endl;
                                return false;
                            }
                        }
                        else
                        {
                            if(!create_variable(id_name, id_type))
                            {
                                //cout << rc_getError() << endl;
                                return false;
                            }
                        }

                        //cout << "return true here" << endl;
                        return true;
                    }

                    //cout << "db2\n";

                    //current token
                    int token_index = 2;

                    //check for the next rule; must be [], AS, or =
                    //cout << "token = " << token[token_index] << endl;
                    if(token[token_index].compare("<square>")==0 && current_block_state == BLOCK_STATE_TYPE)
                    {
                        //token_index++;
                        int end_token = token_index+1;
                        int sq_scope = 1;
                        for(; end_token < token.size(); end_token++)
                        {
                            if(token[end_token].compare("<square>")==0)
                                sq_scope++;
                            else if(token[end_token].compare("</square>")==0)
                                sq_scope--;

                            if(sq_scope==0)
                                break;
                        }
                        if(sq_scope != 0)
                        {
                            rc_setError("Expected ] in array definition");
                            return false;
                        }
                        /*if(end_token > token_index)
                            end_token--;
                        else
                        {
                            rc_setError("Expected atleast 1 parameter in member array definition");
                            return false;
                        }*/
                        //if(eval_constantExpression(token_index, end_token))
                        //cout << "EVAL EXPR" << endl;
                        if(eval_expression(token_index, end_token, true))
                        {
                            dimensions = multi_arg_count;
                        }
                        else
                        {
                            rc_setError("Expected constant for type member array");
                            return false;
                        }

                        token_index = end_token+1;

                        //cout << "DBG token = " << token[token_index] << std::endl;

                        if(token.size() > token_index)
                        {
                            if(token[token_index].compare("<as>")==0)
                            {
                                token_index++;
                                if(token[token_index].substr(0,4).compare("<id>")!=0)
                                {
                                    rc_setError("Invalid type identifier name in DIM");
                                    return false;
                                }

                                id_type = ID_TYPE_USER;
                                id_type_name = token[token_index].substr(4);
                                //cout << "Add member (" << id_name << ") of type (" << id_type_name << ") with " << dimensions << " dimensions [" << constant_arg[0] << "," << constant_arg[1] << "," << constant_arg[2] << "]" << endl;
                                //if(!add_type_member(id_name, id_type, id_type_name, dimensions, constant_arg[0], constant_arg[1], constant_arg[2]))
                                if(!add_type_member(id_name, id_type, id_type_name, dimensions, multi_arg[0], multi_arg[1], multi_arg[2]))
                                    return false;
                            }
                            else
                            {
                                rc_setError("Invalid member array declaration in DIM");
                                return false;
                            }
                        }
                        else
                        {
                            //cout << "Add member (" << id_name << ") of type (num/str) with " << dimensions << " dimensions [" << constant_arg[0] << "," << constant_arg[1] << "," << constant_arg[2] << "]" << endl;
                            //if(!add_type_member(id_name, id_type, "", dimensions, constant_arg[0], constant_arg[1], constant_arg[2]))
                            if(!add_type_member(id_name, id_type, "", dimensions, multi_arg[0], multi_arg[1], multi_arg[2]))
                                return false;
                        }

                        return true;

                    }
                    else if(token[token_index].compare("<square>")==0)
                    {
                        multi_arg[0] = "";
                        multi_arg[1] = "";
                        multi_arg[2] = "";
                        multi_arg_count = 0;
                        int end_token = token_index+1;
                        int sq_scope = 1;
                        for(; end_token < token.size(); end_token++)
                        {
                            if(token[end_token].compare("</square>")==0)
                                sq_scope--;
                            else if(token[end_token].compare("<square>")==0)
                                sq_scope++;

                            if(sq_scope==0)
                                break;
                        }
                        if(sq_scope != 0)
                        {
                            rc_setError("Expected ] in array definition");
                            return false;
                        }
                        if(!eval_expression(token_index, end_token, true))
                        {
                            rc_setError("Could not evaluate expression in array definition");
                            return false;
                        }
                        if(multi_arg_count <= 0 || multi_arg_count > 3)
                        {
                            rc_setError("Expected 1 to 3 Arguments for array definition, Found " + rc_intToString(multi_arg_count));
                            return false;
                        }
                        else
                        {
                            //cout << "M_ARG[0] = " << multi_arg[0] << endl;
                            //cout << "M_ARG[1] = " << multi_arg[1] << endl;
                            //cout << "M_ARG[2] = " << multi_arg[2] << endl;
                            dimensions = multi_arg_count;
                        }
                        token_index = end_token+1;

                        if(token.size()>token_index)
                        {
                            if(token[token_index].compare("<as>")==0)
                            {
                                token_index++;
                                if(token.size()>token_index)
                                {
                                    if(token[token_index].substr(0,4).compare("<id>")!=0)
                                    {
                                        rc_setError("Invalid type identifier in DIM");
                                        return false;
                                    }

                                    id_type_name = token[token_index].substr(4);

                                    //cout << "DIM <" << id_name << "> AS < " << id_type_name << " [";
                                    switch(dimensions)
                                    {
                                        case 1:
                                            //cout << multi_arg[0] << "] >" << endl;
                                            break;
                                        case 2:
                                            //cout << multi_arg[0] << ", " << multi_arg[1] << "] >" << endl;
                                            break;
                                        case 3:
                                            //cout << multi_arg[0] << ", " << multi_arg[1] << ", " << multi_arg[2] << "] >" << endl;
                                            break;
                                        default:
                                            rc_setError("Too many arguments in DIM");
                                            return false;
                                    }

                                    create_array(id_name, ID_TYPE_USER, id_type_name, dimensions, multi_arg[0], multi_arg[1], multi_arg[2]);
                                    //vm_asm.push_back("preset_t !" + )
                                    //cout << "Create FN USER ARRAY - " << id_name << endl;
                                    return true;
                                }
                                else
                                {
                                    rc_setError("Expected type identifier in DIM");
                                    return false;
                                }
                            }
                            else
                            {
                                rc_setError("Invalid array type definition");
                                return false;
                            }
                        }
                    }
                    else if(token[token_index].compare("<as>")==0)
                    {
                        id_type = ID_TYPE_USER;

                        if(token.size() != 4)
                        {
                            rc_setError("Expected single type identifier in DIM");
                            return false;
                        }
                        else if(token[3].substr(0,4).compare("<id>")!=0)
                        {
                            rc_setError("Invalid type identifier name in DIM");
                            return false;
                        }

                        if(current_block_state == BLOCK_STATE_TYPE)
                        {
                            //cout << "create member (" << id_name << ") of type " << token[3].substr(4) << endl;
                            if(!add_type_member(id_name, ID_TYPE_USER, token[3].substr(4), 0))
                                return false;
                        }
                        else
                        {
                            //cout << "create variable (" << id_name << ") of type " << token[3].substr(4) << endl;
                            if(!create_variable(id_name, id_type, token[3].substr(4)))
                                return false;
                        }

                        return true;
                    }

                    if(token.size()>token_index)
                    {
                        rc_setError("Invalid variable definition: " + token[token_index] + ", " + rc_intToString(current_block_state) + " <--> " + rc_intToString(BLOCK_STATE_TYPE));
                        return false;
                    }

                }
                else
                {
                    //if the next token is not an id then the syntax is incorrect and false is returned
                    rc_setError("Expected Identifier name");
                    return false;
                }

                if(dimensions > 0)
                {
                    switch(id_type)
                    {
                        case ID_TYPE_NUM:
                            id_type = ID_TYPE_ARR_NUM;
                            break;
                        case ID_TYPE_STR:
                            id_type = ID_TYPE_ARR_STR;
                            break;
                    }
                    if(isInFunctionScope)
                    {
                        if(!create_function_array(id_name,id_type, dimensions, multi_arg[0], multi_arg[1], multi_arg[2]))
                        {
                            return false;
                        }
                    }
                    else if(!create_array(id_name, id_type, id_type_name, dimensions, multi_arg[0], multi_arg[1], multi_arg[2]))
                    {
                        //cout << rc_getError() << endl;
                        return false;
                    }
                    //cout << "Created Array: " << id_name << " of type " << id_type << endl;
                }
                else
                {
                    if(!create_variable(id_name, id_type, id_type_name))
                    {
                        //cout << rc_getError() << endl;
                        return false;
                    }
                }

            }
            else
            {
                //if the size of the token vector is not greater than one then the syntax for the line is incomplete so I return false
                rc_setError("Expected Identifier name");
                return false;
            }
        }
        else if(token[0].compare("<redim>")==0)
        {
            //cout << "REDIM RULE FOUND" << endl;  //'DIM' [ID]; '[' #; #; # ']' ; 'AS' [TYPE]; '=' (VALUE)

            string id_name = "";
            int id_type = ID_TYPE_NUM;
            string id_type_name = "";
            int dimensions = 0;
            int id_index = -1;

            //check if the next token is a identifier
            if(token.size() > 1)
            {
                if(token[1].substr(0,4).compare("<id>")==0)
                {
                    //if the identifier is not a valid name then return false
                    id_name = token[1].substr(4);
                    id_type = ID_TYPE_NUM;
                    id_type_name = "";
                    dimensions = 0;

                    if(!isValidIDName(id_name))
                    {
                        rc_setError("Invalid Identifier name");
                        return false;
                    }


                    id_index  = getIDInScope_ByIndex(id_name);
                    //cout << "debug 0: " << id_index << " -> " << id[id_index].name << " --- " << id[id_index].vec_pos << endl;

                    //if the identifier already exists and current_block state is not type then return false
                    if(id_index < 0)
                    {
                        rc_setError("Identifier was not defined in current scope");
                        return false;
                    }


                    if(id[id_index].num_args <= 0)
                    {
                        rc_setError("REDIM expected array identifier");
                        return false;
                    }


                    id_type = id[id_index].type;
                    type_redim_arg_type = 0;

                    //cout << "db1\n";

                    //if there are only two tokens then return here because there is nothing left to check
                    if(token.size()==2)
                    {
                        rc_setError("Dimensions must be specified for REDIM");
                        //cout << "return true here" << endl;
                        return false;
                    }

                    //cout << "db2\n";

                    //current token
                    int token_index = 2;

                    //check for the next rule; must be [], AS, or =
                    if(token[token_index].compare("<square>")==0 && current_block_state == BLOCK_STATE_TYPE)
                    {
                        token_index++;
                        int end_token = token_index;
                        int sq_scope = 1;
                        for(; end_token < token.size(); end_token++)
                        {
                            if(token[end_token].compare("<square>")==0)
                                sq_scope++;
                            else if(token[end_token].compare("</square>")==0)
                                sq_scope--;

                            if(sq_scope==0)
                                break;
                        }
                        if(sq_scope != 0)
                        {
                            rc_setError("Expected ] in array definition");
                            return false;
                        }
                        if(end_token > token_index)
                            end_token--;
                        else
                        {
                            rc_setError("Expected atleast 1 parameter in member array definition");
                            return false;
                        }
                        if(eval_constantExpression(token_index, end_token))
                        {
                            dimensions = constant_arg_count;
                        }
                        else
                        {
                            rc_setError("Expected constant for type member array");
                            return false;
                        }
                        token_index = end_token+2;

                    }
                    else if(token[token_index].compare("<square>")==0)
                    {
                        multi_arg[0] = "";
                        multi_arg[1] = "";
                        multi_arg[2] = "";
                        multi_arg_count = 0;
                        int end_token = token_index+1;
                        int sq_scope = 1;
                        bool has_child = false;
                        for(; end_token < token.size(); end_token++)
                        {
                            if(token[end_token].compare("</square>")==0)
                                sq_scope--;
                            else if(token[end_token].compare("<square>")==0)
                                sq_scope++;

                            if( (end_token+1) < token.size() )
                            {
                                if(token[end_token+1].compare("<child>")==0 || token[end_token].compare("<child>")==0)
                                {
                                    has_child = true;
                                    continue;
                                }
                                else if(token[end_token+1].compare("<square>")==0)
                                    continue;
                            }

                            if(sq_scope==0)
                                break;
                        }

                        if(sq_scope != 0)
                        {
                            rc_setError("Expected ] in array definition");
                            return false;
                        }

                        //cout << "DEBUG TOKENS: " << endl;
                        //cout << "----------------------" << endl;
                        //for(int tk = token_index; tk < end_token; tk++) cout << token[tk] << endl;
                        //cout << "-------------------------------------" << endl;

                        if(has_child)
                        {
                            token_index = 1;
                            type_redim_flag = true;
                            type_redim_arg_type = 0;
                        }
                        else
                            type_redim_flag = false;

                        //cout << "debug 1: " << id_index << endl;

                        if(!eval_expression(token_index, end_token, true))
                        {
                            rc_setError("Could not evaluate expression in array definition");
                            return false;
                        }

                        //cout << "debug 2: " << id_index << endl;

                        if(type_redim_flag)
                        {
                            if(type_redim_dim_count <= 0)
                            {
                                rc_setError("Expected 1 to 3 Arguments for array re-dimension, Found " + rc_intToString(multi_arg_count));
                                return false;
                            }
                            dimensions = type_redim_dim_count;
                            multi_arg[0] = type_redim_dim[0];
                            multi_arg[1] = type_redim_dim[1];
                            multi_arg[2] = type_redim_dim[2];

                            //cout << "type arg = " << type_redim_arg << "  type = " << type_redim_arg_type << "  utype = " << type_redim_arg_utype << endl;
                        }
                        else if(multi_arg_count <= 0 || multi_arg_count > 3)
                        {
                            rc_setError("Expected 1 to 3 Arguments for array re-dimension, Found " + rc_intToString(multi_arg_count));
                            return false;
                        }
                        else
                        {
                            //cout << "M_ARG[0] = " << multi_arg[0] << endl;
                            //cout << "M_ARG[1] = " << multi_arg[1] << endl;
                            //cout << "M_ARG[2] = " << multi_arg[2] << endl;
                            dimensions = multi_arg_count;
                        }
                        token_index = end_token+1;

                        //cout << "debug 3: " << id_index << endl;
                    }
                    else
                    {
                        rc_setError("Expected dimensions for REDIM");
                        return false;
                    }

                    if(token.size()>token_index)
                    {
                        rc_setError("Invalid use of REDIM");
                        return false;
                    }

                    //cout << "debug 4: " << id_index << endl;

                }
                else
                {
                    //if the next token is not an id then the syntax is incorrect and false is returned
                    rc_setError("Expected Identifier name");
                    return false;
                }

                if(!type_redim_flag) //if type_redim_flag is set, then this error will get raised in the pre_parse step
                {
                    if(dimensions != id[id_index].num_args) // no longer allowing the user to change dimensions since it can lead to unnecessary confusion
                    {
                        rc_setError("Expected " + rc_intToString(id[id_index].num_args) + " dimensions but found " + rc_intToString(dimensions));
                        return false;
                    }
                }

                type_redim_flag = false;

                if(dimensions > 0)
                {
                    //cout << "debug 5: " << id_index <<  endl;
                    switch(id_type)
                    {
                        case ID_TYPE_NUM:
                            id_type = ID_TYPE_ARR_NUM;
                            break;
                        case ID_TYPE_STR:
                            id_type = ID_TYPE_ARR_STR;
                            break;
                    }

                    //cout << "debug 6: " << id_index << endl;

                    //if(id[id_index].num_args != dimensions)
                    //{
                    //    id[id_index].num_args = dimensions;
                    //}

                    //cout << "debug 7: " << id_index << " -- " << id[id_index].type << endl;

                    if(type_redim_arg_type == ID_TYPE_USER)
                    {
                        switch(dimensions)
                        {
                            case 1:
                                vm_asm.push_back("redim_type1 " + type_redim_arg + " " + type_redim_arg_utype + " " + multi_arg[0]);
                                break;
                            case 2:
                                vm_asm.push_back("redim_type2 " + type_redim_arg + " " + type_redim_arg_utype + " " + multi_arg[0] + " " + multi_arg[1]);
                                break;
                            case 3:
                                vm_asm.push_back("redim_type3 " + type_redim_arg + " " + type_redim_arg_utype + " " + multi_arg[0] + " " + multi_arg[1] + " " + multi_arg[2]);
                                break;
                            default:
                                rc_setError("Invalid number of dimensions in REDIM");
                                return false;
                        }
                    }
                    else if(type_redim_arg_type == ID_TYPE_USER_NUM || type_redim_arg_type == ID_TYPE_USER_NUM_ARRAY)
                    {
                        switch(dimensions)
                        {
                            case 1:
                                vm_asm.push_back("redim_type_n1 " + type_redim_arg + " " + multi_arg[0]);
                                break;
                            case 2:
                                vm_asm.push_back("redim_type_n2 " + type_redim_arg + " " + multi_arg[0] + " " + multi_arg[1]);
                                break;
                            case 3:
                                vm_asm.push_back("redim_type_n3 " + type_redim_arg + " " + multi_arg[0] + " " + multi_arg[1] + " " + multi_arg[2]);
                                break;
                            default:
                                rc_setError("Invalid number of dimensions in REDIM");
                                return false;
                        }
                    }
                    else if(type_redim_arg_type == ID_TYPE_USER_STR || type_redim_arg_type == ID_TYPE_USER_STR_ARRAY)
                    {
                        switch(dimensions)
                        {
                            case 1:
                                vm_asm.push_back("redim_type_s1 " + type_redim_arg + " " + multi_arg[0]);
                                break;
                            case 2:
                                vm_asm.push_back("redim_type_s2 " + type_redim_arg + " " + multi_arg[0] + " " + multi_arg[1]);
                                break;
                            case 3:
                                vm_asm.push_back("redim_type_s3 " + type_redim_arg + " " + multi_arg[0] + " " + multi_arg[1] + " " + multi_arg[2]);
                                break;
                            default:
                                rc_setError("Invalid number of dimensions in REDIM");
                                return false;
                        }
                    }
                    else if(id[id_index].type == ID_TYPE_USER)
                    {
                        vm_asm.push_back("redim_top"); //This will set the top level flag for redim_type

                        //cout << "debug 8" << endl;
                        switch(dimensions)
                        {
                            case 1:
                                vm_asm.push_back("redim_type1 !" + rc_intToString(id[id_index].vec_pos) + " !" + rc_intToString(id[id_index].type_index) + " " + multi_arg[0]);
                                break;
                            case 2:
                                vm_asm.push_back("redim_type2 !" + rc_intToString(id[id_index].vec_pos) + " !" + rc_intToString(id[id_index].type_index) + " " + multi_arg[0] + " " + multi_arg[1]);
                                break;
                            case 3:
                                vm_asm.push_back("redim_type3 !" + rc_intToString(id[id_index].vec_pos) + " !" + rc_intToString(id[id_index].type_index) + " " + multi_arg[0] + " " + multi_arg[1] + " " + multi_arg[2]);
                                break;
                            default:
                                rc_setError("Invalid number of dimensions in REDIM");
                                return false;
                        }
                    }
                    else if(id[id_index].type == ID_TYPE_NUM || id[id_index].type == ID_TYPE_ARR_NUM)
                    {
                        //cout << "debug 8" << endl;
                        switch(dimensions)
                        {
                            case 1:
                                vm_asm.push_back("redim1 !" + rc_intToString(id[id_index].vec_pos) + " " + multi_arg[0]);
                                break;
                            case 2:
                                vm_asm.push_back("redim2 !" + rc_intToString(id[id_index].vec_pos) + " " + multi_arg[0] + " " + multi_arg[1]);
                                break;
                            case 3:
                                vm_asm.push_back("redim3 !" + rc_intToString(id[id_index].vec_pos) + " " + multi_arg[0] + " " + multi_arg[1] + " " + multi_arg[2]);
                                break;
                            default:
                                rc_setError("Invalid number of dimensions in REDIM");
                                return false;
                        }
                    }
                    else if(id[id_index].type == ID_TYPE_STR || id[id_index].type == ID_TYPE_ARR_STR)
                    {
                        switch(dimensions)
                        {
                            case 1:
                                vm_asm.push_back("redim1$ !" + rc_intToString(id[id_index].vec_pos) + " " + multi_arg[0]);
                                break;
                            case 2:
                                vm_asm.push_back("redim2$ !" + rc_intToString(id[id_index].vec_pos) + " " + multi_arg[0] + " " + multi_arg[1]);
                                break;
                            case 3:
                                vm_asm.push_back("redim3$ !" + rc_intToString(id[id_index].vec_pos) + " " + multi_arg[0] + " " + multi_arg[1] + " " + multi_arg[2]);
                                break;
                            default:
                                rc_setError("Invalid number of dimensions in REDIM");
                                return false;
                        }
                    }
                    else
                    {
                        rc_setError("Invalid type for REDIM: " + rc_intToString(id[id_index].type));
                        return false;
                    }
                    //cout << "balls" << endl;
                    return true;
                }
                else
                {
                    rc_setError("Expected dimensions in REDIM");
                    return false;
                }

            }
            else
            {
                //if the size of the token vector is not greater than one then the syntax for the line is incomplete so I return false
                rc_setError("Expected Identifier name");
                return false;
            }
            //cout << "debug final" << endl;
        }
        else if(token[0].compare("<end>")==0)
        {
            if(token.size()==1)
            {
                vm_asm.push_back("end");
                return true;
            }
            if(token[1].compare("<function>")==0)
            {
                if(token.size()>2)
                {
                    rc_setError("Expected End of Line in END FUNCTION");
                    return false;
                }
                if(current_block_state != BLOCK_STATE_FUNCTION)
                {
                    rc_setError("Cannot exit function from this scope");
                    return false;
                }

                //int ptr_count = 0;
                //for(int n = 0; n < id[current_fn_index].fn_arg.size(); n++)
                //{
                //    if(id[current_fn_index].fn_arg_type[n] == ID_TYPE_BYREF_NUM || id[current_fn_index].fn_arg_type[n] == ID_TYPE_BYREF_STR)
                //    {
                //        ptr_count++;
                //    }
                //}

                //if(ptr_count > 0)
                //    vm_asm.push_back("pop_ptr !" + rc_intToString(ptr_count));
                if(id[current_fn_index].type == ID_TYPE_FN_NUM)
                {
                    vm_asm.push_back("push 0");
                    vm_asm.push_back("return");
                    vm_asm.push_back(".code");
                    vm_asm.n_stack_count = 0;
                }
                else if(id[current_fn_index].type == ID_TYPE_FN_STR)
                {
                    vm_asm.push_back("push_empty$");
                    vm_asm.push_back("return");
                    vm_asm.push_back(".code");
                    vm_asm.s_stack_count = 0;
                }
                else if(id[current_fn_index].type == ID_TYPE_FN_USER)
                {
                    vm_asm.push_back("dim_type u0 !" + rc_intToString(id[current_fn_index].type_index));
                    vm_asm.push_back("push_t u0");
                    vm_asm.push_back("return");
                    vm_asm.push_back(".code");
                    vm_asm.u_stack_count = 0;
                }
                block_state.pop();
                current_block_state = BLOCK_STATE_MAIN;
                isInFunctionScope = false;
                current_scope = "main";

                for(uint64_t i = 0; i < id[current_fn_index].fn_arg.size(); i++)
                {
                    uint64_t id_vec = id[current_fn_index].fn_arg_vec[i];
                    uint64_t id_type = id[current_fn_index].fn_arg_type[i];
                    uint64_t id_utype = id[current_fn_index].fn_arg_utype[i];

                    if(id_type == ID_TYPE_USER)
                    {
                        vm_asm.push_back("dim_type !" + rc_intToString(id_vec) + " !" + rc_intToString(id_utype));
                    }
                }

                current_fn_index++;
            }
            else if(token[1].compare("<subp>")==0)
            {
                if(token.size()>2)
                {
                    rc_setError("Expected End of Line in END SUB");
                    return false;
                }
                if(current_block_state != BLOCK_STATE_SUB)
                {
                    rc_setError("Cannot exit sub routine from this scope");
                    return false;
                }

                //int ptr_count = 0;
                //for(int n = 0; n < id[current_fn_index].fn_arg.size(); n++)
                //{
                //    if(id[current_fn_index].fn_arg_type[n] == ID_TYPE_BYREF_NUM || id[current_fn_index].fn_arg_type[n] == ID_TYPE_BYREF_STR)
                //    {
                //        ptr_count++;
                //    }
                //}

                //if(ptr_count > 0)
                //    vm_asm.push_back("pop_ptr !" + rc_intToString(ptr_count));

                vm_asm.push_back("return");
                vm_asm.push_back(".code");

                block_state.pop();
                current_block_state = BLOCK_STATE_MAIN;
                isInFunctionScope = false;
                current_scope = "main";

                for(uint64_t i = 0; i < id[current_fn_index].fn_arg.size(); i++)
                {
                    uint64_t id_vec = id[current_fn_index].fn_arg_vec[i];
                    uint64_t id_type = id[current_fn_index].fn_arg_type[i];
                    uint64_t id_utype = id[current_fn_index].fn_arg_utype[i];

                    if(id_type == ID_TYPE_USER)
                    {
                        vm_asm.push_back("dim_type !" + rc_intToString(id_vec) + " !" + rc_intToString(id_utype));
                    }
                }

                current_fn_index++;
            }
            else if(token[1].compare("<type>")==0)
            {
                if(token.size()>2)
                {
                    rc_setError("Expected End of Line in END TYPE");
                    return false;
                }
                if(current_block_state != BLOCK_STATE_TYPE)
                {
                    rc_setError("Cannot exit TYPE definition from this scope");
                    return false;
                }

                block_state.pop();
                current_block_state = BLOCK_STATE_MAIN;
                current_scope = "main";
            }
            else if(token[1].compare("<if>")==0)
            {
                if(token.size() > 2)
                {
                    rc_setError("Expected End of Line in END IF");
                    return false;
                }
                if(current_block_state != BLOCK_STATE_IF)
                {
                    rc_setError("Cannot END IF without starting an IF Block");
                    return false;
                }
                block_state.pop();
                current_block_state = block_state.top();

                vm_asm.push_back("label ELSE:" + rc_intToString(if_block.top().index) + "->CONDITION:" + rc_intToString(if_block.top().condition));
                vm_asm.push_back("label ENDIF:" + rc_intToString(if_block.top().index));
                if_block.pop();
                exit_scope(1);
            }
            else if(token[1].compare("<select>")==0)
            {
                if(token.size() > 2)
                {
                    rc_setError("Expected End of Line in END SELECT");
                    return false;
                }
                if(current_block_state != BLOCK_STATE_SELECT)
                {
                    rc_setError("Cannot END SELECT without starting a SELECT Block");
                    return false;
                }
                block_state.pop();
                current_block_state = block_state.top();


                vm_asm.push_back("label SELECT:" + rc_intToString(select_block.top().index) + "->CASE:" + rc_intToString(select_block.top().case_index));
                vm_asm.push_back("label SELECT:" + rc_intToString(select_block.top().index) + "->END");

                if(select_block.top().case_type==ID_TYPE_STR)
                {
                    string compare_case = "s" + rc_intToString(s_reg);
                    vm_asm.push_back("pop$ " + compare_case);
                    inc_s(1);
                }
                else
                {
                    string compare_case = "n" + rc_intToString(n_reg);
                    vm_asm.push_back("pop " + compare_case);
                    inc_n(1);
                }

                select_block.pop();
                exit_scope(1);
            }
            else
            {
                if(!eval_expression(1, token.size()-1))
                {
                    rc_setError("Could not evaluate expression");
                    return false;
                }

                if(expr_result.substr(0,1).compare("n")!=0)
                {
                    rc_setError("Expected a number expression");
                    return false;
                }

                vm_asm.push_back("end_x " + expr_result);
                return true;
            }
        }
        else if(token[0].compare("<function>")==0)
        {
            if(isInFunctionScope)
            {
                rc_setError("Cannot declare FUNCTION from this scope");
                return false;
            }
            if(token.size()<2)
            {
                rc_setError("Expected identifier for FUNCTION declaration");
                return false;
            }

            string fn_name = rc_substr(token[1], 4, token[1].length());
            if(!isValidIDName(fn_name) )
            {
                rc_setError(fn_name + " is not a valid identifier name");
                return false;
            }
            if(idExistsInScope(fn_name))
            {
                rc_setError("Identifier " + fn_name + " already exists in this scope");
                return false;
            }

            int fn_type = ID_TYPE_FN_NUM;
            if(fn_name.substr(fn_name.length()-1,1).compare("$")==0)
                fn_type = ID_TYPE_FN_STR;

            string fn_type_name = "";
            if(token.size()>2)
            {
                if(token[token.size()-2].compare("<as>")==0)
                {
                    fn_type = ID_TYPE_FN_USER;
                    if(token[token.size()-1].substr(0,4).compare("<id>")==0)
                        fn_type_name = token[token.size()-1].substr(4);
                    else
                    {
                        rc_setError("Invalid return type in FUNCTION definition");
                        return false;
                    }
                    token.pop_back();
                    token.pop_back();
                }
            }

            if(!create_function(fn_name, fn_type, fn_type_name))
            {
                rc_setError("Could not create FUNCTION \"" + fn_name + "\" of type \"" + fn_type_name + "\"");
                return false;
            }
            current_block_state = BLOCK_STATE_FUNCTION;
            block_state.push(current_block_state);

            string fn_arg = "";
            int fn_arg_type = ID_TYPE_NUM;
            string fn_arg_user_type = "";
            bool fn_byref = false;

            int end_token = 0;

            for(int i = 3; i < token.size(); i++)
            {
                if(token[i].compare("<byref>")==0)
                {
                    fn_byref = true;
                }
                else if(rc_substr(token[i], 0, 4).compare("<id>")==0)
                {
                    fn_arg += token[i];
                    if(fn_arg.substr(fn_arg.length()-1,1).compare("$")==0)
                        fn_arg_type = ID_TYPE_STR;
                    else
                        fn_arg_type = ID_TYPE_NUM;
                }
                else if(token[i].compare("<as>")==0)
                {
                    i++;
                    fn_arg_type = ID_TYPE_USER;
                    fn_arg_user_type = "";
                    int arg_type_index = -1;
                    if(i < token.size())
                        if(token[i].substr(0,4).compare("<id>")==0)
                            fn_arg_user_type = token[i].substr(4);

                    if(fn_arg_user_type.compare("")==0)
                    {
                        rc_setError("Invalid Type in FUNCTION Definition");
                        return false;
                    }

                }
                else if(token[i].compare("<comma>")==0)
                {
                    //cout << "ADD ARG: " << fn_arg << endl;
                    fn_arg = rc_substr(fn_arg, 4, fn_arg.length()-1);
                    if(!isValidIDName(fn_arg))
                    {
                        rc_setError("FUNCTION argument is not a valid identifier name");
                        return false;
                    }
                    if(idExistsInScope(fn_arg))
                    {
                        rc_setError("FUNCTION argument identifier already exists in current scope");
                        return false;
                    }

                    //cout << "CHECK 1" << endl;

                    if(fn_byref)
                    {
                        if(fn_arg_type == ID_TYPE_NUM)
                            fn_arg_type = ID_TYPE_BYREF_NUM;
                        else if(fn_arg_type == ID_TYPE_STR)
                            fn_arg_type = ID_TYPE_BYREF_STR;
                        else
                            fn_arg_type = ID_TYPE_BYREF_USER;
                    }

                    if(!add_function_arg(fn_arg, fn_arg_type, fn_arg_user_type))
                    {
                        return false;
                    }
                    fn_arg = "";
                    fn_byref = false;

                    //cout << "DONE" << endl;
                }
                else if(token[i].compare("</par>")==0)
                {
                    if((i+1) < token.size())
                    {
                        rc_setError("Expected End of FUNCTION Declaration");
                        return false;
                    }
                    if(fn_arg.compare("")==0)
                    {
                        end_token = i+1;
                        break;
                    }
                    fn_arg = rc_substr(fn_arg, 4, fn_arg.length()-1);
                    if(!isValidIDName(fn_arg))
                    {
                        rc_setError("FUNCTION argument is not a valid identifier name");
                        return false;
                    }
                    if(idExistsInScope(fn_arg))
                    {
                        rc_setError("FUNCTION argument identifier already exists in current scope");
                        return false;
                    }

                    if(fn_byref)
                    {
                        if(fn_arg_type == ID_TYPE_NUM)
                            fn_arg_type = ID_TYPE_BYREF_NUM;
                        else if(fn_arg_type == ID_TYPE_STR)
                            fn_arg_type = ID_TYPE_BYREF_STR;
                        else
                            fn_arg_type = ID_TYPE_BYREF_USER;
                    }

                    if(!add_function_arg(fn_arg, fn_arg_type, fn_arg_user_type))
                    {
                        return false;
                    }

                    fn_arg = "";
                    fn_byref = false;
                    end_token = i+1;
                    break;
                }
                else
                {
                    rc_setError("Argument to FUNCTION must be a valid identifier: " + token[i]);
                }
            }

            if(token.size()>end_token)
            {
                rc_setError("Expected end of FUNCTION declaration");
                return false;
            }

        }
        else if(token[0].compare("<subp>")==0)
        {
            if(isInFunctionScope)
            {
                rc_setError("Cannot declare SUB ROUTINE from this scope");
                return false;
            }
            if(token.size()<2)
            {
                rc_setError("Expected identifier for SUB ROUTINE declaration");
                return false;
            }

            string fn_name = rc_substr(token[1], 4, token[1].length());
            if(!isValidIDName(fn_name) )
            {
                rc_setError(fn_name + " is not a valid identifier name");
                return false;
            }
            if(idExistsInScope(fn_name))
            {
                rc_setError("Identifier " + fn_name + " already exists in this scope");
                return false;
            }

            int fn_type = ID_TYPE_SUB;

            string fn_type_name = "";

            if(!create_function(fn_name, fn_type, fn_type_name))
            {
                rc_setError("Could not create SUB ROUTINE \"" + fn_name + "\"");
                return false;
            }
            current_block_state = BLOCK_STATE_SUB;
            block_state.push(current_block_state);

            string fn_arg = "";
            int fn_arg_type = ID_TYPE_NUM;
            string fn_arg_user_type = "";
            bool fn_byref = false;

            int end_token = 0;

            for(int i = 3; i < token.size(); i++)
            {
                if(token[i].compare("<byref>")==0)
                {
                    fn_byref = true;
                }
                else if(rc_substr(token[i], 0, 4).compare("<id>")==0)
                {
                    fn_arg += token[i];
                    if(fn_arg.substr(fn_arg.length()-1,1).compare("$")==0)
                        fn_arg_type = ID_TYPE_STR;
                    else
                        fn_arg_type = ID_TYPE_NUM;
                }
                else if(token[i].compare("<as>")==0)
                {
                    i++;
                    fn_arg_type = ID_TYPE_USER;
                    fn_arg_user_type = "";
                    int arg_type_index = -1;
                    if(i < token.size())
                        if(token[i].substr(0,4).compare("<id>")==0)
                            fn_arg_user_type = token[i].substr(4);

                    if(fn_arg_user_type.compare("")==0)
                    {
                        rc_setError("Invalid Type in SUB ROUTINE Definition");
                        return false;
                    }

                }
                else if(token[i].compare("<comma>")==0)
                {
                    //cout << "ADD ARG: " << fn_arg << endl;
                    fn_arg = rc_substr(fn_arg, 4, fn_arg.length()-1);
                    if(!isValidIDName(fn_arg))
                    {
                        rc_setError("SUB ROUTINE argument is not a valid identifier name");
                        return false;
                    }
                    if(idExistsInScope(fn_arg))
                    {
                        rc_setError("SUB ROUTINE argument identifier already exists in current scope");
                        return false;
                    }

                    //cout << "CHECK 1" << endl;

                    if(fn_byref)
                    {
                        if(fn_arg_type == ID_TYPE_NUM)
                            fn_arg_type = ID_TYPE_BYREF_NUM;
                        else if(fn_arg_type == ID_TYPE_STR)
                            fn_arg_type = ID_TYPE_BYREF_STR;
                        else
                            fn_arg_type = ID_TYPE_BYREF_USER;
                    }

                    if(!add_function_arg(fn_arg, fn_arg_type, fn_arg_user_type))
                    {
                        return false;
                    }
                    fn_arg = "";
                    fn_byref = false;

                    //cout << "DONE" << endl;
                }
                else if(token[i].compare("</par>")==0)
                {
                    if((i+1) < token.size())
                    {
                        rc_setError("Expected End of SUB ROUTINE Declaration");
                        return false;
                    }
                    if(fn_arg.compare("")==0)
                    {
                        end_token = i+1;
                        break;
                    }
                    fn_arg = rc_substr(fn_arg, 4, fn_arg.length()-1);
                    if(!isValidIDName(fn_arg))
                    {
                        rc_setError("SUB ROUTINE argument is not a valid identifier name");
                        return false;
                    }
                    if(idExistsInScope(fn_arg))
                    {
                        rc_setError("SUB ROUTINE argument identifier already exists in current scope");
                        return false;
                    }

                    if(fn_byref)
                    {
                        if(fn_arg_type == ID_TYPE_NUM)
                            fn_arg_type = ID_TYPE_BYREF_NUM;
                        else if(fn_arg_type == ID_TYPE_STR)
                            fn_arg_type = ID_TYPE_BYREF_STR;
                        else
                            fn_arg_type = ID_TYPE_BYREF_USER;
                    }

                    if(!add_function_arg(fn_arg, fn_arg_type, fn_arg_user_type))
                    {
                        return false;
                    }

                    fn_arg = "";
                    fn_byref = false;
                    end_token = i+1;
                    break;
                }
                else
                {
                    rc_setError("Argument to SUB ROUTINE must be a valid identifier: " + token[i]);
                }
            }

            if(token.size()>end_token)
            {
                rc_setError("Expected end of SUB ROUTINE declaration");
                return false;
            }

        }
        else if(token[0].compare("<return>")==0)
        {
            string tmp_scope = current_scope;
            stack<select_data> tmp_select_stack = select_block;
            int fnID = -1;
            if(current_block_state != BLOCK_STATE_FUNCTION && current_block_state != BLOCK_STATE_SUB)
            {
                string scope_type = "";
                int scope_start = current_scope.find_last_of(".");

                while(scope_start > 0)
                {
                    scope_type = current_scope.substr(scope_start+1);

                    //cout << "\nSCOPE_TYPE->" << scope_type << endl << endl;

                    if(rc_substr(scope_type, 0, 5).compare("#FOR:")==0)
                    {
                        vm_asm.push_back("pop_loop_stack");
                    }
                    else if(rc_substr(scope_type, 0, 8).compare("#SELECT:")==0)
                    {
                        if(tmp_select_stack.top().case_type == ID_TYPE_STR)
                        {
                            vm_asm.push_back("pop$ s0"); //doesnt matter which reg I use since EXIT does not allow expressions
                        }
                        else
                        {
                            vm_asm.push_back("pop n0");
                        }
                        tmp_select_stack.pop();
                    }
                    else
                    {
                        fnID = getIDInScope_ByIndex(scope_type);

                        if(fnID < 0)
                        {
                            exit_scope(1);
                            scope_start = current_scope.find_last_of(".");
                            continue;
                        }

                        int ptr_count = 0;
                        for(int n = 0; n < id[fnID].fn_arg.size(); n++)
                        {
                            if(id[fnID].fn_arg_type[n] == ID_TYPE_BYREF_NUM || id[fnID].fn_arg_type[n] == ID_TYPE_BYREF_STR)
                            {
                                ptr_count++;
                            }
                        }

                        //if(ptr_count > 0)
                        //    vm_asm.push_back("pop_ptr !" + rc_intToString(ptr_count));

                        //cout << "\nRETURN FROM FUNCTION" << id[fnID].name << endl << endl;


                        if(id[fnID].type == ID_TYPE_FN_NUM || id[fnID].type == ID_TYPE_FN_STR)
                        {
                            break;
                        }
                        else if(id[fnID].type == ID_TYPE_SUB)
                        {
                            if(token.size() > 1)
                            {
                                rc_setError("Cannot return a value from a SUB ROUTINE, You should use a FUNCTION instead");
                                return false;
                            }
                            else
                            {
                                current_scope = tmp_scope;
                                vm_asm.push_back("return");
                                return true;
                            }
                        }
                        else
                        {
                            rc_setError("Cannot return from this scope");
                            return false;
                        }
                    }

                    exit_scope(1);
                    scope_start = current_scope.find_last_of(".");
                }

                if(fnID < 0)
                {
                    rc_setError("Cannot return outside of a FUNCTION or SUB");
                    return false;
                }

                current_scope = tmp_scope;

                //rc_setError("cannot return from outside of a function of sub routine");
                //return false;
            }

            if(id[current_fn_index].type == ID_TYPE_SUB)
            {
                if(token.size() > 1)
                {
                    rc_setError("Cannot return a value from a SUB Routine, You should use a FUNCTION instead");
                    return false;
                }
                current_scope = tmp_scope;
                vm_asm.push_back("return");
                return true;
            }

            if(!eval_expression(1, token.size()-1))
            {
                //rc_setError("Could not evaluate expression");
                return false;
            }
            if(id[current_fn_index].type == ID_TYPE_FN_NUM)
            {
                if(expr_result.substr(0,1).compare("n")!=0)
                {
                    rc_setError("Must return a number");
                    return false;
                }
                vm_asm.push_back("push " + expr_result);
                vm_asm.push_back("return");
            }
            else if(id[current_fn_index].type == ID_TYPE_FN_STR)
            {
                if(expr_result.substr(0,1).compare("s")!=0)
                {
                    rc_setError("Must return a string");
                    return false;
                }
                vm_asm.push_back("push$ " + expr_result);
                vm_asm.push_back("return");
            }
            else if(id[current_fn_index].type == ID_TYPE_FN_USER)
            {
                if(expr_result.substr(0,1).compare("u")!=0)
                {
                    rc_setError("Must return a \"" + utype[id[current_fn_index].type_index].name + "\"");
                    return false;
                }

                int fn_type = -1;
                int u_type_index = -1;
                getRegInfo(expr_result, fn_type, u_type_index);

                if(u_type_index != id[current_fn_index].type_index)
                {
                    rc_setError("+Must return a \"" + utype[id[current_fn_index].type_index].name + "\"");
                    return false;
                }


                vm_asm.push_back("push_t " + expr_result);
                vm_asm.push_back("return");
            }
        }
        else if(token[0].compare("<exit>")==0)
        {
            string tmp_scope = current_scope;
            stack<select_data> tmp_select_stack = select_block;
            string scope_type = "";
            string exit_type = "";

            if(token.size()==1)
            {
                rc_setError("Expected {DO | FOR | WHILE} in EXIT statement");
                return false;
            }

            if(token[1].compare("<do>")==0)
                exit_type = "#DO:";
            else if(token[1].compare("<for>")==0)
                exit_type = "#FOR:";
            else if(token[1].compare("<while>")==0)
                exit_type = "#WHILE:";
            else
            {
                rc_setError("Expected {DO | FOR | WHILE} in EXIT statement");
                return false;
            }

            int scope_start = current_scope.find_last_of(".");
            bool canExit = false;

            while(scope_start > 0)
            {
                scope_type = current_scope.substr(scope_start+1);

                if(rc_substr(scope_type, 0, 5).compare("#FOR:")==0)
                {
                    vm_asm.push_back("pop_loop_stack");
                }
                else if(rc_substr(scope_type, 0, 8).compare("#SELECT:")==0)
                {
                    if(tmp_select_stack.top().case_type == ID_TYPE_STR)
                    {
                        vm_asm.push_back("pop$ s0"); //doesnt matter which reg I use since EXIT does not allow expressions
                    }
                    else
                    {
                        vm_asm.push_back("pop n0");
                    }
                    tmp_select_stack.pop();
                }

                if(scope_type.substr(0,4).compare("#DO:")==0 && exit_type.compare("#DO:")==0)
                {
                    canExit = true;
                    vm_asm.push_back("jmp @" + do_end.top());
                    break;
                }
                else if(scope_type.substr(0,5).compare("#FOR:")==0 && exit_type.compare("#FOR:")==0)
                {
                    canExit = true;
                    vm_asm.push_back("jmp @" + for_end.top());
                    break;
                }
                else if(scope_type.substr(0,7).compare("#WHILE:")==0 && exit_type.compare("#WHILE:")==0)
                {
                    canExit = true;
                    vm_asm.push_back("jmp @" + while_end.top());
                    break;
                }

                exit_scope(1);
                scope_start = current_scope.find_last_of(".");
            }

            if(!canExit)
            {
                rc_setError("Cannot EXIT this scope");
                return false;
            }
            current_scope = tmp_scope;
        }
        else if(token[0].compare("<while>")==0)
        {
            if(token.size()<2)
            {
                rc_setError("Expected expression in WHILE");
                return false;
            }
            current_block_state = BLOCK_STATE_WHILE;
            block_state.push(current_block_state);
            string start_label = current_scope + ".#WHILE:" + rc_intToString(current_while_index);
            string end_label = current_scope + ".#WEND:" + rc_intToString(current_while_index);

            current_scope = start_label;
            while_end.push(end_label);

            current_while_index++;

            vm_asm.push_back("label " + start_label);

            if(!eval_expression(1, token.size()-1))
            {
                //rc_setError("Could not evaluate expression");
                return false;
            }

            if(expr_result.substr(0,1).compare("n")!=0)
            {
                rc_setError("Expected a boolean expression");
                return false;
            }

            vm_asm.push_back("while " + expr_result + " @" + end_label);

        }
        else if(token[0].compare("<continue>")==0)
        {
            string tmp_scope = current_scope;
            stack<select_data> tmp_select_stack = select_block;
            string scope_type = "";

            int scope_start = current_scope.find_last_of(".");
            bool canContinue = false;

            while(scope_start > 0)
            {
                scope_type = current_scope.substr(scope_start+1);

                if(rc_substr(scope_type, 0, 5).compare("#FOR:")==0)
                {
                    canContinue = true;
                    vm_asm.push_back("next @" + current_scope);
                    vm_asm.push_back("jmp @" + for_end.top());
                    break;
                }
                if(scope_type.substr(0,4).compare("#DO:")==0)
                {
                    canContinue = true;
                    vm_asm.push_back("loop @" + current_scope);
                    vm_asm.push_back("jmp @" + do_end.top());
                    break;
                }
                if(scope_type.substr(0,7).compare("#WHILE:")==0)
                {
                    canContinue = true;
                    vm_asm.push_back("jmp @" + current_scope);
                    vm_asm.push_back("jmp @" + while_end.top());
                    break;
                }
                else if(rc_substr(scope_type, 0, 8).compare("#SELECT:")==0)
                {
                    if(tmp_select_stack.top().case_type == ID_TYPE_STR)
                    {
                        vm_asm.push_back("pop$ s0"); //doesnt matter which reg I use since EXIT does not allow expressions
                    }
                    else
                    {
                        vm_asm.push_back("pop n0");
                    }
                    tmp_select_stack.pop();
                }

                exit_scope(1);
                scope_start = current_scope.find_last_of(".");
            }

            if(!canContinue)
            {
                rc_setError("CONTINUE can only be used within a loop");
                return false;
            }
            current_scope = tmp_scope;

        }
        else if(token[0].compare("<wend>")==0)
        {
            if(token.size() > 1)
            {
                rc_setError("Expected end of line in WEND");
                return false;
            }
            if(current_block_state != BLOCK_STATE_WHILE)
            {
                rc_setError("Cannot use WEND outside of WHILE");
                return false;
            }
            vm_asm.push_back("jmp @" + current_scope);
            vm_asm.push_back("label " + while_end.top());
            while_end.pop();

            block_state.pop();
            current_block_state = block_state.top();
            exit_scope(1);
        }
        else if(token[0].compare("<do>")==0)
        {
            if(token.size() > 1)
            {
                rc_setError("Expected end of line in DO");
                return false;
            }
            current_block_state = BLOCK_STATE_DO;
            block_state.push(current_block_state);
            string start_label = current_scope + ".#DO:" + rc_intToString(current_do_index);
            string end_label = current_scope + ".#LOOP:" + rc_intToString(current_do_index);

            current_scope = start_label;
            do_end.push(end_label);

            current_do_index++;

            vm_asm.push_back("label " + start_label);
        }
        else if(token[0].compare("<loop>")==0)
        {
            if(current_block_state != BLOCK_STATE_DO)
            {
                rc_setError("Cannot use LOOP outside of DO");
                return false;
            }
            if(token.size()==1)
            {
                vm_asm.push_back("loop @" + current_scope);
                vm_asm.push_back("label " + do_end.top());
                do_end.pop();

                block_state.pop();
                current_block_state = block_state.top();
                exit_scope(1);

            }
            else if(token[1].compare("<while>")==0)
            {
                if(!eval_expression(2, token.size()-1))
                {
                    //rc_setError("Could not evaluate expression");
                    return false;
                }
                if(expr_result.substr(0,1).compare("n")!=0)
                {
                    rc_setError("Expected boolean expression: " + expr_result);
                    return false;
                }
                vm_asm.push_back("loop_while " + expr_result + " @" + current_scope);
                vm_asm.push_back("label " + do_end.top());
                do_end.pop();

                block_state.pop();
                current_block_state = block_state.top();
                exit_scope(1);
            }
            else if(token[1].compare("<until>")==0)
            {
                if(!eval_expression(2, token.size()-1))
                {
                    //rc_setError("Could not evaluate expression");
                    return false;
                }
                if(expr_result.substr(0,1).compare("n")!=0)
                {
                    rc_setError("Expected boolean expression");
                    return false;
                }
                vm_asm.push_back("loop_until " + expr_result + " @" + current_scope);
                vm_asm.push_back("label " + do_end.top());
                do_end.pop();

                block_state.pop();
                current_block_state = block_state.top();
                exit_scope(1);
            }
            else
            {
                rc_setError("Expected WHILE or UNTIL before expression");
                return false;
            }
        }
        else if(token[0].compare("<for>")==0)
        {
            current_block_state = BLOCK_STATE_FOR;
            block_state.push(BLOCK_STATE_FOR);
            string start_label = current_scope + ".#FOR:" + rc_intToString(current_for_index);
            string end_label = current_scope +".#NEXT:" + rc_intToString(current_for_index);

            current_scope  = start_label;
            for_end.push(end_label);

            current_for_index++;

            for(int i = token.size(); i < 6; i++)
                token.push_back("");

            int counter_id = -1;
            string counter_var = "";
            string start_value = "";
            string end_value = "";
            string step_value = "";

            bool d_type_counter = false;
            int d_type_equal_index = 0;

            if(rc_substr(token[1], 0, 4).compare("<id>")==0)
            {
                counter_var = token[1].substr(4);
                counter_id = getIDInScope_ByIndex(counter_var);
                if(counter_id < 0)
                {
                    if(!isValidIDName(counter_var) || rc_substr(counter_var, counter_var.length()-1,1).compare("$")==0)
                    {
                        rc_setError("Invalid identifier name in FOR");
                        return false;
                    }
                    if(isInFunctionScope)
                    {
                        if(!create_function_variable(counter_var, ID_TYPE_NUM,""))
                        {
                            rc_setError("could not create identifier " + counter_var);
                            return false;
                        }
                    }
                    else if(!create_variable(counter_var, ID_TYPE_NUM))
                    {
                        rc_setError("Could not create identifier " + counter_var);
                        return false;
                    }
                }
                else if(id[counter_id].type == ID_TYPE_USER)
                {
                    //cout << "FOR debug: " << token[1].substr(4) << endl;

                    int end_token = 0;
                    int scope = 0;
                    bool expr_start = false;
                    for(end_token = 0; end_token < token.size(); end_token++)
                    {
                        if(token[end_token].compare("<square>")==0 || token[end_token].compare("<par>")==0)
                            scope++;
                        else if(token[end_token].compare("</square>")==0 || token[end_token].compare("</par>")==0)
                            scope--;

                        if(scope == 0 && token[end_token].compare("<equal>")==0)
                        {
                            d_type_equal_index = end_token;
                            end_token--;
                            expr_start = true;
                            break;
                        }
                    }

                    if(!expr_start)
                    {
                        rc_setError("[0]Could not evaluate defined type member in FOR identifier");
                        return false;
                    }

                    if(!eval_expression(1, end_token))
                    {
                        rc_setError("[1]Could not evaluate defined type member in FOR identifier");
                        return false;
                    }

                    if(multi_arg_count != 1)
                    {
                        rc_setError("[2]Could not evaluate defined type member in FOR identifier");
                        return false;
                    }

                    if(multi_arg[0].substr(0,1).compare("n") != 0)
                    {
                        rc_setError("[3]Could not evaluate defined type member in FOR identifier");
                        return false;
                    }

                    d_type_counter = true;
                }
                else if(id[counter_id].type != ID_TYPE_NUM && id[counter_id].type != ID_TYPE_BYREF_NUM && id[counter_id].type != ID_TYPE_ARR_NUM)
                {
                    rc_setError("Expected number identifier in for");
                    return false;
                }
                else if(id[counter_id].type == ID_TYPE_ARR_NUM && token[2].compare("<square>") != 0)
                {
                    rc_setError("Expected \"[\" in array");
                    return false;
                }

                if(d_type_counter)
                {
                    //DO STUFF HERE
                    create_variable("!FOR_TYPE_COUNTER[" + rc_intToString(current_for_index) + "]", ID_TYPE_NUM,"");
                    counter_id = getIDInScope_ByIndex("!FOR_TYPE_COUNTER[" + rc_intToString(current_for_index) + "]");
                    if(counter_id < 0)
                    {
                        rc_setError("RCBasic Compiler ERROR: Type member in FOR caused internal error");
                        return false;
                    }

                    vm_asm.push_back("ptr !" + rc_intToString(id[counter_id].vec_pos) + " " + multi_arg[0]);
                    for_counter.push(counter_id);
                }
                else
                {
                    counter_id = getIDInScope_ByIndex(counter_var);
                    for_counter.push(counter_id);
                }

            }
            else
            {
                rc_setError("Expected identifier after FOR");
                return false;
            }

            int for_equal_op_offset = 2;
            int for_counter_args = 0;

            if(d_type_counter)
                for_equal_op_offset = d_type_equal_index;

            if(id[counter_id].type == ID_TYPE_ARR_NUM || id[counter_id].type == ID_TYPE_BYREF_NUM)
            {
                if(token[2].compare("<square>") == 0)
                {
                    int f_scope = 1;
                    int token_start = 2;
                    int token_end = 3;
                    multi_arg[0] = "";
                    multi_arg[1] = "";
                    multi_arg[2] = "";
                    multi_arg_count = 0;
                    for(int i = 3; i < token.size(); i++)
                    {
                        if(token[i].compare("<square>")==0)
                            f_scope++;
                        else if(token[i].compare("</square>")==0)
                            f_scope--;
                        if(f_scope == 0)
                        {
                            token_end = i;
                            for_equal_op_offset = i+1;
                            if(token[for_equal_op_offset].compare("<equal>")==0)
                                break;
                            else
                            {
                                rc_setError("Expected \"=\" in FOR");
                                return false;
                            }
                        }
                    }
                    if(!eval_expression(token_start, token_end, true))
                    {
                        rc_setError("Error evaluating counter in FOR");
                        return false;
                    }

                    if(id[counter_id].type == ID_TYPE_ARR_NUM && id[counter_id].num_args != multi_arg_count)
                    {
                        rc_setError("Invalid number of dimensions in FOR counter array");
                        return false;
                    }
                    else if(id[counter_id].type == ID_TYPE_BYREF_NUM && multi_arg_count != 1)
                    {
                        rc_setError("Expected 1 argument in FOR counter ByRef array");
                        return false;
                    }

                    switch(multi_arg_count)
                    {
                        case 1:
                            vm_asm.push_back("for_offset_arr1 " + multi_arg[0]);
                            break;
                        case 2:
                            vm_asm.push_back("for_offset_arr2 " + multi_arg[0] + " " + multi_arg[1]);
                            break;
                        case 3:
                            vm_asm.push_back("for_offset_arr3 " + multi_arg[0] + " " + multi_arg[1] + " " + multi_arg[2]);
                            break;
                    }

                    for(int i = token_start; i <= token_end; i++)
                    {
                        //cout << "remove token: " << token[i] << endl;
                        token[i] = "";
                    }

                }
                else
                    vm_asm.push_back("for_offset_0");
            }

            if(token[for_equal_op_offset].compare("<equal>")!=0)
            {
                rc_setError("Expected = in FOR");
                return false;
            }
            int ft_count = 0;
            string ftokens[] = {"", ""};
            for(int i = for_equal_op_offset+1; i < token.size(); i++)
            {
                if(token[i].compare("<to>")==0 || token[i].compare("<step>")==0)
                {
                    if(ft_count >= 2)
                    {
                        rc_setError("Illegal Syntax in FOR");
                        return false;
                    }
                    ftokens[ft_count] = token[i];
                    ft_count++;
                    token[i] = "!<comma>";
                }
            }
            if(ftokens[0].compare("<to>")!=0)
            {
                rc_setError("Expected to after initialize expression");
                return false;
            }
            if(ftokens[1].compare("<step>")!=0 && ftokens[1].compare("") != 0)
            {
                rc_setError("Expected STEP or end of FOR line");
                return false;
            }

            if(!eval_expression(for_equal_op_offset+1, token.size()-1, true))
            {
                //rc_setError("Could not evaluate expression");
                return false;
            }

            start_value = multi_arg[0];
            end_value = multi_arg[1];

            if(multi_arg_count == 2)
            {
                step_value = "n" + rc_intToString(n_reg);
                vm_asm.push_back("mov " + step_value + " 1");
            }
            else if(multi_arg_count == 3)
            {
                step_value = multi_arg[2];
            }
            else
            {
                rc_setError("To many arguments in FOR");
                return false;
            }

            if(start_value.substr(0,1).compare("n")!=0 || end_value.substr(0,1).compare("n")!=0 || step_value.substr(0,1).compare("n")!=0)
            {
                rc_setError("Expected number expression in FOR");
                return false;
            }

            //cout << "FOR_RESULT" << endl << "------------------" << endl;
            //cout << "identifier = " << id[counter_id].vec_pos << endl;
            //cout << "start = " << start_value << endl;
            //cout << "end = " << end_value << endl;
            //cout << "step = " << step_value << endl << endl;

            if(for_counter.size() > max_for_count)
                max_for_count = for_counter.size();

            vm_asm.push_back("for !" + rc_intToString(id[counter_id].vec_pos) + " " + start_value + " " + end_value + " " + step_value);
            vm_asm.push_back("lval @" + end_label);
            vm_asm.push_back("label " + start_label);


        }
        else if(token[0].compare("<next>")==0)
        {
            if(current_block_state != BLOCK_STATE_FOR)
            {
                rc_setError("Cannot use NEXT outside of a FOR loop");
                return false;
            }
            if(token.size() > 1)
            {
                rc_setError("Expected end of line in NEXT");
                return false;
            }
            uint64_t counter_id = for_counter.top();
            for_counter.pop();
            string next_label = for_end.top();
            for_end.pop();
            block_state.pop();
            current_block_state = block_state.top();
            vm_asm.push_back("next @" + current_scope);
            vm_asm.push_back("label " + next_label);
            //cout << "next_addr = " << vm_asm.current_address[CODE_SEGMENT] << endl;
            exit_scope(1);
        }
        else if(token[0].compare("<if>")==0)
        {
            current_block_state = BLOCK_STATE_IF;
            block_state.push(current_block_state);

            if_data if_start;

            if_start.index = current_if_index;
            if_start.condition = 0;

            if_block.push(if_start);

            string start_label = current_scope + ".#IF:" + rc_intToString(if_start.index);

            current_scope = start_label;

            int if_then = -1;

            for(int i = 0; i < token.size(); i++)
            {
                if(token[i].compare("<then>")==0)
                {
                    if_then = i;
                    break;
                }
            }


            if(if_then < 0)
            {
                rc_setError("Expected THEN in IF statement");
                return false;
            }

            if(token.size() > (if_then+1))
            {
                rc_setError("Expected End of Line after THEN");
                return false;
            }

            if(if_then < 2)
            {
                rc_setError("Expected expression in IF");
                return false;
            }

            if(!eval_expression(1, if_then-1))
            {
                //rc_setError("Could not evaluate expression");
                return false;
            }

            if(expr_result.substr(0,1).compare("n")!=0)
            {
                rc_setError("Expected Boolean expression");
                return false;
            }

            string else_label = "ELSE:" + rc_intToString(if_block.top().index) + "->CONDITION:" + rc_intToString(if_block.top().condition);

            vm_asm.push_back("cmp " + expr_result + " 0");
            vm_asm.push_back("je @" + else_label);
            //vm_asm.push_back("");
            current_if_index++;

        }
        else if(token[0].compare("<elseif>")==0)
        {
            if(if_block.top().else_set)
            {
                rc_setError("Cannot use ELSEIF after ELSE in the same IF Block");
                return false;
            }
            string start_label = "ELSE:" + rc_intToString(if_block.top().index) + "->CONDITION:" + rc_intToString(if_block.top().condition);
            vm_asm.push_back("jmp @ENDIF:" + rc_intToString(if_block.top().index) );
            vm_asm.push_back("label " + start_label);
            if_block.top().condition++;

            exit_scope(1);

            current_scope += ".#" + start_label;

            int if_then = -1;

            for(int i = 0; i < token.size(); i++)
            {
                if(token[i].compare("<then>")==0)
                {
                    if_then = i;
                    break;
                }
            }


            if(if_then < 0)
            {
                rc_setError("Expected THEN in IF statement");
                return false;
            }

            if(token.size() > (if_then+1))
            {
                rc_setError("Expected End of Line after THEN");
                return false;
            }

            if(if_then < 2)
            {
                rc_setError("Expected expression in IF");
                return false;
            }

            if(!eval_expression(1, if_then-1))
            {
                rc_setError("Could not evaluate expression");
                return false;
            }

            if(expr_result.substr(0,1).compare("n")!=0)
            {
                rc_setError("Expected Boolean expression");
                return false;
            }

            string else_label = "ELSE:" + rc_intToString(if_block.top().index) + "->CONDITION:" + rc_intToString(if_block.top().condition);

            vm_asm.push_back("cmp " + expr_result + " 0");
            vm_asm.push_back("je @" + else_label);
            //vm_asm.push_back("");
        }
        else if(token[0].compare("<else>")==0)
        {
            if(token.size()>1)
            {
                rc_setError("Expected end of line in ELSE");
                return false;
            }

            string start_label = "ELSE:" + rc_intToString(if_block.top().index) + "->CONDITION:" + rc_intToString(if_block.top().condition);
            vm_asm.push_back("jmp @ENDIF:" + rc_intToString(if_block.top().index) );
            vm_asm.push_back("label " + start_label);
            //vm_asm.push_back("");
            if_block.top().else_set = true;
            if_block.top().condition++;

            exit_scope(1);

            current_scope += ".#" + start_label;

        }
        else if(token[0].compare("<select>")==0)
        {
            if(token.size() < 3)
            {
                rc_setError("Incomplete SELECT CASE statement");
                return false;
            }
            if(token[1].compare("<case>")!=0)
            {
                rc_setError("Expected CASE in SELECT CASE statement");
                return false;
            }
            if(!eval_expression(2, token.size()-1))
            {
                //rc_setError("Could not evaluate expression");
                return false;
            }
            select_data select_start;
            select_start.index = current_select_index;
            select_start.case_index = 0;
            select_start.default_set = false;
            if(expr_result.substr(0,1).compare("s")==0)
            {
                select_start.case_type = ID_TYPE_STR;
                vm_asm.push_back("push$ " + expr_result);
            }
            else
            {
                select_start.case_type = ID_TYPE_NUM;
                vm_asm.push_back("push " + expr_result);
            }

            select_block.push(select_start);
            string select_label = "SELECT:" + rc_intToString(select_block.top().index) + "->CASE:" + rc_intToString(select_block.top().case_index);

            vm_asm.push_back("jmp @" + select_label);

            current_select_index++;
            current_scope += ".#" + select_label;
            current_block_state = BLOCK_STATE_SELECT;
            block_state.push(current_block_state);

            //vm_asm.push_back("");

        }
        else if(token[0].compare("<case>")==0)
        {
            if(token.size()==1)
            {
                rc_setError("Expected expression in CASE");
                return false;
            }
            if(current_block_state != BLOCK_STATE_SELECT)
            {
                rc_setError("Cannot set CASE outside of a SELECT BLOCK");
                return false;
            }


            select_block.top().case_set = true;

            string compare_case = "";

            string case_end = "SELECT:" + rc_intToString(select_block.top().index) + "->END";
            string case_label = "SELECT:" + rc_intToString(select_block.top().index) + "->CASE:" + rc_intToString(select_block.top().case_index);
            exit_scope(1);
            current_scope += ".#" + case_label;

            select_block.top().case_index++;
            string next_case_label = "SELECT:" + rc_intToString(select_block.top().index) + "->CASE:" + rc_intToString(select_block.top().case_index);

            vm_asm.push_back("jmp @" + case_end);
            vm_asm.push_back("label " + case_label);

            if(select_block.top().case_type==ID_TYPE_STR)
            {
                compare_case = "s" + rc_intToString(s_reg);
                vm_asm.push_back("pop$ " + compare_case);
                vm_asm.push_back("push$ " + compare_case);
                inc_s(1);
            }
            else
            {
                compare_case = "n" + rc_intToString(n_reg);
                vm_asm.push_back("pop " + compare_case);
                vm_asm.push_back("push " + compare_case);
                inc_n(1);
            }
            for(int i = 0; i < token.size(); i++)
            {
                if(token[i].compare("<comma>")==0)
                    token[i] = "!<comma>";
            }
            if(!eval_expression(1, token.size()-1, true))
            {
                //rc_setError("Could not evaluate expression");
                return false;
            }
            string case_reg_type = "n";
            if(select_block.top().case_type == ID_TYPE_STR)
                case_reg_type = "s";

            string cmp_or_result = "n" + rc_intToString(n_reg);
            inc_n(1);

            string case_flag_result = "n" + rc_intToString(n_reg);
            inc_n(1);

            vm_asm.push_back("mov " + cmp_or_result + " 0");

            for(int i = 0; i < multi_arg_count; i++)
            {
                if(multi_arg[i].substr(0,1).compare(case_reg_type)!=0)
                {
                    rc_setError("Mismatch type in CASE: " + multi_arg[i]);
                    return false;
                }
                if(case_reg_type.compare("s")==0)
                {
                    vm_asm.push_back("cmp$ " + compare_case + " " + multi_arg[i]);
                    vm_asm.push_back("mov " + case_flag_result + " %EQUAL_FLAG");
                    vm_asm.push_back("or " + cmp_or_result + " " + case_flag_result);
                }
                else
                {
                    vm_asm.push_back("cmp " + compare_case + " " + multi_arg[i]);
                    vm_asm.push_back("mov " + case_flag_result + " %EQUAL_FLAG");
                    vm_asm.push_back("or " + cmp_or_result + " " + case_flag_result);
                }
            }
            vm_asm.push_back("cmp " + cmp_or_result + " 0");
            vm_asm.push_back("je @" + next_case_label);
            //vm_asm.push_back("");
        }
        else if(token[0].compare("<default>")==0)
        {
            if(token.size()>1)
            {
                rc_setError("Expected End of Line for default");
                return false;
            }
            if(current_block_state != BLOCK_STATE_SELECT)
            {
                rc_setError("Cannot set DEFAULT outside of a SELECT BLOCK");
                return false;
            }


            select_block.top().case_set = true;

            string compare_case = "";

            string case_end = "SELECT:" + rc_intToString(select_block.top().index) + "->END";
            string case_label = "SELECT:" + rc_intToString(select_block.top().index) + "->CASE:" + rc_intToString(select_block.top().case_index);
            exit_scope(1);
            current_scope += ".#" + case_label;

            select_block.top().case_index++;
            string next_case_label = "SELECT:" + rc_intToString(select_block.top().index) + "->CASE:" + rc_intToString(select_block.top().case_index);

            vm_asm.push_back("jmp @" + case_end);
            vm_asm.push_back("label " + case_label);

            //vm_asm.push_back("");
        }
        else if(token[0].compare("<print>")==0)
        {
            string last_token = token[token.size()-1];
            if(token.size()==1)
            {
                rc_setError("Expected expression for PRINT");
                return false;
            }
            int start_token = 1;
            if(token[token.size()-1].compare("<semi>")!=0)
                token.push_back("<semi>");
            for(int i = 0; i < token.size(); i++)
            {
                if(token[i].compare("<semi>")==0)
                {
                    token[i] = "";
                    if(!eval_expression(start_token, i))
                    {
                        //rc_setError("Could not evaluate expression");
                        //output_tokens();
                        cout << endl << endl;
                        return false;
                    }
                    if(expr_result.substr(0,1).compare("n")==0)
                        vm_asm.push_back("print " + expr_result);
                    else if(expr_result.substr(0,1).compare("s")==0)
                        vm_asm.push_back("print$ " + expr_result);
                    else
                    {
                        rc_setError("Invalid expression in PRINT");
                        return false;
                    }
                    start_token = i;
                }
            }
            if(start_token < (token.size()-1 ) )
            {
                if(!eval_expression(start_token, token.size()-1))
                {
                    //rc_setError("Could not evaluate expression");
                    return false;
                }
                if(expr_result.substr(0,1).compare("n")==0)
                    vm_asm.push_back("print " + expr_result);
                else if(expr_result.substr(0,1).compare("s")==0)
                    vm_asm.push_back("print$ " + expr_result);
                else
                {
                    rc_setError("Invalid expression in PRINT");
                    return false;
                }
            }
            if(last_token.compare("<semi>")!=0)
                vm_asm.push_back("println");
        }
        else if(token[0].compare("<delete>")==0)
        {
            if(token.size() < 2)
            {
                rc_setError("Expected single identifier in DELETE statement");
                return false;
            }
            if(token[1].substr(0,4).compare("<id>")!=0)
            {
                rc_setError("Expected single identifier in DELETE statement");
                return false;
            }
            int id_index = getIDInScope_ByIndex(token[1].substr(4));
            if(id_index < 0)
            {
                rc_setError("Identifier does not exists in current scope: " + token[1].substr(4) + ", SCOPE=" + current_scope);
                return false;
            }
            if(id[id_index].type == ID_TYPE_ARR_NUM || id[id_index].type == ID_TYPE_NUM)
            {
                if(token.size() != 2)
                {
                    rc_setError("Expected single identifier in DELETE statement");
                    return false;
                }

                vm_asm.push_back("delete !" + rc_intToString(id[id_index].vec_pos));
            }
            else if(id[id_index].type == ID_TYPE_ARR_STR || id[id_index].type == ID_TYPE_STR)
            {
                if(token.size() != 2)
                {
                    rc_setError("Expected single identifier in DELETE statement");
                    return false;
                }

                vm_asm.push_back("delete$ !" + rc_intToString(id[id_index].vec_pos));
            }
            else if(id[id_index].type == ID_TYPE_USER)
            {
                token[0] = "";

                type_delete_flag = true;
                type_delete_arg = "";
                type_delete_arg_whole = true;

                if(!eval_expression())
                {
                    rc_setError("Could not evaluate identifer");
                    return false;
                }
                if(type_delete_arg.substr(0,1).compare("!")!=0)
                {
                    rc_setError("Could not determine Identifier Type in DELETE: " + type_delete_arg);
                    return false;
                }

                string d_type = "!";
                string top_level_flag = "!0";

                if(!type_delete_arg_whole)
                    top_level_flag = "!1";

                if(type_delete_arg_type == ID_TYPE_USER_STR || type_delete_arg_type == ID_TYPE_USER_STR_ARRAY)
                {
                    cout << "DELETE STRING" << endl;
                    d_type += "1";
                }
                else if(type_delete_arg_type == ID_TYPE_USER_NUM || type_delete_arg_type == ID_TYPE_USER_NUM_ARRAY)
                {
                    cout << "DELETE NUMBER" << endl;
                    d_type += "0";
                }
                else if(type_delete_arg_type == ID_TYPE_USER)
                {
                    cout << "DELETE USER TYPE" << endl;
                    d_type += "2";
                }
                else
                {
                    rc_setError("Cannot delete identifier of this type or within this scope");
                    return false;
                }

                vm_asm.push_back("delete_t " + type_delete_arg + " " + top_level_flag + " " + d_type);

                type_delete_flag = false;
                type_delete_arg_whole = true;
            }
            else
            {
                rc_setError("Cannot delete identifier of this type");
                return false;
            }
            //id[id_index].name = "";
        }
        else if(token[0].compare("<type>")==0)
        {
            if(current_scope.compare("main")!=0)
            {
                rc_setError("TYPE cannot be defined in this scope");
                return false;
            }
            if(token.size() != 2)
            {
                rc_setError("Expected TYPE Identifier in TYPE statement");
                return false;
            }
            if(token[1].substr(0,4).compare("<id>")!=0)
            {
                rc_setError("Expected TYPE Identifier in TYPE statement");
                return false;
            }
            int id_index = getIDInScope_ByIndex(token[1].substr(4));
            if(id_index >= 0)
            {
                rc_setError("TYPE Identifier exists in current scope");
                return false;
            }
            create_type(token[1].substr(4));
            current_block_state = BLOCK_STATE_TYPE;
            block_state.push(current_block_state);

            string start_label = current_scope + ".#TYPE:" + token[1].substr(4);

            current_scope  = start_label;
        }
        else if(token.size() > 2)
        {
            //cout << "token[1] = " << token[1] << endl;
            if(token[0].substr(0,4).compare("<id>")==0)
            {
                int id_index = getIDInScope_ByIndex(token[0].substr(4));
                if(id_index >= 0)
                {
                    //cout << "DBG TYPE: name = " << id[id_index].name << " -- type = " << id[id_index].type << " -- scope = " << id[id_index].scope << endl;

                    if( ID_TYPE_USER_ALL(id_index) )
                    {
                        //NOTE: PARSING TYPE VAR HERE

                        string full_id = "";
                        int tmp_scope = 0;
                        int end_token = -1;
                        int op_token = -1;

                        //getting the id to parse
                        for(int i = 0; i < token.size(); i++)
                        {
                            //cout << "DEBUG TOKEN[" << i << "] = " << token[i] << endl;

                            if(token[i].compare("<square>")==0 || token[i].compare("!<square>")==0 ||
                               token[i].compare("<par>")==0 || token[i].compare("!<par>")==0)
                                tmp_scope++;
                            else if(token[i].compare("</square>")==0 || token[i].compare("!</square>")==0 ||
                                    token[i].compare("</par>")==0 || token[i].compare("!</par>")==0)
                                tmp_scope--;
                            else if(tmp_scope == 0 && isOperatorToken2(i))
                            {
                                //cout << "PARSE ID = \n" << full_id << endl;
                                op_token = i;
                                end_token = i-1;
                                break;
                            }

                        }

                        if(end_token < 0)
                        {
                            end_token = 0;
                        }

                        string op = "";

                        if(op_token >= 0)
                        {
                            op = token[op_token];
                            token[op_token] = "";

                            if(end_token==0)
                                end_token++;
                        }

                        if(!eval_expression(0, end_token))
                        {
                            rc_setError("[1] Could not evaluate Identifier: " + rc_intToString(end_token));
                            return false;
                        }

                        if(op_token >= 0)
                            token[op_token] = op;

                        bool set_val = false;
                        string id_arg = "";

                        if(op_token >= 0)
                        if(token[op_token].compare("<equal>")==0)
                        {
                            //cout << "BALLS" << endl;
                            set_val = true;
                            id_arg = token[0];
                            for(int i = 0; i <= op_token; i++)
                                token[i] = "";

                            //for(int i = op_token+1; i < token.size(); i++)
                            //    cout << "SUPER T[" << i << "] = " << token[i] << endl;
                        }

                        if(!eval_expression())
                        {
                            rc_setError("Could not evaluate expression");
                            return false;
                        }

                        //cout << endl << "NEW SET" << endl;
                        //cout << "-----------------------" << endl;
                        //for(int i = 0; i < token.size(); i++)
                        //    cout << i << ":" << token[i] << endl;
                        //cout << endl;



                        //I will do something with this eventually
                        int var_type = -1;
                        //cout << "Set Val = " << set_val << endl;
                        if(set_val)
                        {
                            if(expr_result.substr(0,1).compare(id_arg.substr(0,1))!=0)
                            {
                                rc_setError("[0]Expression type does not match identifier");
                                return false;
                            }

                            int ut_info = 0;
                            int ut1 = -1;
                            int ut2 = -1;

                            var_type = id_arg.substr(0,1).compare("n")==0 ? ID_TYPE_NUM : -1;
                            var_type = (var_type < 0) ? (id_arg.substr(0,1).compare("s")==0 ? ID_TYPE_STR : -1) : var_type;
                            var_type = (var_type < 0) ? (id_arg.substr(0,1).compare("u")==0 ? ID_TYPE_USER : -1) : var_type;
                            switch(var_type)
                            {
                                case ID_TYPE_NUM:
                                    vm_asm.push_back("mov_r " + id_arg + " " + expr_result);
                                    break;
                                case ID_TYPE_STR:
                                    vm_asm.push_back("mov_r$ " + id_arg + " " + expr_result);
                                    break;
                                case ID_TYPE_USER:
                                    getRegInfo(id_arg, ut_info, ut1);
                                    getRegInfo(expr_result, ut_info, ut2);
                                    if(ut1 != ut2)
                                    {
                                        rc_setError("[1]Expression type does not match identifier in assignment");
                                        return false;
                                    }
                                    vm_asm.push_back("mov_type " + id_arg + " " + expr_result);
                                    break;
                                default:
                                    //cout << "VAR_TYPE = " << var_type << endl;
                                    break;
                            }

                            return true;
                        }
                    }
                }
            }

            if(token[1].compare("<equal>")==0)
            {
                string var_id = "";
                int var_type = ID_TYPE_NUM;
                int var_ut_index = -1;
                int var_id_index = -1;

                if(rc_substr(token[0], 0, 1).compare("n")==0 || rc_substr(token[0], 0, 1).compare("s")==0)
                {
                    for(int i = 0; i < resolveID_id_reg.size(); i++)
                    {
                        if(resolveID_id_reg[i].compare(token[0])==0)
                        {
                            var_id = "~" + token[0];
                            if(token[0].substr(0,1).compare("s")==0)
                                var_type = ID_TYPE_STR;
                            else if(resolveID_id_type[i] == ID_TYPE_USER)
                            {
                                var_type = ID_TYPE_USER;
                                var_ut_index = resolveID_id_ut_index[i];
                            }
                            else
                                var_type = resolveID_id_type[i];
                            break;
                        }
                    }
                    if(var_id.compare("")==0)
                    {
                        rc_setError("Expected identifier for variable assignment");
                        return false;
                    }
                }
                else if(rc_substr(token[0], 0, 4).compare("<id>")==0)
                {
                    var_id = token[0].substr(4);
                    var_type = (var_id.substr(var_id.length()-1).compare("$")==0) ? ID_TYPE_STR : ID_TYPE_NUM; //length() will always be atleast 1 so there is no need to check

//                    if(var_id.substr(var_id.length()-1,1).compare("$")==0)
//                    {
//                        //cout << "looking for: " << var_id.substr(0, var_id.length()-1) << endl;
//                        var_id_index = getIDInScope(var_id.substr(0, var_id.length()-1));
//                        if(var_id_index >= 0)
//                            var_type = id[var_id_index].type;
//                        //cout << "var_index = " << var_id_index << endl;
//                    }
                    if(var_id_index < 0)
                    {
                        var_id_index = getIDInScope_ByIndex(var_id);
                        if(var_id_index >= 0)
                            var_type = id[var_id_index].type;
                    }

                    if(var_id_index < 0)
                    {
                        if(!isValidIDName(var_id))
                        {
                            rc_setError(var_id + " is not a valid identifier");
                            return false;
                        }
                        if(isInFunctionScope)
                        {
                            if(!create_function_variable(var_id, var_type, ""))
                            {
                                rc_setError("Could not create " + var_id);
                                return false;
                            }
                        }
                        else if(!create_variable(var_id, var_type))
                        {
                            rc_setError("Could not create " + var_id);
                            return false;
                        }

                        var_id_index = getIDInScope_ByIndex(var_id);

                        if(var_id_index < 0)
                        {
                            rc_setError("Unexpected error");
                            return false;
                        }
                    }
                }

                if(var_type == ID_TYPE_BYREF_NUM)
                    var_type = ID_TYPE_NUM;
                else if(var_type == ID_TYPE_BYREF_STR)
                    var_type = ID_TYPE_STR;

                if(var_type != ID_TYPE_NUM && var_type != ID_TYPE_STR)
                {
                    bool id_type_match = false;
                    if(token.size()!=3)
                    {
                        rc_setError("Expected identifier of same type in assignment");
                        return false;
                    }

                    for(int i = 0; i < resolveID_id_reg.size(); i++)
                    {
                        if(resolveID_id_reg[i].compare(token[2])==0)
                        {
                            if(resolveID_id_type[i] == var_type)
                            {
                                if(var_type == ID_TYPE_USER && var_ut_index == resolveID_id_ut_index[i])
                                {
                                    id_type_match = true;
                                }
                                else if(var_type == ID_TYPE_ARR_NUM || var_type == ID_TYPE_ARR_STR)
                                {
                                    id_type_match = true;
                                }
                            }
                        }
                    }

                    if(!id_type_match)
                    {
                        rc_setError("Expected identifier of same type in assignment");
                        return false;
                    }

                    vm_asm.push_back("mov_type " + var_id.substr(1) + " " + token[2]);

                    return true;
                }

                if(!eval_expression(2))
                {
                    //rc_setError("Could not evaluate expression");
                    return false;
                }

                if(var_type == ID_TYPE_NUM && expr_result.substr(0,1).compare("n")!=0 )
                {
                    rc_setError("Must set number variable to number expression");
                    return false;
                }
                else if(var_type == ID_TYPE_STR && expr_result.substr(0,1).compare("s")!=0 )
                {
                    rc_setError("Must set string variable to string expression");
                    return false;
                }

                if(var_id.substr(0,1).compare("~")==0)
                {
                    switch(var_type)
                    {
                        case ID_TYPE_NUM:
                            vm_asm.push_back("mov_r " + var_id.substr(1) + " " + expr_result);
                            break;
                        case ID_TYPE_STR:
                            vm_asm.push_back("mov_r$ " + var_id.substr(1) + " " +expr_result);
                            break;
                        default:
                            //cout << "VAR_TYPE = " << var_type << endl;
                            break;
                    }
                }
                else
                {
                    switch(var_type)
                    {
                        case ID_TYPE_NUM:
                            vm_asm.push_back("mov !" + rc_intToString(id[var_id_index].vec_pos) + " " + expr_result);
                            break;
                        case ID_TYPE_STR:
                            vm_asm.push_back("mov$ !" + rc_intToString(id[var_id_index].vec_pos) + " " + expr_result);
                            break;
                    }
                }

            }
            else if(rc_substr(token[0], 0, 4).compare("<id>")==0 && token.size() > 5)
            {
                //cout << "dbg 1" << endl;
                int expr_id = getIDInScope_ByIndex(token[0].substr(4));

                if(expr_id < 0)
                {
                    rc_setError("Identifier \"" + token[0].substr(4) + "\" was not declared in this scope");
                    return false;
                }

                int start_token = 0;
                int end_token = 0;

                int s_scope = 1;

                if(token[1].compare("<square>")==0)
                {
                    for(int i = 2; i < token.size(); i++)
                    {
                        if(token[i].compare("</square>")==0)
                            s_scope--;
                        else if(token[i].compare("<square>")==0)
                            s_scope++;
                        if(s_scope == 0)
                        {
                            end_token = i;

                            //for(int i2 = start_token; i2 <= end_token; i2++)
                            //    cout << "token: " << i2 << token[i2] << endl;

                            break;
                        }
                    }
                    if(s_scope != 0)
                    {
                        rc_setError("Expected ] in array assignment");
                        return false;
                    }
                }
                else
                {
                    //cout << "dbg 2" << endl;
                    if(!eval_expression())
                    {
                        rc_setError("Could not evaluate expression");
                        return false;
                    }
                }

                if(!eval_expression(start_token, end_token))
                {
                    rc_setError("Could not resolve array identifier");
                    return false;
                }

                string var = expr_result;
                end_token++;
                bool isAssignment = false;

                if(token.size()>end_token)
                {
                    if(token[end_token].compare("<equal>")==0)
                    {
                        isAssignment = true;
                        start_token = end_token+1;
                    }
                }


                string var_result = "";
                if(isAssignment)
                {
                    if(!eval_expression(start_token, token.size()-1))
                    {
                        //rc_setError("Could not evaluate expression");
                        return false;
                    }

                    if(var.substr(0,1).compare("n")==0 && expr_result.substr(0,1).compare("n")==0)
                    {
                        vm_asm.push_back("mov_r " + var + " " + expr_result);
                        return true;
                    }
                    else if(var.substr(0,1).compare("s")==0 && expr_result.substr(0,1).compare("s")==0)
                    {
                        vm_asm.push_back("mov_r$ " + var + " " + expr_result);
                        return true;
                    }
                    else
                    {
                        rc_setError("Identifier type does not match assignment type");
                        return false;
                    }

                }
                else
                {
                    if(!eval_expression(start_token, token.size()-1))
                    {
                        //rc_setError("Could not evaluate expression");
                        return false;
                    }
                }

            }
            else
            {
                //cout << "debug problem here" << endl;
                //output_tokens();
                if(!eval_expression())
                {
                    //rc_setError("Could not evaluate expression");
                    return false;
                }
            }
        }
        else
        {
            if(!eval_expression(0, token.size()-1))
            {
                //rc_setError("Could not evaluate expression");
                return false;
            }
            //cout <<"THIS IS A TEST" << endl;
        }
    }
    return true;
}

bool check_rule_embedded()
{
    if(token.size() > 0)
    {
        if(current_block_state == BLOCK_STATE_TYPE)
        {
            if(token[0].compare("<dim>")!=0 && token[0].compare("<end>")!=0)
            {
                rc_setError("Expected DIM in TYPE definition");
                return false;
            }
        }
        else if(current_block_state != BLOCK_STATE_MAIN)
        {
            if(token[0].compare("<type>")==0)
            {
                rc_setError("TYPE cannot be declared in the current scope");
                return false;
            }
            else if(token[0].compare("<function>")==0)
            {
                rc_setError("FUNCTION cannot be declared in the current scope");
                return false;
            }
            else if(token[0].compare("<subp>")==0)
            {
                rc_setError("SUB ROUTINE cannot be declared in the current scope");
                return false;
            }
        }

        if(token[0].compare("<function>")==0)
        {
            if(token.size()<2)
            {
                rc_setError("Expected identifier for function declaration");
                return false;
            }

            string fn_name = rc_substr(token[1], 4, token[1].length());
            if(!isValidIDName(fn_name) )
            {
                rc_setError(fn_name + " is not a valid identifier name");
                return false;
            }
            if(idExistsInScope(fn_name))
            {
                rc_setError("Identifier " + fn_name + " already exists in this scope");
                return false;
            }

            int fn_type = ID_TYPE_FN_NUM;
            if(fn_name.substr(fn_name.length()-1,1).compare("$")==0)
                fn_type = ID_TYPE_FN_STR;

            string fn_type_name = "";
            if(token.size()>2)
            {
                if(token[token.size()-2].compare("<as>")==0)
                {
                    fn_type = ID_TYPE_FN_USER;
                    if(token[token.size()-1].substr(0,4).compare("<id>")==0)
                        fn_type_name = token[token.size()-1].substr(4);
                    else
                    {
                        rc_setError("Invalid return type in FUNCTION definition");
                        return false;
                    }
                    token.pop_back();
                    token.pop_back();
                }
            }

            if(!embed_function(fn_name, fn_type, getUType(fn_type_name)))
            {
                rc_setError("Could not create FUNCTION \"" + fn_name + "\" of type \"" + fn_type_name + "\"");
                return false;
            }
            current_block_state = BLOCK_STATE_FUNCTION;
            block_state.push(current_block_state);

            string fn_arg = "";
            int fn_arg_type = ID_TYPE_NUM;
            string fn_arg_user_type = "";
            bool fn_byref = false;

            int end_token = 0;

            for(int i = 3; i < token.size(); i++)
            {
                if(token[i].compare("<byref>")==0)
                {
                    fn_byref = true;
                }
                else if(rc_substr(token[i], 0, 4).compare("<id>")==0)
                {
                    fn_arg += token[i];
                    if(fn_arg.substr(fn_arg.length()-1,1).compare("$")==0)
                        fn_arg_type = ID_TYPE_STR;
                    else
                        fn_arg_type = ID_TYPE_NUM;
                }
                else if(token[i].compare("<as>")==0)
                {
                    i++;
                    fn_arg_type = ID_TYPE_USER;
                    fn_arg_user_type = "";
                    int arg_type_index = -1;
                    if(i < token.size())
                        if(token[i].substr(0,4).compare("<id>")==0)
                            fn_arg_user_type = token[i].substr(4);

                    if(fn_arg_user_type.compare("")==0)
                    {
                        rc_setError("Invalid Type in FUNCTION Definition");
                        return false;
                    }

                }
                else if(token[i].compare("<comma>")==0)
                {
                    //cout << "ADD ARG: " << fn_arg << endl;
                    fn_arg = rc_substr(fn_arg, 4, fn_arg.length()-1);
                    if(!isValidIDName(fn_arg))
                    {
                        rc_setError("FUNCTION argument is not a valid identifier name");
                        return false;
                    }
                    if(idExistsInScope(fn_arg))
                    {
                        rc_setError("FUNCTION argument identifier already exists in current scope");
                        return false;
                    }

                    //cout << "CHECK 1" << endl;

                    if(fn_byref)
                    {
                        if(fn_arg_type == ID_TYPE_NUM)
                            fn_arg_type = ID_TYPE_BYREF_NUM;
                        else if(fn_arg_type == ID_TYPE_STR)
                            fn_arg_type = ID_TYPE_BYREF_STR;
                        else
                            fn_arg_type = ID_TYPE_BYREF_USER;
                    }

                    if(!add_embedded_arg(fn_arg, fn_arg_type, getUType(fn_arg_user_type)))
                    {
                        return false;
                    }
                    fn_arg = "";
                    fn_byref = false;

                    //cout << "DONE" << endl;
                }
                else if(token[i].compare("</par>")==0)
                {
                    if((i+1) < token.size())
                    {
                        rc_setError("Expected End of FUNCTION Declaration");
                        return false;
                    }
                    if(fn_arg.compare("")==0)
                    {
                        end_token = i+1;
                        break;
                    }
                    fn_arg = rc_substr(fn_arg, 4, fn_arg.length()-1);
                    if(!isValidIDName(fn_arg))
                    {
                        rc_setError("FUNCTION argument is not a valid identifier name");
                        return false;
                    }
                    if(idExistsInScope(fn_arg))
                    {
                        rc_setError("FUNCTION argument identifier already exists in current scope");
                        return false;
                    }

                    if(fn_byref)
                    {
                        if(fn_arg_type == ID_TYPE_NUM)
                            fn_arg_type = ID_TYPE_BYREF_NUM;
                        else if(fn_arg_type == ID_TYPE_STR)
                            fn_arg_type = ID_TYPE_BYREF_STR;
                        else
                            fn_arg_type = ID_TYPE_BYREF_USER;
                    }

                    if(!add_embedded_arg(fn_arg, fn_arg_type, getUType(fn_arg_user_type)))
                    {
                        return false;
                    }

                    fn_arg = "";
                    fn_byref = false;
                    end_token = i+1;
                    break;
                }
                else
                {
                    rc_setError("Argument to FUNCTION must be a valid identifier: " + token[i]);
                }
            }

            current_block_state = BLOCK_STATE_MAIN;
            current_scope = "main";
            block_state.pop();
            isInFunctionScope = false;
            current_fn_index++;

            if(token.size()>end_token)
            {
                rc_setError("Expected end of function declaration");
                return false;
            }

        }
        else if(token[0].compare("<subp>")==0)
        {
            if(token.size()<2)
            {
                rc_setError("Expected identifier for function declaration");
                return false;
            }

            string fn_name = rc_substr(token[1], 4, token[1].length());
            if(!isValidIDName(fn_name) )
            {
                rc_setError(fn_name + " is not a valid identifier name");
                return false;
            }
            if(idExistsInScope(fn_name))
            {
                rc_setError("Identifier " + fn_name + " already exists in this scope");
                return false;
            }

            int fn_type = ID_TYPE_SUB;

            string fn_type_name = "";

            if(!embed_function(fn_name, fn_type, getUType(fn_type_name)))
            {
                rc_setError("Could not create SUB ROUTINE \"" + fn_name + "\"");
                return false;
            }
            current_block_state = BLOCK_STATE_SUB;
            block_state.push(current_block_state);

            string fn_arg = "";
            int fn_arg_type = ID_TYPE_NUM;
            string fn_arg_user_type = "";
            bool fn_byref = false;

            int end_token = 0;

            for(int i = 3; i < token.size(); i++)
            {
                if(token[i].compare("<byref>")==0)
                {
                    fn_byref = true;
                }
                else if(rc_substr(token[i], 0, 4).compare("<id>")==0)
                {
                    fn_arg += token[i];
                    if(fn_arg.substr(fn_arg.length()-1,1).compare("$")==0)
                        fn_arg_type = ID_TYPE_STR;
                    else
                        fn_arg_type = ID_TYPE_NUM;
                }
                else if(token[i].compare("<as>")==0)
                {
                    i++;
                    fn_arg_type = ID_TYPE_USER;
                    fn_arg_user_type = "";
                    int arg_type_index = -1;
                    if(i < token.size())
                        if(token[i].substr(0,4).compare("<id>")==0)
                            fn_arg_user_type = token[i].substr(4);

                    if(fn_arg_user_type.compare("")==0)
                    {
                        rc_setError("Invalid Type in SUB ROUTINE Definition");
                        return false;
                    }

                }
                else if(token[i].compare("<comma>")==0)
                {
                    //cout << "ADD ARG: " << fn_arg << endl;
                    fn_arg = rc_substr(fn_arg, 4, fn_arg.length()-1);
                    if(!isValidIDName(fn_arg))
                    {
                        rc_setError("SUB ROUTINE argument is not a valid identifier name");
                        return false;
                    }
                    if(idExistsInScope(fn_arg))
                    {
                        rc_setError("SUB ROUTINE argument identifier already exists in current scope");
                        return false;
                    }

                    //cout << "CHECK 1" << endl;

                    if(fn_byref)
                    {
                        if(fn_arg_type == ID_TYPE_NUM)
                            fn_arg_type = ID_TYPE_BYREF_NUM;
                        else if(fn_arg_type == ID_TYPE_STR)
                            fn_arg_type = ID_TYPE_BYREF_STR;
                        else
                            fn_arg_type = ID_TYPE_BYREF_USER;
                    }

                    if(!add_embedded_arg(fn_arg, fn_arg_type, getUType(fn_arg_user_type)))
                    {
                        return false;
                    }
                    fn_arg = "";
                    fn_byref = false;

                    //cout << "DONE" << endl;
                }
                else if(token[i].compare("</par>")==0)
                {
                    if((i+1) < token.size())
                    {
                        rc_setError("Expected End of SUB ROUTINE Declaration");
                        return false;
                    }
                    if(fn_arg.compare("")==0)
                    {
                        end_token = i+1;
                        break;
                    }
                    fn_arg = rc_substr(fn_arg, 4, fn_arg.length()-1);
                    if(!isValidIDName(fn_arg))
                    {
                        rc_setError("SUB ROUTINE argument is not a valid identifier name");
                        return false;
                    }
                    if(idExistsInScope(fn_arg))
                    {
                        rc_setError("SUB ROUTINE argument identifier already exists in current scope");
                        return false;
                    }

                    if(fn_byref)
                    {
                        if(fn_arg_type == ID_TYPE_NUM)
                            fn_arg_type = ID_TYPE_BYREF_NUM;
                        else if(fn_arg_type == ID_TYPE_STR)
                            fn_arg_type = ID_TYPE_BYREF_STR;
                        else
                            fn_arg_type = ID_TYPE_BYREF_USER;
                    }

                    if(!add_embedded_arg(fn_arg, fn_arg_type, getUType(fn_arg_user_type)))
                    {
                        return false;
                    }

                    fn_arg = "";
                    fn_byref = false;
                    end_token = i+1;
                    break;
                }
                else
                {
                    rc_setError("Argument to SUB ROUTINE must be a valid identifier: " + token[i]);
                }
            }

            current_block_state = BLOCK_STATE_MAIN;
            current_scope = "main";
            block_state.pop();
            isInFunctionScope = false;
            current_fn_index++;

            if(token.size()>end_token)
            {
                rc_setError("Expected end of function declaration");
                return false;
            }

        }
        else if(token[0].compare("<type>")==0)
        {
            if(current_scope.compare("main")!=0)
            {
                rc_setError("TYPE cannot be defined in this scope");
                return false;
            }
            if(token.size() != 2)
            {
                rc_setError("Expected TYPE Identifier in TYPE statement");
                return false;
            }
            if(token[1].substr(0,4).compare("<id>")!=0)
            {
                rc_setError("Expected TYPE Identifier in TYPE statement");
                return false;
            }
            int id_index = getIDInScope_ByIndex(token[1].substr(4));
            if(id_index >= 0)
            {
                rc_setError("TYPE Identifier exists in current scope");
                return false;
            }
            create_type(token[1].substr(4));
            current_block_state = BLOCK_STATE_TYPE;
            block_state.push(current_block_state);

            string start_label = current_scope + ".#TYPE:" + token[1].substr(4);

            current_scope  = start_label;
        }
        else if(token[0].compare("<dim>")==0)
        {
            if(current_block_state != BLOCK_STATE_TYPE)
            {
                rc_setError("DIM can only be used for type members when embedding");
                return false;
            }
            //cout << "DIM RULE FOUND" << endl;  //'DIM' [ID]; '[' #; #; # ']' ; 'AS' [TYPE]; '=' (VALUE)

            string id_name = "";
            int id_type = ID_TYPE_NUM;
            string id_type_name = "";
            int dimensions = 0;

            //check if the next token is a identifier
            if(token.size() > 1)
            {
                if(token[1].substr(0,4).compare("<id>")==0)
                {
                    //if the identifier is not a valid name then return false
                    id_name = token[1].substr(4);
                    id_type = ID_TYPE_NUM;
                    id_type_name = "";
                    dimensions = 0;

                    if(!isValidIDName(id_name))
                    {
                        rc_setError("Invalid Identifier name");
                        return false;
                    }

                    //check if the data type is a string
                    if(id_name.substr(id_name.length()-1).compare("$")==0)
                        id_type = ID_TYPE_STR;

                    //if the identifier already exists and current_block state is not type then return false
                    if(idExistsInScope(id_name))
                    {
                        rc_setError("Identifier already defined in current scope");
                        return false;
                    }

                    //cout << "db1\n";

                    //if there are only two tokens then return here because there is nothing left to check
                    if(token.size()==2)
                    {
                        if(current_block_state == BLOCK_STATE_TYPE)
                        {
                            //cout << "adding type member" << endl;
                            if(!add_type_member_embedded(id_name, id_type, "", 0, 0, 0, 0))
                            {
                                //cout << rc_getError() << endl;
                                return false;
                            }
                        }

                        //cout << "return true here" << endl;
                        return true;
                    }

                    //cout << "db2\n";

                    //current token
                    int token_index = 2;

                    int t_dim_arg[3];
                    t_dim_arg[0] = 0;
                    t_dim_arg[1] = 0;
                    t_dim_arg[2] = 0;

                    //check for the next rule; must be [], AS, or =
                    //cout << "token = " << token[token_index] << endl;
                    if(token[token_index].compare("<square>")==0 && current_block_state == BLOCK_STATE_TYPE)
                    {
                        //token_index++;
                        int end_token = token_index+1;
                        int sq_scope = 1;
                        multi_arg_count = 0;
                        int arg_index = 0;

                        t_dim_arg[0] = 0;
                        t_dim_arg[1] = 0;
                        t_dim_arg[2] = 0;
                        for(; end_token < token.size(); end_token++)
                        {
                            if(token[end_token].compare("<square>")==0)
                                sq_scope++;
                            else if(token[end_token].compare("</square>")==0)
                                sq_scope--;
                            else if(token[end_token].substr(0,5).compare("<num>")==0)
                            {
                                if(arg_index > 2)
                                {
                                    rc_setError("Too many dimensions in type member declaration for embedded");
                                    return false;
                                }
                                multi_arg[arg_index] = token[end_token].substr(5);
                                t_dim_arg[arg_index] = rc_stringToInt(multi_arg[arg_index]);
                                multi_arg_count = arg_index+1;
                            }
                            else if(token[end_token].compare("<comma>")==0)
                                arg_index++;
                            else
                            {
                                rc_setError("Expected number constant in type member declaration for embedded: " + token[end_token]);
                                return false;
                            }

                            if(sq_scope==0)
                                break;
                        }
                        if(sq_scope != 0)
                        {
                            rc_setError("Expected ] in array definition");
                            return false;
                        }

                        dimensions = multi_arg_count;


                        token_index = end_token+1;

                        //cout << "DBG token = " << token[token_index] << std::endl;

                        if(token.size() > token_index)
                        {
                            if(token[token_index].compare("<as>")==0)
                            {
                                token_index++;
                                if(token[token_index].substr(0,4).compare("<id>")!=0)
                                {
                                    rc_setError("Invalid type identifier name in DIM");
                                    return false;
                                }

                                id_type = ID_TYPE_USER;
                                id_type_name = token[token_index].substr(4);
                                //cout << "Add member (" << id_name << ") of type (" << id_type_name << ") with " << dimensions << " dimensions [" << constant_arg[0] << "," << constant_arg[1] << "," << constant_arg[2] << "]" << endl;
                                //if(!add_type_member(id_name, id_type, id_type_name, dimensions, constant_arg[0], constant_arg[1], constant_arg[2]))
                                if(!add_type_member_embedded(id_name, id_type, id_type_name, dimensions, t_dim_arg[0], t_dim_arg[1], t_dim_arg[2]))
                                    return false;
                            }
                            else
                            {
                                rc_setError("Invalid member array declaration in DIM");
                                return false;
                            }
                        }
                        else
                        {
                            //cout << "Add member (" << id_name << ") of type (num/str) with " << dimensions << " dimensions [" << constant_arg[0] << "," << constant_arg[1] << "," << constant_arg[2] << "]" << endl;
                            //if(!add_type_member(id_name, id_type, "", dimensions, constant_arg[0], constant_arg[1], constant_arg[2]))
                            if(!add_type_member_embedded(id_name, id_type, "", dimensions, t_dim_arg[0], t_dim_arg[1], t_dim_arg[2]))
                                return false;
                        }

                        return true;

                    }
                    else if(token[token_index].compare("<as>")==0)
                    {
                        token_index++;

                        if(token_index >= token.size())
                        {
                            rc_setError("Invalid member declaration");
                            return false;
                        }

                        if(token[token_index].substr(0,4).compare("<id>")!=0)
                        {
                            rc_setError("Invalid type identifier name in DIM");
                            return false;
                        }

                        id_type = ID_TYPE_USER;
                        id_type_name = token[token_index].substr(4);
                        //cout << "Add member (" << id_name << ") of type (" << id_type_name << ") with " << dimensions << " dimensions [" << constant_arg[0] << "," << constant_arg[1] << "," << constant_arg[2] << "]" << endl;
                        //if(!add_type_member(id_name, id_type, id_type_name, dimensions, constant_arg[0], constant_arg[1], constant_arg[2]))
                        if(!add_type_member_embedded(id_name, id_type, id_type_name, 0, 0, 0, 0))
                            return false;

                        return true;
                    }


                    if(token.size()>token_index)
                    {
                        rc_setError("Invalid variable definition: " + token[token_index] + ", " + rc_intToString(current_block_state) + " <--> " + rc_intToString(BLOCK_STATE_TYPE));
                        return false;
                    }

                }
                else
                {
                    //if the next token is not an id then the syntax is incorrect and false is returned
                    rc_setError("Expected Identifier name");
                    return false;
                }

            }
            else
            {
                //if the size of the token vector is not greater than one then the syntax for the line is incomplete so I return false
                rc_setError("Expected Identifier name");
                return false;
            }
        }
        else if(token[0].compare("<end>")==0)
        {
            if(token.size()==1)
            {
                rc_setError("END can only be used to end TYPE when embedding");
                return false;
            }
            if(token[1].compare("<type>")==0)
            {
                if(token.size()>2)
                {
                    rc_setError("Expected End of Line in END TYPE");
                    return false;
                }
                if(current_block_state != BLOCK_STATE_TYPE)
                {
                    rc_setError("Cannot exit TYPE definition from this scope");
                    return false;
                }

                block_state.pop();
                current_block_state = BLOCK_STATE_MAIN;
                current_scope = "main";
            }
            else
            {
                rc_setError("END can only be used to end TYPE when embedding");
                return false;
            }
        }
    }
    return true;
}

#endif // PARSER_H_INCLUDED
