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

📄 semantics.cpp

📁 SSD6 练习4的原版正确答案
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* semantics -- */

#include "flincl.h"
#include "shortstack.h"
#include "semantics.h"
#include "stdio.h" // for compiler.h
#include "compiler.h"
#include "assert.h"

#define must(emit) if (!(emit)) return false;

typedef struct {
	char *name;
	short params;
	short op;
} Builtin_desc;

// built_ins are "global functions" that cannot be
// overridden or overloaded
Builtin_desc built_ins[] = {
	{ "array", 1, OP_NEWARRAY },
    { "dict", 1, OP_NEWDICT },
    { "flatten", 1, OP_FLATTEN },
    { "repr", 1, OP_REPR },
    { "str", 1, OP_STR },
    { "type", 1, OP_TYPE },
    { "len", 1, OP_LENGTH },
    { "cos", 1, OP_COS },
    { "sin", 1, OP_SIN },
    { "tan", 1, OP_TAN },
    { "exp", 1, OP_EXP },
    { "sqrt", 1, OP_SQRT },
    { "rem", 1, OP_REM },
    { "min", 2, OP_MIN },
    { "max", 2, OP_MAX },
    { "random", 0, OP_RANDOM },
    { "abs", 1, OP_ABS },
    { "int", 1, OP_TRUNCATE },
    { "round", 1, OP_ROUND },
    { "float", 1, OP_FLOAT },
    { "chr", 1, OP_CHR },
    { "ord", 1, OP_ORD },
    { "hex", 1, OP_HEX },
    { "id", 1, OP_ID },
    { "intern", 1, OP_INTERN },
    { "isinstance", 2, OP_INST },
    { "issubclass", 2, OP_SUBCL },
    { "oct", 1, OP_OCT },
    { "strcat", 2, OP_STRCAT },
    { "subseq", 3, OP_SUBSEQ },
    { "isupper", 1, OP_ISUPPER },
    { "islower", 1, OP_ISLOWER },
    { "isalpha", 1, OP_ISALPHA },
    { "isdigit", 1, OP_ISDIGIT },
    { "isalnum", 1, OP_ISALNUM },
    { "toupper", 1, OP_TOUPPER },
    { "tolower", 1, OP_TOLOWER },
    { "find", 4, OP_FIND },
	{ "exit", 0, OP_EXIT },
	{ "frame_previous", 1, OP_FRMPREV },
	{ "frame_variables", 1, OP_FRMVARS },
	{ "frame_pc", 1, OP_FRMPC },
	{ "frame_method", 1, OP_FRMMETH },
	{ "frame_class", 1, OP_FRMCLASS },
	{ "runtime_exception_nesting", 0, OP_NEST },
	{ "frame_get", 0, OP_FRMGET },
	{ NULL, 0, 0 }
};

// builtin_methods are implemented by op_codes,
// but if the first operand's type is object,
// a method lookup is performed. Builtin_methods
// allow us to implement builtin methods on builtin
// types, and run more efficiently than a full
// method call which allocates a frame.
Builtin_desc builtin_methods[] = {
    { "readline", 0, OP_READLINE },
    { "write", 1, OP_WRITE },
    { "read", 1, OP_READ },
	{ "unread", 1, OP_UNREAD },
    { "readvalue", 0, OP_READVAL },
    { "close", 0, OP_CLOSE },
    { "token", 0, OP_TOKEN },
	{ "append", 1, OP_APPEND },
	{ "unappend", 0, OP_UNAPPEND },
    { "last", 0, OP_LAST },
    { "keys", 0, OP_KEYS },
    { "values", 0, OP_VALUES },
    { "clear", 0, OP_CLEAR },
    { "index", 1, OP_INDEX },
    { "reverse", 0, OP_REVERSE },
    { "sort", 0, OP_SORT },
    { "remove", 1, OP_REMOVE },
    { "copy", 0, OP_COPY },
    { "has_key", 1, OP_HASKEY },
    { "get", 2, OP_GET },
	{ "value", 0, OP_VALUE },
    // { "get2", 2, OP_GET2 },
    { NULL, 0, 0 }
};



