c++ - std::unordered_map 作为结构成员具有地址 0

标签 c++ struct

我有一个看起来像这样的结构:

// A lexical scope that keeps track of every declared variable
// in a function
struct LexState
{
    // A map containing the index of a variable in it's function
    // The key is the variable name
    std::unordered_map<std::string, int> _vars;

    Function *_function;
    LexState *_parent;
};

这是使用结构的代码:

#define DD(msg) std::cout << "Debug: " << msg << '\n'
#define DD1(msg, p1) std::cout << "Debug: " << msg << p1 << '\n'
#define DD2(msg, p1, p2) std::cout << "Debug: " << msg << p1 << p2 << '\n'

// A lexical scope that keeps track of every declared variable
// in a function
struct LexState
{
    // A map containing the index of a variable in it's function
    // The key is the variable name
    std::unordered_map<std::string, int> _vars;

    Function *_function;
    LexState *_parent;

    LexState(LexState *parent, Function *function)
    {
        _parent = parent;
        _function = function;
    }

    Value *SearchVar(char *name)
    {
        if (_parent == nullptr)
        {
            return nullptr;
        }
        std::string str(name);
        auto var = _parent->_vars.find(str);
        if (var == _parent->_vars.end())
        {
            return _parent->SearchVar(name);
        }
        return _function->GetLocalVar(var->second)->GetValue();
    }
};

class Compiler
{
public:

    State *_state;
    Function *_current_function;
    GC *_gc;
    LexState *_ls;

    Compiler(State *state) :
        _state(state)
    {
        _current_function = nullptr;
        _gc = state->GetGC();
        _current_function = new Function(nullptr);
        _state->_main_function = _current_function;
        _ls = nullptr;
    }

    void PushFunction()
    {
        Function *new_function = new Function(_current_function);
        _current_function = new_function;
        LexState *new_ls = new LexState(_ls, new_function);

        // even now, right after creating new_ls, new_ls->_vars is 0
        printf("%p\n", &new_ls->_vars);
        _ls = new_ls;
    }

    void PopFunction()
    {
        _current_function = _current_function->_parent;
        LexState *parent = _ls->_parent;
        delete _ls;
        _ls = parent;
    }

    int DeclareVar(const Symbol *node)
    {
        assert(node->_type == NODE_SYMBOL);

        DD("Declaring variable");

        auto token = node->_token;
        char name[token->len + 1];
        memcpy(name, token->pos, token->len);
        name[token->len] = '\0';

        int idx = _current_function->AddLocalVar(name);
        std::string key(name);

        printf("%p\n", &_ls->_vars);

        if (_ls != nullptr)
            _ls->_vars.insert(std::make_pair(key, idx));
        else
           DD("LexState nullptr");

        DD("Variable declared");

        return idx;
    }

    void Compile(const Node *node)
    {
        switch (node->_type)
        {
            case NODE_CHUNK:
                CompileChunk((Chunk *)node);
                break;

            case NODE_BLOCK:
                CompileBlock((Block *)node);
                break;

            case NODE_FUNCTION_DEF:
                CompileFunctionDef((FunctionDef *)node);
                break;

            case NODE_CONDITIONAL:
                CompileConditional((ConditionalStatement *)node);
                break;

            case NODE_BINARY_EXPR:
                CompileBinaryExpr((BinaryExpr *)node);
                break;

            case NODE_UNARY_EXPR:
                CompileUnaryExpr((UnaryExpr *)node);
                break;

            case NODE_SYMBOL:
                CompileSymbol((Symbol *)node);
                break;

            case NODE_STRING_LITERAL:
                CompileStringLiteral((StringLiteral *)node);
                break;

            case NODE_BOOL_LITERAL:
                CompileBoolLiteral((BoolLiteral *)node);
                break;

            case NODE_INT_LITERAL:
                CompileIntLiteral((IntLiteral *)node);
                break;
        }
    }

    void CompileChunk(const Chunk *chunk)
    {
        Compile(chunk->_block);
        AddCode(OP_HALT);
    }

    void CompileBlock(const Block *block)
    {
        std::vector<Node *> vec = block->_vec;
        for (auto it = vec.begin(); it != vec.end(); it++)
        {
            Compile(*it);
        }
    }

