⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 semantics.cpp

📁 SSD6 练习4的原版正确答案
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	mach->push(s);
	// is this a local? look in method symbol table
    if (method->get_localtable()->lookup(s, &index)) {
		must(emit(instr_compose(instr_store_local, (short) index)));
	} else if (fclass && 
               fclass->get_symboltable()->lookup(s, &mp, &index) &&
			   mp == NULL) {
		trace("assign_id got instance index of %d\n", index);
		must(emit(instr_compose(instr_store_instvar, (short) index)));
	} else { // load value from a global
		index = insert_symbol(id);
		must(emit(instr_compose(instr_store_global, (short) index)));
	}
	mach->pop();
	return true;
}


bool Semantics::field(char *id)
{
	trace("field not implemented\n");	// not implemented
	return true;
}


bool Semantics::aref()
{
	return emit(OP_AREF);
}

bool Semantics::if_true()
{
    // emit a test to branch over true part
    must(emit(OP_JUMPIFNOT));
    // save PC for the branch location
    if_stack->push(next_instr, mach);
    // emit zero as a placeholder for branch location
    return emit(0);
}


bool Semantics::if_else()
{
    // this is the target for the if:
	long target = if_stack->pop(mach);
    // emit a jump around else part
    must(emit(OP_JUMP));
    // save PC for the branch location
    if_stack->push(next_instr, mach);
    // emit zero as a placeholder for branch location
    emit(0);
    return emit_at(target, next_instr - target);
}


bool Semantics::if_end()
{
    // this is the target for whatever is on the stack
	long target = if_stack->pop(mach);
    return emit_at(target, next_instr - target);
}


bool Semantics::while_begin()
{
    // remember where to branch back to
    loop_stack->push(next_instr, mach);
    return true;
}

bool Semantics::while_true()
{
    // emit a test to branch over true part
    must(emit(OP_JUMPIFNOT));
    // save PC for the branch location
    loop_stack->push(next_instr, mach);
    // emit zero as a placeholder for branch location
    return emit(0);
}


bool Semantics::while_end()
{
    // top of stack is branch out of loop
    long end_of_loop_branch = loop_stack->pop(mach);
    // now emit loop branch
    must(emit(OP_JUMP));
    must(emit(loop_stack->pop(mach) - next_instr));
    // fix up previous branch to next instr (after loop)
    return emit_at(end_of_loop_branch, next_instr - end_of_loop_branch);
}


bool Semantics::return_end()
{
    return emit(OP_RETURN);
}


bool Semantics::load_end()
{
    return emit(OP_LOAD);
}


bool Semantics::print_expr()
{
	return emit(OP_PRINT);
}


bool Semantics::print_comma()
{
    return emit(OP_SPACE);
}


bool Semantics::print_end()
{
    return emit(OP_ENDL);
}


// assign_end -- called after rval is on stack
// 
// emit pushed instruction to finish the job:
// possibilities are:
//   assign to array: stack has array, index, value
//   assign to head: stack has node, value
//   assign to tail: stack has node, value
//   assign to variable: stack has value
//   assign to field of object: stack has object, index, value
//
bool Semantics::assign_end()
{
    short op = assign_stack->pop(mach);
    return emit(op);
}


// rval2lval -- prepare for an assignment statement
//
// when you encounter an '=', the expression on the left has
// just emitted an instruction to load the value to the stack
// The method "undoes" the emit, and converts the instruction
// from one that loads a value to one that stores a value.
// Error is returned if the instruction cannot be converted.
// E.g. if the instruction is an array reference, convert to 
// a store.  If the instruction is addition, return false.
//
bool Semantics::rval2lval()
{
    // first get previous instruction
    short op = unemit();
    short newop = OP_NOOP;
    
    // now compute the assignment version of op
    short typ = instr_type(op);
    short arg = instr_arg(op);
    if (typ == instr_op) {
        if (op == OP_AREF) newop = OP_SETAREF;
        else if (op == OP_FIELD) newop = OP_SETFIELD;
    } else if (typ == instr_load_global) {
        newop = instr_compose(instr_store_global, arg);
    } else if (typ == instr_load_instvar) {
        newop = instr_compose(instr_store_instvar, arg);
    } else if (typ == instr_load_local) {
        newop = instr_compose(instr_store_local, arg);
    }
    if (newop != OP_NOOP) {
        assign_stack->push(newop, mach);
        return true;
    }
    return false;
}
        

bool Semantics::unary_minus()
{
    return emit(OP_MINUS);
}


bool Semantics::not()
{
    return emit(OP_NULL);
}


bool Semantics::lognot()
{
    return emit(OP_LOGNOT);
}