// builtin -- searches for id in built-in list
//
// if found, return op-code required to execute the built-in
// and set actuals to the number of parameters required by
// the built-in function
// otherwise, return 0 and set actuals to -1
//
short Semantics::builtin(char *id, short *actuals)
{
    int i = 0;
	while (built_ins[i].name) {
		if (streql(built_ins[i].name, id)) {
			*actuals = built_ins[i].params;
			return instr_compose(instr_op, built_ins[i].op);
		}
		i++;
	}
	*actuals = -1;
	return 0;
}


short Semantics::builtin_method(char *id, short *actuals)
{
    int i = 0;
    while (builtin_methods[i].name) {
        if (streql(builtin_methods[i].name, id)) {
            *actuals = builtin_methods[i].params;
            return instr_compose(instr_op, builtin_methods[i].op);
        }
        i++;
    }
    *actuals = -1;
    return 0;
}


bool Semantics::init(Machine_ptr m, Compiler_ptr c)
{
	mach = m;
	comp = c;
	instructions = NULL;
	if_stack = Short_stack::create(3, mach);
	loop_stack = Short_stack::create(2, mach);
	assign_stack = Short_stack::create(2, mach);
	indent_stack = Short_stack::create(8, mach);
	array_stack = Short_stack::create(2, mach);
	call_stack = Short_stack::create(2, mach);
    return if_stack && loop_stack && assign_stack && 
        indent_stack && array_stack && call_stack;
    // BUG: need error report here if returning false
}


Semantics::Semantics()
{
}


bool Semantics::reset()
{
    if (instructions) {
        //FLSys::free(instructions, max_instr);
    }
	class_started = false;
	method_started = false;
	local_offset = 0;
	member_offset = 0;
    next_instr = 0;
    max_instr = 0;
	method = NULL;
	fclass = NULL;
	method_name = NULL;
    class_name = NULL;
    var_name = NULL;
	array_index = 0;
	opcode = 0;
    actuals = 0;
	// initially has room for 16 symbols
	symbols = Array::create(0, 16, mach);
    return symbols != NULL;
}


bool Semantics::emit(short instruction)
{
    if (next_instr >= max_instr) {
        if (!grow()) return false;
    }
    if (next_instr < max_instr) {
        instructions->set_instr(next_instr++, instruction, 
                                mach->trace_flag);
    }
    return true;
}


bool Semantics::emit_at(long location, long instruction)
{
    assert(location < next_instr);
	if (instruction > 0x7FFF || instruction < -0x10000) {
		comp->report_error("virtual machine limitation: branch out of bounds");
		return false;
	}
    instructions->set_instr(location, (short) instruction, 
                            mach->trace_flag);
	return true;
}


bool Semantics::for_var(char *id)
{
	long index;  // variable index in frame
	// is this a local? look in method symbol table
	Symbol_ptr s = Symbol::create(id, mach);
    if (!method->get_localtable()->lookup(s, &index)) {
		comp->report_error("undeclared loop variable");
		return false;
	}
	// now index is the loop variable offset
	loop_stack->push((short) index, mach);
	return true;
}


bool Semantics::for_init()
{
	short index = loop_stack->pop(mach);
	// store the initial value
	must(emit(instr_compose(instr_store_local, (short) index)));
	loop_stack->push(index, mach);  // save for later
	return true;
}


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


bool Semantics::for_by(bool by_flag)
{
	if (!by_flag) { // no BY expression
		emit(instr_compose(instr_load_int, 1));
	}
	// generate instruction to push the loopcounter
	short index = loop_stack->pop(mach);
	loop_stack->push(index, mach);
	emit(instr_compose(instr_load_local, (short) index));
	emit(OP_JUMP);
	loop_stack->push(next_instr, mach);
	emit(0);
	// machine stack is to_value, by_value, loopcount (top)
	return true;
}