    void CompileFunctionDef(const FunctionDef *func)
    {
        Value v;

        int f = AddConstant(v);
        AddCode(OP_PUSH, f);

        Value *vp = _current_function->GetConstant(f);

        if (func->_name)
        {
            int fvar = DeclareVar((Symbol *)func->_name);
            AddCode(OP_STOR_LOCAL, fvar);
        }

        ArgList *argsnode = (ArgList *)func->_args;
        auto args = argsnode->_vec;
        int argcount = args.size();

        PushFunction();
        auto closure = new Closure(_current_function);
        closure->_argcount = argcount;
        std::cout << argcount << '\n';
        vp->_closure = closure;
        vp->_type = VALUE_CLOSURE;

        // Compiling inside function

        // Arguments are compiled in reserved order, because in the function call
        // the passed arguments will be pushed in the order they are passed
        for (auto it = args.rbegin(); it != args.rend(); it++)
        {
            int var = DeclareVar((Symbol *)*it);
            AddCode(OP_STOR_LOCAL, var);
        }

        if (func->_guard)
        {
            Compile(func->_guard);
        }
        else
        {
            Compile(func->_body);
        }

        AddCode(OP_RETURN);

        // End function

        PopFunction();
    }

    void CompileConditional(const ConditionalStatement *node)
    {
        auto function = _current_function;
        Compile(node->_condition);

        int cond_res_idx = function->AddLocalVar();
        AddCode(OP_DUP);

        // Store the condition result into an internal variable
        AddCode(OP_STOR_LOCAL, cond_res_idx);

        AddCode(OP_DUP);
        int true_jmp = AddCode(OP_JMP_T, 0);
        int false_jmp = AddCode(OP_JMP_F, 0);

        // Save index of the first code of the block
        int block_idx = function->_code.size();

        // Jump to block when condition is true
        function->ChangeCode(true_jmp, block_idx);

        Compile(node->_expr1);
        AddCode(OP_PUSH_LOCAL, cond_res_idx);

        // Jump to the end of the whole if-elif-else statement
        // if the condition result was true
        int exit_jmp = AddCode(OP_JMP_T, 0);

        // Save index of the first code after this statement
        int right_idx = function->_code.size();
        function->ChangeCode(false_jmp, right_idx);

        if (node->_expr2 != nullptr)
        {
            Compile(node->_expr2);
        }
        else
        {
            AddCode(OP_PUSH_NIL);
        }

        int end_idx = function->_code.size();
        function->ChangeCode(exit_jmp, end_idx);
    }

    void CompileBinaryExpr(const BinaryExpr *expr)
    {
        auto function = _current_function;
        auto token = expr->_op->type;

        if (token == TOKEN_ASSIGN)
        {
            if (expr->_left->_type == NODE_SYMBOL)
            {
                int var = DeclareVar((Symbol *)expr->_left);

                Compile(expr->_right);
                AddCode(OP_STOR_LOCAL, var);
                return;
            }
        }

        // A function call
        if (token == TOKEN_LEFTPAREN)
        {
            ArgList *arglist = (ArgList *)expr->_right;
            auto args = arglist->_vec;
            int argcount = args.size();

            // A function call cannot have more than 255 arguments
            assert(argcount < 256);

            for (auto it = args.begin(), end = args.end();
                it != end; it++)
            {
                Compile(*it);
            }

            Compile(expr->_left);

            AddCode(OP_CALL, argcount);
            return;
        }

        Compile(expr->_left);

        // Both 'and' and 'or' expressions does short circuit
        if (token == TOKEN_BOOL_AND || 
            token == TOKEN_BOOL_OR)
        {

            AddCode(OP_DUP);

            OpType op = (token == TOKEN_BOOL_AND) ? OP_JMP_F : OP_JMP_T;
            int idx = AddCode(op, function->_ip + 1);

            Compile(expr->_right);
            int next = function->_code.size();
            uint32_t instr = function->_code[idx];
            function->ChangeCode(idx, next);
            return;
        }

        // No need for lazy evaluation, compile normally
        Compile(expr->_right);

        switch (expr->_op->type)
        {

            case TOKEN_ADD:
                AddCode(OP_ADD);
                break;
            case TOKEN_SUB:
                AddCode(OP_SUB);
                break;
            case TOKEN_MUL:
                AddCode(OP_MUL);
                break;
            case TOKEN_DIV:
                AddCode(OP_DIV);
                break;
            case TOKEN_POW:
                AddCode(OP_POW);
                break;
            case TOKEN_AND:
                AddCode(OP_AND);
                break;
            case TOKEN_OR:
                AddCode(OP_OR);
                break;
            case TOKEN_XOR:
                AddCode(OP_XOR);
                break;
            case TOKEN_LT:
                AddCode(OP_LT);
                break;
            case TOKEN_GT:
                AddCode(OP_GT);
                break;
            case TOKEN_LTEQ:
                AddCode(OP_LTEQ);
                break;
            case TOKEN_GTEQ:
                AddCode(OP_GTEQ);
                break;
            case TOKEN_SHIFT_L:
                AddCode(OP_SHIFT_L);
                break;
            case TOKEN_SHIFT_R:
                AddCode(OP_SHIFT_R);
                break;
        }
    }