bool Semantics::push_long(int64 value)
{
	if (mach->arg_sign_extend(instr_arg((long) value)) == value) {
		return emit(instr_compose(instr_load_int, instr_arg((short) value)));
	} else {
		FVal lit = FLong::create(value, mach);
		mach->push(lit);
		assert(method);
		short arg = method->literal_add(lit, mach);
		mach->pop();
		return emit(instr_compose(instr_load_lit, arg));
	}
}

bool Semantics::push_double(double value)
{
	FVal lit = FDouble::create(value, mach);
	return push_fval(lit);
}


bool Semantics::push_string(char *s)
{
    FVal lit = FString::create(s, mach);
	return push_fval(lit);
}


bool Semantics::push_symbol(char *s)
{
    FVal lit = Symbol::create(s, mach);
    return push_fval(lit);
}


bool Semantics::push_fval(FVal v)
{
	mach->push(v);
	assert(method);
	short arg = method->literal_add(v, mach);
	mach->pop();
	return emit(instr_compose(instr_load_lit, arg));
}


bool Semantics::var_decl(char * id)
{
	if (method_started) { // local variable in method
		assert(method);
		Symbol_ptr s = Symbol::create(id, mach);
		assert(s);
		mach->push(s);
		trace("var_decl: before new method variable, locals are:\n");
		method->get_localtable()->trace_locals();
		if (!method->get_localtable()->
			insert_var(s, local_offset++, mach)) {
			comp->report_error("local variable already declared");
			mach->pop();
			return false;
		}
		method->set_stack_offset(1 + method->get_stack_offset());
		mach->pop();
	} else if (class_started) {
		assert(fclass);
		Symbol_ptr s = Symbol::create(id, mach);
		mach->push(s);
		trace("instance var at index %d\n", member_offset);
		if (!fclass->get_symboltable()->
			insert_var(s, member_offset++, mach)) {
			comp->report_error("instance variable already declared");
			mach->pop();
			return false;
		}
		mach->pop();
		fclass->set_inst_slots(member_offset);
	}
	// undeclared variables are globals, the value is stored on the
	// symbol itself, so we do not need to enter it into a table

	// show current state of things
	if (method_started) {
		trace("current locals are:\n");
		method->get_localtable()->trace_locals();
	} else if (class_started) {
		trace("current members are:\n");
		fclass->get_symboltable()->trace_members();
	} else trace("global variable declared\n");
	return true;		
}


// Here's how array code generation works:
//    the current array_index is pushed on array_stack
//     and array_index is set to 0
//     (in case we are dealing with nested arrays)
//    emit placeholder for the size of the array
//     (so there is an upper bound on the size of a 
//     literal array: the maximum literal integer,
//     which is 2047)
//    the location of the literal is pushed on array_stack
//    the create array instruction is emitted
//    for each expression, we duplicate the top of stack,
//     emit a literal index, and emit a store into array op
//    at array_end, we know the size of the array, so we
//     pop the stack and emit the size at that location
//    finally, pop the previous array_index value
bool Semantics::array_start()
{
	array_stack->push(array_index, mach);
	array_index = 0;
	array_stack->push(next_instr, mach);
	return emit(0) && emit(OP_NEWARRAY);
}

bool Semantics::dict_start()
{
	array_stack->push(array_index, mach);
	array_index = 0;
	array_stack->push(next_instr, mach);
	return emit(0) && emit(OP_NEWDICT);
}



bool Semantics::before_array_expr()
{
	short instr = instr_compose(instr_load_int, array_index);
	if (instr_arg(instr) != array_index) {
		comp->report_error("array expression too long");
		return false;
	}
	array_index++;
    return emit(OP_DUP) && emit(instr);
}


bool Semantics::before_dict_key()
{
	array_index++;
    return emit(OP_DUP);
}


bool Semantics::before_dict_val()
{
    return true;
}



bool Semantics::array_expr()
{
    return emit(OP_SETAREF);
}

bool Semantics::dict_key()
{
    return true;
}


bool Semantics::dict_val()
{
    return emit(OP_SETAREF);
}



bool Semantics::array_end()
{
	must(emit_at(array_stack->pop(mach), 
			     instr_compose(instr_load_int, array_index)));
	array_index = array_stack->pop(mach);
	return true;
}


bool Semantics::dict_end()
{
	must(emit_at(array_stack->pop(mach), 
			     instr_compose(instr_load_int, array_index)));
	array_index = array_stack->pop(mach);
	return true;
}


// here's how calls work: 
// there are many built-in functions that compile to instructions
// which must be handled here rather than at run-time. When call()
// or method_call() is called, we look up the function to see if it
// is built-in. If so, we push the corresponding opcode and then
// the required number of parameters onto the call_stack (a 
// compile-time structure). If the function is not built-in, we
// push zero and -1. Whenever we get an actual, we look at the top
// of stack. If opcode = 0 (not built-in), we generate a param opcode, 
// otherwise we decrement
// the top of stack. (At runtime the parameter will be left on the
// expression stack, not copied to a frame.) If the top of stack 
// would go to -1, we return an error (too many parameters).
// When we get an actual_end() we look at the opcode:
// If non-zero, emit it. If zero, emit the
// call opcode. If actuals is greater than zero, return an error
// (too few actuals).
// FOR CONVENIENCE, we will keep the top of the stack in member vars,
// opcode and actuals.