// for_end_range -- called after for-=-to-by-:
//
bool Semantics::for_end_range()
{
	long looptop = loop_stack->pop(mach);
	long loopvar = loop_stack->pop(mach);
	return emit(OP_LOOPINC) &&
	       emit((short) loopvar) &&
		   // jump instruction is pc += *pc,
		   //    next_instr = looptop + *looptop,
		   //    *looptop = next_instr - looptop
		   emit_at(looptop, next_instr - looptop) &&
		   emit(OP_LOOPTST) &&
		   // jump instruction is pc += *pc
		   //    looptop + 1 = next_instr + *next_instr
		   //    *next_instr = looptop + 1 - next_instr
		   emit(looptop + 1 - next_instr) &&
	       // break instructions should branch to here
		   emit(OP_POP2);
}


bool Semantics::for_array()
{
	short index = loop_stack->pop(mach);
	must(emit(instr_compose(instr_load_int, 0)));
	must(emit(OP_JUMP));
	loop_stack->push(next_instr, mach);
	return emit(0) &&
		   // store the initial value
		   emit(instr_compose(instr_store_local, index));
}


bool Semantics::for_end_elements()
{
	// stack has looptop-1
	// machine stack has array index, then array
	long looptop = loop_stack->pop(mach);
	return emit_at(looptop, next_instr - looptop) &&
		   emit(OP_LOOPNXT) &&
		   emit(looptop - next_instr);
}


bool Semantics::return_null()
{
    emit(OP_RETNULL);
    return true;
}


// unemit -- undo the previous emit, and return opcode
//
short Semantics::unemit()
{
    if (next_instr <= 0) return OP_NOOP;
    next_instr--;
    return instructions->get_instr(next_instr);
}

    
bool Semantics::grow()
{
    short newlen = 128;
    if (newlen <= max_instr) newlen = max_instr * 2;
    assert(max_instr < newlen);
    Code_ptr newinstr = Code::create(newlen, mach);
    if (!newinstr) return false;
	if (next_instr > 0) {
        for (long i = 0; i < next_instr; i++) {
            newinstr->set_instr(i, instructions->get_instr(i), false);
		}
	}
    instructions = newinstr;
    max_instr = newlen;
    return true;
}


// call prepares to invoke a function.
// The current opcode,actuals pair is pushed
// The new opcode is looked up and saved until
// after parameters are ready
//
bool Semantics::call(char *id)
{
	call_stack->push(opcode, mach);
	call_stack->push(actuals, mach);
	opcode = builtin(id, &actuals);
	if (opcode == 0) {
	    long index = insert_symbol(id);
	    assert(index >= 0 && index < 2048);
	    emit(instr_compose(instr_local_frame, (short) index));
	}
	return true;
}


bool Semantics::method_call(char *id)
{
	call_stack->push(opcode, mach);
	call_stack->push(actuals, mach);
    opcode = builtin_method(id, &actuals);
    if (opcode == 0) {
	    long index = insert_symbol(id);
	    assert(index >= 0 && index < 2048);
	    opcode = instr_compose(instr_frame, (short) index);
    }
    return true;
}


bool Semantics::class_start(char *class_name, char *super_name)
{
	fclass = FClass::create(mach);
	if (!fclass) return false;
	Symbol_ptr s = Symbol::create(class_name, mach);
	mach->push(s);
	FClass_ptr probe = mach->class_lookup(s);
	if (probe) {
		comp->report_error("class is already defined");
		mach->pop();
		fclass = NULL;
		return false;
	}
	mach->class_add(s, fclass);
	mach->pop();
	if (super_name[0]) {
		s = Symbol::create(super_name, mach);
		FClass_ptr super = mach->class_lookup(s);
		if (!super) {
			comp->report_error("super class is undefined");
			fclass = NULL;
			return false;
		}
		fclass->init_super(super);
		member_offset = super->get_inst_slots();
	} else {
		member_offset = 1; // all objects have class pointer
	}
	class_started = true;
	return true;
}


bool Semantics::method_start()
{
    method_started = true;
    local_offset = 0;
    return true;
}


bool Semantics::method_end()
{
	emit(instr_compose(instr_op, OP_RETNULL));
	// copy the code vector to the method
    Code_ptr newinstr = Code::create(next_instr, mach);
    if (!newinstr) return false;
    for (long i = 0; i < next_instr; i++) {
        newinstr->set_instr(i, instructions->get_instr(i), false);
	}
    int len = 1;
    if (mach->trace_flag) {
        for (i = 0; i < next_instr; i += len) {
            char text[64];
            trace(newinstr->disassemble(i, newinstr->get_instr(i), 
                                        newinstr->get_instr(i + 1), text, 
                                        &len, method));
        }
    }
	method->set_code(newinstr, mach);
	method = NULL;
	method_started = false;
	next_instr = 0;
	return true;
}


bool Semantics::method_name_is(char *name)
{
	method_name = Symbol::create(name, mach);
    method = Method::create(method_name, mach);
    if (class_started) { // insert method in the class
		fclass->enter_method(method_name, method, mach);
		method->set_fclass(fclass, mach);
	} else { // attach method to symbol
        method_name->set_function(method, mach);
        method->set_fclass(NULL, mach);
    }
    // add symbols to method:
   	method->init_symbols(symbols, mach);
	if (mach->trace_flag)
        trace("method_name_is: symbol name is %s\n", 
		      method_name->get_name()->get_string());
    return true;
}


bool Semantics::begin_formals()
{
    formal_type = FORMAL_REQUIRED;
    return true;
}


bool Semantics::set_formal_type(short ft)
{
    if (ft < formal_type) {
    	comp->report_error("formal type out of order");
        return false;
    }
    formal_type = ft;
    return true;
}


bool Semantics::formal_is(char *name)
{
	// convert the name to a symbol in this class
	var_name = Symbol::create(name, mach);
    // position the stack above the parameter:
	method->set_stack_offset(1 + method->get_stack_offset());
    switch (formal_type) {
      case FORMAL_OPTIONAL:
        method->set_optionals(1 + method->get_optionals());
        // no break, fall through to increment parameters too!
      case FORMAL_REQUIRED:
        method->set_parameters(1 + method->get_parameters());
        break;
      case FORMAL_KEYWORD:
        method->set_keywords(1 + method->get_keywords());
        break;
      case FORMAL_REST:
        method->set_rest_flag(true);
        break;
      case FORMAL_DICTIONARY:
        method->set_dict_flag(true);
        break;
    }
        
    return method->get_localtable()->insert_var(var_name, local_offset++, mach);
}


bool Semantics::default_value(FVal v)
{
    // first see if there is an optionals array:
    Array_ptr defaults = method->get_default();
    if (!defaults) {
        defaults = Array::create(1, 1, mach);
        method->set_default(defaults);
    }
    // this new value is for local_offset-1, but the defaults start
    // at parameters - optionals
    long index = local_offset - 1 - 
        (method->get_parameters() - method->get_optionals());
    // make sure array is long enough:
    while (defaults->get_array_len() <= index) {
        defaults->append(NULL, mach);
    }
    defaults->set_fastref(index, v, mach);
    return true;
}


bool Semantics::end_of_formals()
{
    // signature is number of formals
    // stack_offset is number of formals + locals
	// frame_slots is stack_offset + maximum stack size
	method->set_frame_slots(method->get_stack_offset() + 
							EXPR_STACK_MAX);
    return true;
}


bool Semantics::id(char *id)
{
	Symbol_ptr s = Symbol::create(id, mach);
	long index; // variable index in frame
	Method_ptr mp;
	mach->push(s);
	// is this a local? look in method symbol table
    if (method->get_localtable()->lookup(s, &index)) {
		must(emit(instr_compose(instr_load_local, (short) index)));
	} else if (fclass &&
               fclass->get_symboltable()->lookup(s, &mp, &index) &&
			   mp == NULL) {
		must(emit(instr_compose(instr_load_instvar, (short) index)));
	} else { // load value from a global
		index = insert_symbol(id);
		must(emit(instr_compose(instr_load_global, (short) index)));
	}
	mach->pop();
	return true;
}


bool Semantics::assign_id(char *id)
{
	Symbol_ptr s = Symbol::create(id, mach);
	long index; // variable index in frame
	Method_ptr mp;

⌨️ 快捷键说明

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