    void CompileUnaryExpr(const UnaryExpr *expr)
    {
        Compile(expr->_right);

        switch (expr->_token->type)
        {
            case TOKEN_SUB:
                AddCode(OP_NEGATE);
                break;

            case TOKEN_NOT:
                AddCode(OP_NOT);
                break;

            case TOKEN_BOOL_NOT:
                AddCode(OP_BOOL_NOT);
                break;
        }
    }

    // This function gets called only when it's a reference
    void CompileSymbol(const Symbol *node)
    {
        auto token = node->_token;
        char name[token->len + 1];
        memcpy(name, token->pos, token->len);
        name[token->len] = '\0';

        DD1("Searching reference: ", name);

        Value *upvalue = _ls->SearchVar(name);
        if (upvalue)
        {
            int idx = _current_function->AddUpValue(upvalue);
            AddCode(OP_PUSH_UPVALUE, idx);
            return;
        }

        int idx = _current_function->GetLocalVarIndex(name);
        AddCode(OP_PUSH_LOCAL, idx);
    }

    void CompileStringLiteral(const StringLiteral *sl)
    {
        Value v(sl->_token->str, sl->_token->len);
        AddCode(OP_PUSH, AddConstant(v));
    }

    void CompileBoolLiteral(const BoolLiteral *bl)
    {
        Value v(bl->_token->type == TOKEN_TRUE);
        AddCode(OP_PUSH, AddConstant(v));
    }

    void CompileIntLiteral(const IntLiteral *il)
    {
        Value v(il->_token->num);
        AddCode(OP_PUSH, AddConstant(v));
    }

    int AddCode(OpType code)
    {
        return _current_function->AddCode(code);
    }

    int AddCode(OpType code, int a)
    {
        return _current_function->AddCode(code, a);
    }

    int AddConstant(const Value &v)
    {
        return _current_function->AddConstant(v);
    }
};

程序输出:

Declaring variable
0

它在 DD("Variable declared") 部分之前崩溃。

尽管我是 C++ 的新手,但我很确定我不需要自己分配无序映射,对吗?因为它不是一个指针,它会在我执行 new LexState

时分配

那么我忘记了任何初始化/分配吗?

最佳答案

%i 不是用于打印指针的正确格式说明符。您很可能得到表示指针截断值的输出。请改用 %p

printf("%p\n", &state->_vars);

我没有发现使用 state->_vars 有任何问题。请参阅 http://ideone.com/YAJK5K 处的工作代码.

关于c++ - std::unordered_map 作为结构成员具有地址 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33265814/

相关文章:

C++ STD::find_if 使用结构谓词

c++ - 如何在单元测试中引入对 std::string 的边界检查?

matlab - 动态访问 Matlab 中的嵌套字段

c++ - 为要在 1 类中使用的结构成员分配常量值

c++ - 用于编译 .idls 的 Makefile

c++ - Arduino:中断昂贵的功能并恢复另一个

c++ - 在 Visual Studio C++ 构建中打印日期和时间?

ios - NSNotificationCenter 发布 C 结构并从通知回调函数中检索它

c# - 将结构从 C# 程序共享到 C++ win32 DLL 的最佳实践?

c++ - 如何从未排序的链表中删除重复项