bool Semantics::actual()
{
    if (opcode == 0) return emit(OP_PARAM);
	if (actuals == 0) {
		comp->report_error("too many parameters");
		return false;
	}
	actuals--;
	return true;
}


bool Semantics::keyword(long index)
{
    assert(index < 0x10000);
    if (opcode == 0) {
        return emit(OP_KEYPARAM) && emit((short) index);
    } else {
        comp->report_error("unexpected keyword parameter");
        return false;
    }
}


bool Semantics::actual_end()
{
    // if optional start, stop parameters are missing, fill
    // them in now
    if (opcode == instr_compose(instr_op, OP_FIND)) {
        if (actuals == 2) {
            push_long(0);
            actuals--;
        }
        if (actuals == 1) {
            push_long(-1);
            actuals--;
        }
    // this is another style for variable argument lists
    // if get(key) use OP_GET, if get(key, default) use OP_GET2:
    } else if (opcode == instr_compose(instr_op, OP_GET)) {
        if (actuals == 1) {
            actuals--; // OP_GET really takes one parameter
        } else if (actuals == 0) {
            // 2 parameters, so use OP_GET2:
            opcode = instr_compose(instr_op, OP_GET2);
        }
    }
	if (actuals > 0) {
		comp->report_error("too few parameters");
		return false;
	}
	if (opcode != 0) emit(opcode);
	else emit(instr_compose(instr_op, OP_CALL));
    actuals = call_stack->pop(mach);  // restore actuals
	opcode = call_stack->pop(mach);   // restore opcode
	return true;
}


bool Semantics::end_id_expr()
{
	emit(instr_compose(instr_op, OP_POP));
	return true;
}

int Semantics::insert_symbol(char *str)
{
	Symbol_ptr s = Symbol::create(str, mach);
	mach->push(s);
	long len = symbols->get_array_len();
	for (int i = 0; i < len; i++) {
		if (symbols->fastref(i).symbol == s) {
			mach->pop();
			return i;
		}
	}
	symbols->append(s, mach);
	mach->pop();
	return i;
}


bool Semantics::relop(char *op)
{
    if (streql(op, "<")) return emit(OP_LESS);
    if (streql(op, ">")) return emit(OP_GTR);
    if (streql(op, "<=")) return emit(OP_LESSEQL);
    if (streql(op, ">=")) return emit(OP_GTREQL);
    if (streql(op, "==")) return emit(OP_ISEQUAL);
    if (streql(op, "!=")) return emit(OP_NOTEQUAL);
    if (streql(op, "is")) return emit(OP_IS);
    if (streql(op, "isnot")) return emit(OP_ISNOT);
    if (streql(op, "in")) return emit(OP_MEMBER);
    if (streql(op, "notin")) return emit(OP_NOTMEMBER);
    return false;
}


bool Semantics::addop(char *op)
{
    if (streql(op, "+")) return emit(OP_ADD);
    if (streql(op, "-")) return emit(OP_SUB);
    return false;
}


bool Semantics::mulop(char *op)
{
    if (streql(op, "*")) return emit(OP_MUL);
    if (streql(op, "/")) return emit(OP_DIV);
    if (streql(op, "%")) return emit(OP_REM);
    return false;
}


bool Semantics::power()
{
    return emit(OP_POWER);
}


bool Semantics::begin_and(char *op)
{
    if (op[0] == '&') return true; // logical and
    must(emit(OP_CNDAND));
    if_stack->push(next_instr, mach);
    // emit zero as a placeholder for branch location
    return emit(0);
}


bool Semantics::end_and(char *op)
{
    if (op[0] == '&') return emit(OP_LOGAND);
	long target = if_stack->pop(mach);
    return emit_at(target, next_instr - target);
    // emit a jump around 2nd operand to here
}

bool Semantics::begin_or(char *op)
{
    if (op[0] == '|' ||
        op[0] == '^') return true; // logical or
    must(emit(OP_CNDOR));
    if_stack->push(next_instr, mach);
    // emit zero as a placeholder for branch location
    return emit(0);
}


bool Semantics::end_or(char *op)
{
    if (op[0] == '|') return emit(OP_LOGIOR);
    if (op[0] == '^') return emit(OP_LOGXOR);
    if (op[0] == '<') return emit(OP_LSHIFT);
    if (op[0] == '>') return emit(OP_RSHIFT);
	long target = if_stack->pop(mach);
    return emit_at(target, next_instr - target);
    // emit a jump around 2nd operand to here
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -