def assign_stmt(node): (ASSIGN, oper, rexp) = node assert_match(ASSIGN, 'assign') (OPER, lexp, fix) = oper if lexp[0] == 'id': #('id', name) # grab everything we know about variable named id name = lexp[1] (sym_type, data_type, val) = state.symbol_table.lookup_sym(name) # compute rhs value of assignment stmt (t1, v1, p1) = walk(oper) (t2, v2, p2) = walk(rexp) if not safe_assign(data_type, t2): raise ValueError(\ "a value of type {} cannot be assigned to the variable {} of type {}"\ .format(t2,name,data_type)) # update symbol table with new value value = (sym_type, data_type, conversion_fun(data_type, t2)(v2)) state.symbol_table.update_sym(name, value) handle_suffix(p1 + p2) elif lexp[0] == 'array-access': # ('array-access', id, exp) # grab everything we know about the array named id name = lexp[1] (ARRAY_VAL, data_type, memory) = state.symbol_table.lookup_sym(name) if ARRAY_VAL != 'array-val': # make sure we are seeing an array-val raise ValueError("cannot index non-array {}".format(name)) (ARRAY_TYPE, size_val, elem_type) = data_type assert_match(ARRAY_TYPE, 'array-type') # grab the index expression value and do error checking (ix_type, ix_val) = walk(lexp[2]) if ix_type[0] != 'integer': raise ValueError("illegal index value {}".format(ix_val)) if ix_val not in range(size_val): raise ValueError("index {} for {} out of bounds".format( ix_val, name)) # compute the rhs value of the assignment stmt (t1, v1, p1) = walk(lexp) (t2, v2, p2) = walk(rexp) if not safe_assign(elem_type, t2): raise ValueError(\ "a value of type {} cannot be assigned to the elements of {} of type {}"\ .format(t2,name,elem_type)) # update the memory cell for this array access memory[ix_val] = conversion_fun(elem_type, t2)(v2) handle_suffix(p1 + p2) else: raise ValueError("illegal left side {} of assignment".format(lexp[0]))
def declare_array(self, sym, array_type, init_val): ''' declare an array in the current scope. ''' # first we need to check whether the symbol was already declared # at this scope if sym in self.scoped_symtab[CURR_SCOPE]: raise ValueError("symbol {} already declared".format(sym)) # unpack the array type (ARRAY_TYPE, size, elem_type) = array_type # look at the initializer if init_val[0] == 'nil': memory = [ conversion_fun(elem_type, ('integer', ))(0) for i in range(size) ] else: memory = _compute_array_initializer(elem_type, init_val) if len(memory) != size: raise ValueError("size of initializer does not match array {}"\ .format(sym)) # declare symbol in current scope val = ('array-val', array_type, memory) self.scoped_symtab[CURR_SCOPE].update({sym: val})
def declare_scalar(self, sym, data_type, init_val): ''' declare a scalar in the current scope. ''' # first we need to check whether the symbol was already declared # at this scope if sym in self.scoped_symtab[CURR_SCOPE]: raise ValueError("symbol {} already declared".format(sym)) # look at init value if init_val[0] == 'nil': init_val = conversion_fun(data_type, ('integer', ))(0) else: (t, v, post) = init_val if safe_assign(data_type, t): init_val = conversion_fun(data_type, t)(v) else: raise ValueError("illegal init value {}".format(v)) # enter the symbol with its value in the current scope val = ('scalar-val', data_type, init_val) self.scoped_symtab[CURR_SCOPE].update({sym: val})
def _compute_array_initializer(elem_type, initializer): ''' array initializers come in two flavors: (a) as a list of values (b) as an expression that represent sufficient init values for the array here we check and compute the actual memory for the array. ''' if initializer[0] == 'nil': return [] elif initializer[0] == 'seq': (SEQ, (t, v), next) = initializer if not safe_assign(elem_type, t): raise ValueError(\ "illegal array initializer {}"\ .format(v)) return [conversion_fun(elem_type, t)(v)] + _compute_array_initializer( elem_type, next) elif initializer[0][0] == 'array-type': return list(initializer[1]) else: raise ValueError("illegal array initializer {}".format(initializer))