Exemplo n.º 1
0
void sdf_select_instance(const char*celltype, const char*cellinst)
{
      char buffer[128];

	/* First follow the hierarchical parts of the cellinst name to
	   get to the cell that I'm looking for. */
      vpiHandle scope = sdf_scope;
      const char*src = cellinst;
      const char*dp;
      while ( (dp=strchr(src, '.')) ) {
	    int len = dp - src;
	    assert(len < sizeof buffer);
	    strncpy(buffer, src, len);
	    buffer[len] = 0;

	    vpiHandle tmp_scope = find_scope(scope, buffer);
	    if (tmp_scope == 0) {
		  vpi_printf("SDF WARNING: Cannot find %s in %s?\n",
			     buffer, vpi_get_str(vpiName,scope));
		  break;
	    }
	    assert(tmp_scope);
	    scope = tmp_scope;

	    src = dp + 1;
      }

	/* Now find the cell. */
      if (src[0] == 0)
	    sdf_cur_cell = sdf_scope;
      else
	    sdf_cur_cell = find_scope(scope, src);
      if (sdf_cur_cell == 0) {
	    vpi_printf("SDF WARNING: Unable to find %s in current scope\n",
		       cellinst);
	    return;
      }

	/* The scope that matches should be a module. */
      if (vpi_get(vpiType,sdf_cur_cell) != vpiModule) {
	    vpi_printf("SDF ERROR: Scope %s in %s is not a module.\n",
		       cellinst, vpi_get_str(vpiName,sdf_scope));
      }

	/* The matching scope (a module) should have the expected type. */
      if (strcmp(celltype,vpi_get_str(vpiDefName,sdf_cur_cell)) != 0) {
	    vpi_printf("SDF ERROR: Module %s in %s is not a %s; "
		       "it is an %s\n", cellinst,
		       vpi_get_str(vpiName,sdf_scope), celltype,
		       vpi_get_str(vpiDefName,sdf_cur_cell));
      }

}
Exemplo n.º 2
0
void check_main(sym_table *table) {
    scope *m = find_scope("main", table);
    if (m == NULL) {
        print_missing_main_error();
        isValid = FALSE;
    }
}
Exemplo n.º 3
0
void
analyse_function(Function *f, sym_table *prog, char *scope_id, int line_no) {
    //Find the scope of the function
    scope *called = find_scope(f->id, prog);

    //Find the scope
    if (!called) {
        //Ooops this is an error. Report it.
        print_undefined_proc_call_error(f, line_no);
        isValid = FALSE;
        return;
    }

    Params *fcallee = (Params *) called->params;
    Exprs *fcaller = f->args;
    //Check number of variables
    int call_no = count_list((void *)fcaller);
    int expect_no = count_list((void *)fcallee);

    if (call_no != expect_no) {
        print_func_pmismatch_error(f, fcallee, line_no, expect_no, call_no);
        isValid = FALSE;
    } else {
        //Go through each variable and try match. We know these are the same
        //lenght now.
        int par_num = 1;
        while (fcallee != NULL) {
            Expr *e = fcaller->first;
            Param *p = fcallee->first;
            Type caller = get_expr_type(e, NULL, prog, scope_id, line_no);
            if (caller != p->type && p->ind == VAL_IND) {
                if ((caller == INT_TYPE) && (p->type == FLOAT_TYPE)) {
                    // This is valid, we can cast an int val into a float val
                } else {
                    //Then the parameter calls are incorrect
                    print_func_ptype_error(par_num, caller,
                                           p->type, f, line_no);
                    isValid = FALSE;
                }
            } else if (caller != p->type && p->ind == REF_IND) {
                if ((caller == FLOAT_TYPE) && (p->type == INT_TYPE)) {
                    // This is valid, we can cast an int into a float to store
                    // in the ref.
                } else {
                    //Then the parameter calls are incorrect
                    print_func_ptype_error(par_num, caller,
                                           p->type, f, line_no);
                    isValid = FALSE;
                }
            } else if (caller != p->type && caller != INVALID_TYPE) {
                //Then the parameter calls are incorrect
                print_func_ptype_error(par_num, caller, p->type, f, line_no);
                isValid = FALSE;
            }
            fcallee = fcallee->rest;
            fcaller = fcaller->rest;
            par_num ++;
        }
    }
}
Exemplo n.º 4
0
Walker::ApplyStatus smp_c_for_statement_walker::operator () (SuifObject *x) {
    SuifEnv *the_env = get_env();
    CForStatement *c_for_stmt = to<CForStatement>(x);

    BrickAnnote *loop_label_annote = to<BrickAnnote>(c_for_stmt->lookup_annote_by_name("c_for_label"));
    StringBrick *loop_label_brick = to<StringBrick>(loop_label_annote->get_brick(0));
    String current_loop_label = loop_label_brick->get_value();

    if (current_loop_label != loop_label_argument)
        return Walker::Continue;

    Statement *body = c_for_stmt->get_body();
    if (body) {

        VariableSymbol* loop_counter = get_c_for_basic_induction_variable(c_for_stmt);

        VariableSymbol* strip_loop_counter = new_anonymous_variable(the_env, find_scope(c_for_stmt), loop_counter->get_type());
        name_variable(strip_loop_counter);

        // step size of the strip is the step size of the original loop
        int strip_step_size = get_c_for_step(c_for_stmt);

        c_for_stmt->set_body(0);

        CForStatement* strip = make_strip(the_env, strip_loop_counter, strip_size, strip_step_size, body);
        c_for_stmt->set_body(strip);

        set_c_for_step(c_for_stmt, strip_size);

        smp_load_variable_expression_walker walker(the_env, loop_counter, strip_loop_counter);
        body->walk(walker);

    }
    return Walker::Truncate;
}
Walker::ApplyStatus multi_way_branch_statement_compactor::operator () (SuifObject *x)
    {
    MultiWayBranchStatement *the_case = to<MultiWayBranchStatement>(x);

    // is the table already compact?

    if (is_compact(the_case))
       return Walker::Continue;

    SymbolTable *scope = find_scope(x);
    if (!scope)
	return Walker::Continue;

    CodeLabelSymbol *default_lab =  the_case->get_default_target();

    // very special case - the case list is empty, so just jump to the default label

    if (the_case->get_case_count() == 0) {
	Statement *replacement = create_jump_statement(get_env(),default_lab);
	the_case->get_parent()->replace(the_case,replacement);
    	set_address(replacement);
    	return Walker::Replaced;
	}

    StatementList *replacement = create_statement_list(get_env());

    Expression *operand = the_case->get_decision_operand ();

    remove_suif_object(operand);

    DataType *type = operand->get_result_type();
    VariableSymbol *decision = create_variable_symbol(get_env(),get_type_builder(get_env())->get_qualified_type(type));
    scope->add_symbol(decision);

    replacement->append_statement(create_store_variable_statement(get_env(),decision,operand));

    the_case->set_default_target(0);
    MultiWayGroupList jump_list(get_env(),default_lab,decision);;
    
    Iter<MultiWayBranchStatement::case_pair > iter = the_case->get_case_iterator();
    while (iter.is_valid()) {
	MultiWayBranchStatement::case_pair pair = iter.current();
	jump_list.add_element(pair.first,pair.second);
	iter.next();
	}
    // we have built the new structure, now need to generate code for it

    jump_list.generate_code(replacement);
    
    the_case->get_parent()->replace(the_case,replacement);
    set_address(replacement);
    return Walker::Replaced;
    }
