我有一个看起来像这样的结构:
// 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;
};
这是使用struct的代码:
#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
那么我忘记了任何初始化/分配吗?
答案 0 :(得分:2)
%i
不是用于打印指针的正确格式说明符。您最有可能获得表示指针截断值的输出。请改用%p
。
printf("%p\n", &state->_vars);
我使用state->_vars
看不出任何错误。请参阅http://ideone.com/YAJK5K处的工作代码。