Exemplo n.º 6
0
static const slang_variable_scope *
find_scope(const slang_variable_scope *s, slang_atom name)
{
   GLuint i;
   for (i = 0; i < s->num_variables; i++) {
      if (s->variables[i]->a_name == name)
         return s;
   }
   if (s->outer_scope)
      return find_scope(s->outer_scope, name);
   else
      return NULL;
}
Exemplo n.º 7
0
void check_unused_symbols(sym_table *table, Program *prog) {
    //For each proc get it's symbol table, then for each symbol
    //Map against all symbols and check if used
    Procs *procs = prog->procedures;
    while (procs != NULL) {
        Proc *p = procs->first;
        //Get the scope
        scope *s = find_scope(p->header->id, table);

        //Now we want to map over the scope and print any duplicate errors.
        map_over_symbols(s->table, report_unused_symbols);
        procs = procs->rest;
    }
}
Exemplo n.º 8
0
NodeBuilder::NodeBuilder(ScopedObject* sobj) :
  _symtab(find_scope(sobj)),
  _suif_env(sobj->get_suif_env()),
  _type_builder(get_type_builder(_suif_env))
{}
Exemplo n.º 9
0
// analyzes the wasm opcode.
static int wasm_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
	ut64 addr2 = UT64_MAX;
	int i;
	WasmOp wop = {0};
	memset (op, '\0', sizeof (RAnalOp));
	int ret = wasm_dis (&wop, data, len);
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->ptr = op->val = UT64_MAX;
	op->size = ret;
	op->addr = addr;
	op->sign = true;
	op->type = R_ANAL_OP_TYPE_UNK;
	op->id = wop.op;

	if (!wop.txt || !strncmp (wop.txt, "invalid", 7)) {
		op->type = R_ANAL_OP_TYPE_ILL;
		wasm_stack_ptr = 0;
		free (wop.txt);
		return -1;
	}
	if (wasm_stack_ptr >= WASM_STACK_SIZE) {
		wasm_stack_ptr = 0;
		op->type = R_ANAL_OP_TYPE_NULL;
		free (wop.txt);
		return -1;
	}
	switch (wop.op) {
	/* Calls here are using index instead of address */
	case WASM_OP_LOOP:
		addr2 = find_scope (addr + op->size, data + op->size, len - op->size, true);
		op->type = R_ANAL_OP_TYPE_NOP;
		if (addr2 != UT64_MAX && addr_old != addr) {
			//eprintf("0x%016x > stack %u (loop)\n", addr, wasm_stack_ptr);
			wasm_stack[wasm_stack_ptr].loop = addr;
			wasm_stack[wasm_stack_ptr].end = addr2;
			wasm_stack[wasm_stack_ptr].size = wop.len;
			wasm_stack_ptr++;
		}
		//op->fail = addr + op->size;
		break;
	case WASM_OP_BLOCK:
		op->type = R_ANAL_OP_TYPE_NOP;
		addr2 = find_scope (addr + op->size, data + op->size, len - op->size, true);
		if (addr2 != UT64_MAX && addr_old != addr) {
			//eprintf("0x%016x > stack %u (block)\n", addr, wasm_stack_ptr);
			wasm_stack[wasm_stack_ptr].loop = UT64_MAX;
			wasm_stack[wasm_stack_ptr].end = addr2;
			wasm_stack[wasm_stack_ptr].size = wop.len;
			wasm_stack_ptr++;
		}
		break;
	case WASM_OP_IF:
		op->type = R_ANAL_OP_TYPE_CJMP;
		op->jump = find_scope (addr + op->size, data + op->size, len - op->size, false);
		op->fail = addr + op->size;
		if (op->jump != UT64_MAX && addr_old != addr) {
			//eprintf("0x%016x > stack %u (if)\n", addr, wasm_stack_ptr);
			wasm_stack[wasm_stack_ptr].loop = UT64_MAX;
			wasm_stack[wasm_stack_ptr].end = op->fail;
			wasm_stack[wasm_stack_ptr].size = wop.len;
			wasm_stack_ptr++;
		}
		break;
	case WASM_OP_ELSE:
		op->type = R_ANAL_OP_TYPE_JMP;
		op->jump = find_scope (addr + op->size, data + op->size, len - op->size, false);
		break;
	case WASM_OP_I32REMS:
	case WASM_OP_I32REMU:
		op->type = R_ANAL_OP_TYPE_MOD;
		break;
	case WASM_OP_END:
		//eprintf("0x%016x < stack %u (end)\n", addr, wasm_stack_ptr);
		if (wasm_stack_ptr > 0) {
			op->type = R_ANAL_OP_TYPE_NOP;
			if (addr != UT64_MAX) {
				for (i = wasm_stack_ptr - 1; i > 0; i--) {
					if (wasm_stack[i].end == addr && wasm_stack[i].loop != UT64_MAX) {
						op->type = R_ANAL_OP_TYPE_CJMP;
						op->jump = wasm_stack[i].loop;
						op->fail = addr + op->size;
						break;
					}
				}
			}
			wasm_stack_ptr--;
		} else {
			// all wasm routines ends with an end.
			op->eob = true;
			op->type = R_ANAL_OP_TYPE_RET;
		}
		break;
	case WASM_OP_GETLOCAL:
	case WASM_OP_I32LOAD:
	case WASM_OP_I64LOAD:
	case WASM_OP_F32LOAD:
	case WASM_OP_F64LOAD:
	case WASM_OP_I32LOAD8S:
	case WASM_OP_I32LOAD8U:
	case WASM_OP_I32LOAD16S:
	case WASM_OP_I32LOAD16U:
	case WASM_OP_I64LOAD8S:
	case WASM_OP_I64LOAD8U:
	case WASM_OP_I64LOAD16S:
	case WASM_OP_I64LOAD16U:
	case WASM_OP_I64LOAD32S:
	case WASM_OP_I64LOAD32U:
		op->type = R_ANAL_OP_TYPE_LOAD;
		break;
	case WASM_OP_SETLOCAL:
	case WASM_OP_TEELOCAL:
		op->type = R_ANAL_OP_TYPE_STORE;
		break;
	case WASM_OP_I32EQZ:
	case WASM_OP_I32EQ:
	case WASM_OP_I32NE:
	case WASM_OP_I32LTS:
	case WASM_OP_I32LTU:
	case WASM_OP_I32GTS:
	case WASM_OP_I32GTU:
	case WASM_OP_I32LES:
	case WASM_OP_I32LEU:
	case WASM_OP_I32GES:
	case WASM_OP_I32GEU:
	case WASM_OP_I64EQZ:
	case WASM_OP_I64EQ:
	case WASM_OP_I64NE:
	case WASM_OP_I64LTS:
	case WASM_OP_I64LTU:
	case WASM_OP_I64GTS:
	case WASM_OP_I64GTU:
	case WASM_OP_I64LES:
	case WASM_OP_I64LEU:
	case WASM_OP_I64GES:
	case WASM_OP_I64GEU:
	case WASM_OP_F32EQ:
	case WASM_OP_F32NE:
	case WASM_OP_F32LT:
	case WASM_OP_F32GT:
	case WASM_OP_F32LE:
	case WASM_OP_F32GE:
	case WASM_OP_F64EQ:
	case WASM_OP_F64NE:
	case WASM_OP_F64LT:
	case WASM_OP_F64GT:
	case WASM_OP_F64LE:
	case WASM_OP_F64GE:
		op->type = R_ANAL_OP_TYPE_CMP;
		break;
	case WASM_OP_I64OR:
	case WASM_OP_I32OR:
		op->type = R_ANAL_OP_TYPE_OR;
		break;
	case WASM_OP_I64XOR:
	case WASM_OP_I32XOR:
		op->type = R_ANAL_OP_TYPE_XOR;
		break;
	case WASM_OP_I32CONST:
	case WASM_OP_I64CONST:
	case WASM_OP_F32CONST:
	case WASM_OP_F64CONST:
		op->type = R_ANAL_OP_TYPE_MOV;
		{
			ut8 arg = data[1];
			r_strbuf_setf (&op->esil, "4,sp,-=,%d,sp,=[4]", arg);
		}
		break;
	case WASM_OP_I64ADD:
	case WASM_OP_I32ADD:
	case WASM_OP_F32ADD:
	case WASM_OP_F64ADD:
		op->type = R_ANAL_OP_TYPE_ADD;
		break;
	case WASM_OP_I64SUB:
	case WASM_OP_I32SUB:
	case WASM_OP_F32SUB:
	case WASM_OP_F64SUB:
		op->type = R_ANAL_OP_TYPE_SUB;
		break;
	case WASM_OP_NOP:
		op->type = R_ANAL_OP_TYPE_NOP;
		r_strbuf_setf (&op->esil, "");
		break;
	case WASM_OP_CALL:
	case WASM_OP_CALLINDIRECT:
		op->type = R_ANAL_OP_TYPE_CALL;
		op->jump = get_cf_offset (anal, data);
		op->fail = addr + op->size;
		if (op->jump != UT64_MAX) {
			op->ptr = op->jump;
		}
		r_strbuf_setf (&op->esil, "4,sp,-=,0x%"PFMT64x",sp,=[4],0x%"PFMT64x",pc,=", op->fail, op->jump);
		break;
	case WASM_OP_BR:
		op->type = R_ANAL_OP_TYPE_JMP;
		set_br_jump(op, data, len - op->size);
		break;
	case WASM_OP_BRIF:
		op->fail = addr + op->size;
		op->type = R_ANAL_OP_TYPE_CJMP;
		set_br_jump(op, data, len - op->size);
		break;
	case WASM_OP_RETURN:
		// should be ret, but if there the analisys is stopped.
		op->type = R_ANAL_OP_TYPE_CRET;
	default:
		break;
	}
	op_old = wop.op;
	addr_old = addr;
	free (wop.txt);
	return op->size;
}
Exemplo n.º 10
0
void
slang_print_tree(const slang_operation *op, int indent)
{
   GLuint i;

   switch (op->type) {

   case SLANG_OPER_NONE:
      spaces(indent);
      printf("SLANG_OPER_NONE\n");
      break;

   case SLANG_OPER_BLOCK_NO_NEW_SCOPE:
      spaces(indent);
      printf("{ locals=%p  outer=%p\n", (void*)op->locals, (void*)op->locals->outer_scope);
      print_generic(op, NULL, indent+3);
      spaces(indent);
      printf("}\n");
      break;

   case SLANG_OPER_BLOCK_NEW_SCOPE:
      spaces(indent);
      printf("{{ // new scope  locals=%p outer=%p: ",
             (void *) op->locals,
             (void *) op->locals->outer_scope);
      for (i = 0; i < op->locals->num_variables; i++) {
         printf("%s ", (char *) op->locals->variables[i]->a_name);
      }
      printf("\n");
      print_generic(op, NULL, indent+3);
      spaces(indent);
      printf("}}\n");
      break;

   case SLANG_OPER_VARIABLE_DECL:
      assert(op->num_children == 0 || op->num_children == 1);
      {
         slang_variable *v;
         v = _slang_variable_locate(op->locals, op->a_id, GL_TRUE);
         if (v) {
            const slang_variable_scope *scope;
            spaces(indent);
            printf("DECL (locals=%p outer=%p) ", (void*)op->locals, (void*) op->locals->outer_scope);
            print_type(&v->type);
            printf(" %s (%p)", (char *) op->a_id,
                   (void *) find_var(op->locals, op->a_id));

            scope = find_scope(op->locals, op->a_id);
            printf(" (in scope %p) ", (void *) scope);
            assert(scope);
            if (op->num_children == 1) {
               printf(" :=\n");
               slang_print_tree(&op->children[0], indent + 3);
            }
            else if (v->initializer) {
               printf(" := INITIALIZER\n");
               slang_print_tree(v->initializer, indent + 3);
            }
            else {
               printf(";\n");
            }
            /*
            spaces(indent);
            printf("TYPE: ");
            print_type(&v->type);
            spaces(indent);
            printf("ADDR: %d  size: %d\n", v->address, v->size);
            */
         }
         else {
            spaces(indent);
            printf("DECL %s (anonymous variable!!!!)\n", (char *) op->a_id);
         }
      }
      break;

   case SLANG_OPER_ASM:
      spaces(indent);
      printf("ASM: %s at %p locals=%p outer=%p\n",
             (char *) op->a_id,
             (void *) op,
             (void *) op->locals,
             (void *) op->locals->outer_scope);
      print_generic(op, "ASM", indent+3);
      break;

   case SLANG_OPER_BREAK:
      spaces(indent);
      printf("BREAK\n");
      break;

   case SLANG_OPER_CONTINUE:
      spaces(indent);
      printf("CONTINUE\n");
      break;

   case SLANG_OPER_DISCARD:
      spaces(indent);
      printf("DISCARD\n");
      break;

   case SLANG_OPER_RETURN:
      spaces(indent);
      printf("RETURN\n");
      if (op->num_children > 0)
         slang_print_tree(&op->children[0], indent + 3);
      break;

   case SLANG_OPER_LABEL:
      spaces(indent);
      printf("LABEL %s\n", (char *) op->a_id);
      break;

   case SLANG_OPER_EXPRESSION:
      spaces(indent);
      printf("EXPR:  locals=%p outer=%p\n",
             (void *) op->locals,
             (void *) op->locals->outer_scope);
      /*print_generic(op, "SLANG_OPER_EXPRESSION", indent);*/
      slang_print_tree(&op->children[0], indent + 3);
      break;

   case SLANG_OPER_IF:
      spaces(indent);
      printf("IF\n");
      slang_print_tree(&op->children[0], indent + 3);
      spaces(indent);
      printf("THEN\n");
      slang_print_tree(&op->children[1], indent + 3);
      spaces(indent);
      printf("ELSE\n");
      slang_print_tree(&op->children[2], indent + 3);
      spaces(indent);
      printf("ENDIF\n");
      break;

   case SLANG_OPER_WHILE:
      assert(op->num_children == 2);
      spaces(indent);
      printf("WHILE LOOP: locals = %p\n", (void *) op->locals);
      indent += 3;
      spaces(indent);
      printf("WHILE cond:\n");
      slang_print_tree(&op->children[0], indent + 3);
      spaces(indent);
      printf("WHILE body:\n");
      slang_print_tree(&op->children[1], indent + 3);
      indent -= 3;
      spaces(indent);
      printf("END WHILE LOOP\n");
      break;

   case SLANG_OPER_DO:
      spaces(indent);
      printf("DO LOOP: locals = %p\n", (void *) op->locals);
      indent += 3;
      spaces(indent);
      printf("DO body:\n");
      slang_print_tree(&op->children[0], indent + 3);
      spaces(indent);
      printf("DO cond:\n");
      slang_print_tree(&op->children[1], indent + 3);
      indent -= 3;
      spaces(indent);
      printf("END DO LOOP\n");
      break;

   case SLANG_OPER_FOR:
      spaces(indent);
      printf("FOR LOOP: locals = %p\n", (void *) op->locals);
      indent += 3;
      spaces(indent);
      printf("FOR init:\n");
      slang_print_tree(&op->children[0], indent + 3);
      spaces(indent);
      printf("FOR condition:\n");
      slang_print_tree(&op->children[1], indent + 3);
      spaces(indent);
      printf("FOR step:\n");
      slang_print_tree(&op->children[2], indent + 3);
      spaces(indent);
      printf("FOR body:\n");
      slang_print_tree(&op->children[3], indent + 3);
      indent -= 3;
      spaces(indent);
      printf("ENDFOR\n");
      /*
      print_generic(op, "FOR", indent + 3);
      */
      break;

   case SLANG_OPER_VOID:
      spaces(indent);
      printf("(oper-void)\n");
      break;

   case SLANG_OPER_LITERAL_BOOL:
      spaces(indent);
      printf("LITERAL (");
      for (i = 0; i < op->literal_size; i++)
         printf("%s ", op->literal[0] ? "TRUE" : "FALSE");
      printf(")\n");

      break;

   case SLANG_OPER_LITERAL_INT:
      spaces(indent);
      printf("LITERAL (");
      for (i = 0; i < op->literal_size; i++)
         printf("%d ", (int) op->literal[i]);
      printf(")\n");
      break;

   case SLANG_OPER_LITERAL_FLOAT:
      spaces(indent);
      printf("LITERAL (");
      for (i = 0; i < op->literal_size; i++)
         printf("%f ", op->literal[i]);
      printf(")\n");
      break;

   case SLANG_OPER_IDENTIFIER:
      {
         const slang_variable_scope *scope;
         spaces(indent);
         if (op->var && op->var->a_name) {
            scope = find_scope(op->locals, op->var->a_name);
            printf("VAR %s  (in scope %p)\n", (char *) op->var->a_name,
                   (void *) scope);
            assert(scope);
         }
         else {
            scope = find_scope(op->locals, op->a_id);
            printf("VAR' %s  (in scope %p) locals=%p outer=%p\n",
                   (char *) op->a_id,
                   (void *) scope,
                   (void *) op->locals,
                   (void *) op->locals->outer_scope);
            assert(scope);
         }
      }
      break;

   case SLANG_OPER_SEQUENCE:
      print_generic(op, "COMMA-SEQ", indent+3);
      break;

   case SLANG_OPER_ASSIGN:
      spaces(indent);
      printf("ASSIGNMENT  locals=%p outer=%p\n",
             (void *) op->locals,
             (void *) op->locals->outer_scope);
      print_binary(op, ":=", indent);
      break;

   case SLANG_OPER_ADDASSIGN:
      spaces(indent);
      printf("ASSIGN\n");
      print_binary(op, "+=", indent);
      break;

   case SLANG_OPER_SUBASSIGN:
      spaces(indent);
      printf("ASSIGN\n");
      print_binary(op, "-=", indent);
      break;

   case SLANG_OPER_MULASSIGN:
      spaces(indent);
      printf("ASSIGN\n");
      print_binary(op, "*=", indent);
      break;

   case SLANG_OPER_DIVASSIGN:
      spaces(indent);
      printf("ASSIGN\n");
      print_binary(op, "/=", indent);
      break;

	/*SLANG_OPER_MODASSIGN,*/
	/*SLANG_OPER_LSHASSIGN,*/
	/*SLANG_OPER_RSHASSIGN,*/
	/*SLANG_OPER_ORASSIGN,*/
	/*SLANG_OPER_XORASSIGN,*/
	/*SLANG_OPER_ANDASSIGN,*/
   case SLANG_OPER_SELECT:
      spaces(indent);
      printf("SLANG_OPER_SELECT n=%d\n", op->num_children);
      assert(op->num_children == 3);
      slang_print_tree(&op->children[0], indent+3);
      spaces(indent);
      printf("?\n");
      slang_print_tree(&op->children[1], indent+3);
      spaces(indent);
      printf(":\n");
      slang_print_tree(&op->children[2], indent+3);
      break;

   case SLANG_OPER_LOGICALOR:
      print_binary(op, "||", indent);
      break;

   case SLANG_OPER_LOGICALXOR:
      print_binary(op, "^^", indent);
      break;

   case SLANG_OPER_LOGICALAND:
      print_binary(op, "&&", indent);
      break;

   /*SLANG_OPER_BITOR*/
   /*SLANG_OPER_BITXOR*/
   /*SLANG_OPER_BITAND*/
   case SLANG_OPER_EQUAL:
      print_binary(op, "==", indent);
      break;

   case SLANG_OPER_NOTEQUAL:
      print_binary(op, "!=", indent);
      break;

   case SLANG_OPER_LESS:
      print_binary(op, "<", indent);
      break;

   case SLANG_OPER_GREATER:
      print_binary(op, ">", indent);
      break;

   case SLANG_OPER_LESSEQUAL:
      print_binary(op, "<=", indent);
      break;

   case SLANG_OPER_GREATEREQUAL:
      print_binary(op, ">=", indent);
      break;

   /*SLANG_OPER_LSHIFT*/
   /*SLANG_OPER_RSHIFT*/
   case SLANG_OPER_ADD:
      print_binary(op, "+", indent);
      break;

   case SLANG_OPER_SUBTRACT:
      print_binary(op, "-", indent);
      break;

   case SLANG_OPER_MULTIPLY:
      print_binary(op, "*", indent);
      break;

   case SLANG_OPER_DIVIDE:
      print_binary(op, "/", indent);
      break;

   /*SLANG_OPER_MODULUS*/
   case SLANG_OPER_PREINCREMENT:
      spaces(indent);
      printf("PRE++\n");
      slang_print_tree(&op->children[0], indent+3);
      break;

   case SLANG_OPER_PREDECREMENT:
      spaces(indent);
      printf("PRE--\n");
      slang_print_tree(&op->children[0], indent+3);
      break;

   case SLANG_OPER_PLUS:
      spaces(indent);
      printf("SLANG_OPER_PLUS\n");
      break;

   case SLANG_OPER_MINUS:
      spaces(indent);
      printf("SLANG_OPER_MINUS\n");
      break;

   /*SLANG_OPER_COMPLEMENT*/
   case SLANG_OPER_NOT:
      spaces(indent);
      printf("NOT\n");
      slang_print_tree(&op->children[0], indent+3);
      break;

   case SLANG_OPER_SUBSCRIPT:
      spaces(indent);
      printf("SLANG_OPER_SUBSCRIPT locals=%p outer=%p\n",
             (void *) op->locals,
             (void *) op->locals->outer_scope);
      print_generic(op, NULL, indent+3);
      break;

   case SLANG_OPER_CALL:
#if 0
         slang_function *fun
            = _slang_function_locate(A->space.funcs, oper->a_id,
                                     oper->children,
                                     oper->num_children, &A->space, A->atoms);
#endif
      spaces(indent);
      printf("CALL %s(\n", (char *) op->a_id);
      for (i = 0; i < op->num_children; i++) {
         slang_print_tree(&op->children[i], indent+3);
         if (i + 1 < op->num_children) {
            spaces(indent + 3);
            printf(",\n");
         }
      }
      spaces(indent);
      printf(")\n");
      break;

   case SLANG_OPER_METHOD:
      spaces(indent);
      printf("METHOD CALL %s.%s\n", (char *) op->a_obj, (char *) op->a_id);
      break;

   case SLANG_OPER_FIELD:
      spaces(indent);
      printf("FIELD %s of\n", (char*) op->a_id);
      slang_print_tree(&op->children[0], indent+3);
      break;

   case SLANG_OPER_POSTINCREMENT:
      spaces(indent);
      printf("POST++\n");
      slang_print_tree(&op->children[0], indent+3);
      break;

   case SLANG_OPER_POSTDECREMENT:
      spaces(indent);
      printf("POST--\n");
      slang_print_tree(&op->children[0], indent+3);
      break;

   default:
      printf("unknown op->type %d\n", (int) op->type);
   }

}