Esempio n. 1
0
ilist ins0(instruction ins, fncode fn)
/* Effects: Adds instruction ins to code of 'fn'.
   Modifies: fn
*/
{
  switch (ins)
    {
    case OPmexec4 ... OPmexec4 + 15: 
      adjust_depth(-(ins - OPmexec4), fn);
      break;
    case OPmset:
      adjust_depth(-2, fn);
      break;
    case OPmpop: case OPmeq: case OPmne: case OPmref:
    case OPmlt: case OPmle: case OPmgt: case OPmge: case OPmadd: case OPmsub: 
    case OPmmultiply: case OPmdivide: case OPmremainder: case OPmbitand: 
    case OPmbitor: case OPmbitxor: case OPmshiftleft: case OPmshiftright:
      adjust_depth(-1, fn);
      break;
    case OPmcst: case OPmundefined: case OPmint3 ... OPmint3 + 7:
      adjust_depth(1, fn);
      break;
    case OPmreturn: case OPmnegate: case OPmbitnot: case OPmnot:
    case OPmscheck4 ... OPmscheck4 + 15:
      break;
    default:
      fprintf(stderr, "unknown instruction %d\n", ins);
      assert(0);
    }
  return add_ins(ins, 0, fn);
}
Esempio n. 2
0
void insprim(instruction ins, int nargs, fncode fn)
/* Effects: Adds instruction ins to code of 'fn'.
   Modifies: fn
*/
{
  adjust_depth(-(nargs - 1), fn);
  add_ins(ins, 0, fn);
}
Esempio n. 3
0
static void wexit_code(void *_data, fncode fn)
{
  struct whiledata *wdata = _data;

  set_label(wdata->exitlab, fn);
  generate_component(component_undefined, fn);
  branch(op_branch1, wdata->endlab, fn);
  adjust_depth(-1, fn);
}
Esempio n. 4
0
static void iff_code(void *_data, fncode fn)
{
  struct ifdata *data = _data;

  set_label(data->flab, fn);
  generate_component(data->failure, fn);
  branch(op_branch1, data->endlab, fn);
  adjust_depth(-1, fn);
}
Esempio n. 5
0
static void iff_code(void *_data, fncode fn)
{
  struct ifdata *data = _data;

  set_label(data->flab, fn);
  generate_component(data->failure, NULL, data->discard, fn);
  branch(OPmba3, data->endlab, fn);
  if (!data->discard)
    adjust_depth(-1, fn);
}
Esempio n. 6
0
void ins2(instruction ins, int arg2, fncode fn)
/* Effects: Adds instruction ins to code of 'fn'.
     The instruction has a two byte argument (arg2), stored in big-endian
     format.
   Modifies: fn
*/
{
  switch (ins)
    {
    case OPmreadg:
      adjust_depth(1, fn);
      break;
    case OPmwriteg:
      break;
    case OPmexecg4 ... OPmexecg4 + 15: 
      adjust_depth(-(ins - OPmexecg4) + 1, fn);
      break;
    default:
      assert(0);
    }
  add_ins(ins, 2, fn)->arg = arg2;
}
Esempio n. 7
0
u8 *ins_closure(value code, u16 clen, fncode fn)
/* Effects: Adds code for a 'clen' variable closure with function 'code'
     to 'fn'
   Returns: Pointer to area to add the closure variables
*/
{
  ilist cins = add_ins(OPmclosure, 1, fn);

  cins->arg = clen;
  cins->cst = add_constant(code, fn);
  cins->cvars = allocate(fnmemory(fn), clen * sizeof(*cins->cvars));
  adjust_depth(1, fn);

  return cins->cvars;
}
Esempio n. 8
0
static void generate_if(component condition, component success,
			component failure, fncode fn)
{
  struct ifdata ifdata;

  ifdata.slab = new_label(fn);
  ifdata.flab = new_label(fn);
  ifdata.endlab = new_label(fn);
  ifdata.success = success;
  ifdata.failure = failure;

  generate_condition(condition, ifdata.slab, ifs_code, &ifdata,
		     ifdata.flab, iff_code, &ifdata, fn);
  set_label(ifdata.endlab, fn);
  adjust_depth(1, fn);
}
Esempio n. 9
0
static void generate_while(component condition, component iteration, fncode fn)
{
  struct whiledata wdata;

  wdata.looplab = new_label(fn);
  wdata.mainlab = new_label(fn);
  wdata.exitlab = new_label(fn);
  wdata.endlab = new_label(fn);
  wdata.code = iteration;

  env_start_loop();
  set_label(wdata.looplab, fn);
  generate_condition(condition, wdata.mainlab, wmain_code, &wdata,
		     wdata.exitlab, wexit_code, &wdata, fn);
  set_label(wdata.endlab, fn);
  env_end_loop();
  adjust_depth(1, fn);
}
Esempio n. 10
0
void branch(instruction abranch, label to, fncode fn)
/* Effects: Adds a branch instruction to lavel 'to' to instruction 
     list 'next'.
     A 1 byte offset is added at this stage.
   Requires: 'branch' be a 1 byte branch instruction.
   Modifies: fn
*/
{
  switch (abranch)
    {
    case OPmba3: break;
    case OPmbt3: case OPmbf3:
      adjust_depth(-1, fn);
      break;
    default: assert(0);
    }
  /* assume a small offset by default */
  add_ins(abranch, 0, fn)->to = to;
}
Esempio n. 11
0
void ins1(instruction ins, int arg1, fncode fn)
/* Effects: Adds instruction ins to code of 'fn'.
     The instruction has one argument, arg1.
   Modifies: fn
*/
{
  switch (ins)
    {
    case OPmreadl: case OPmreadc: case OPmclosure:
      adjust_depth(1, fn);
      break;
    case OPmexitn: case OPmclearl: case OPmwritel: case OPmwritec:
    case OPmvcheck4 ... OPmvcheck4 + 15:
      /* Note: OPmexitn *MUST NOT* modify stack depth */
      break;
    default:
      assert(0);
    }
  add_ins(ins, 1, fn)->arg = arg1;
}
Esempio n. 12
0
void generate_if(component condition, component success, component failure,
		 bool discard, fncode fn)
{
  struct ifdata ifdata;

  ifdata.slab = new_label(fn);
  ifdata.flab = new_label(fn);
  ifdata.endlab = new_label(fn);
  ifdata.success = success;
  ifdata.failure = failure;
  ifdata.discard = discard;

  if (failure)
    generate_condition(condition, ifdata.slab, ifs_code, &ifdata,
		       ifdata.flab, iff_code, &ifdata, fn);
  else
    generate_condition(condition, ifdata.slab, ifs_code, &ifdata,
		       ifdata.endlab, NULL, NULL, fn);
  set_label(ifdata.endlab, fn);
  if (!discard)
    adjust_depth(1, fn);
}
Esempio n. 13
0
int main(int argc, char *argv[])
{
    coordinates coord;                   // Coodinates Structure
    depth depth;
    color  colorsIn[2048];               // Colors array
    int    numColors = 0;                // Number of colors to use in color array
    float  colorPower = .3;              // Power exponent to use for color selection
    int    colorStart = 0xFF0000, colorEnd = 0xFFFF00; // Default color gradient settings
    char   *filename = "mandelbrot.png"; // Default PNG output name
    int    i;                            // Misc variables
    bool   noWindow = false;             // Default flag for no-window mode

    // Set default coordinates before reading in args
    coord.x = -2;          // Default Start Coordinates
    coord.y = 2;
    coord.xR = 4;          // Default Range Coordinates
    coord.yR = 4;
    coord.width = -1;      // Invalid pixel size, to be set later
    coord.height = -1;
    depth.d = 100;         // Default Depth level of Mandelbrot Calculation
    depth.automatic = true;

    // Generate default gradient first
    genGradient(colorsIn, &numColors, colorStart, colorEnd);

    // Parse Arguments
    for (i=1; i<argc; i++)
     {
        if (strcmp(argv[i], "--width") == 0)
        {
            coord.width = arg_check_int(argc, argv, i, 1, 10);
            i++;
        }
        else if (strcmp(argv[i], "--height") == 0)
        {
            coord.height = arg_check_int(argc, argv, i, 1, 10);
            i++;
        }
        else if (strcmp(argv[i], "--depth") == 0)
        {
            depth.automatic = false;
            depth.d = arg_check_int(argc, argv, i, 1, 10);
            i++;
        }
        else if (strcmp(argv[i], "--coords") == 0)
        {
            coord.x  = arg_check_float(argc, argv, i, 1);
            coord.y  = arg_check_float(argc, argv, i, 2);
            coord.xR = arg_check_float(argc, argv, i, 3);
            coord.yR = arg_check_float(argc, argv, i, 4);
            i+=4;
        }
        else if (strcmp(argv[i], "--spectrum") == 0)
        {
            genSpectrum(colorsIn, &numColors);
	    colorPower = .7;
        }
        else if (strcmp(argv[i], "--random") == 0)
        {
            genRandom(colorsIn, &numColors);
	    colorPower = 1;
        }
        else if (strcmp(argv[i], "--gradient") == 0)
        {
            colorStart = arg_check_int(argc, argv, i, 1, 16);
            colorEnd = arg_check_int(argc, argv, i, 2, 16);
            genGradient(colorsIn, &numColors, colorStart, colorEnd);
            i+=2;
        }
        else if (strcmp(argv[i], "-o") == 0)
        {
            filename = argv[i+1];
            i++;
        }
        else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0 )
        {
            help();
        }
        else if (strcmp(argv[i], "-nw") == 0 )
        {
            noWindow = true;
        }
        else
        {
            errx(EXIT_FAILURE, "Unknown argument, \"%s\".", argv[i]);
        }
     }

    // Make proportional image if only one dimension is specified
    // Set to default width and height if not specified
    if      (coord.height < 0 && coord.width > 0) coord.height = coord.width  / coord.xR * coord.yR;
    else if (coord.height > 0 && coord.width < 0) coord.width  = coord.height / coord.yR * coord.xR;
    else if (coord.height < 0 && coord.width < 0) coord.width  = coord.height = 1024;

    coord.xS = coord.xR/coord.width;  // X Step Value
    coord.yS = coord.yR/coord.height; // Y Step Value

    // Create final array of colors to use that is scaled to the depth that is selected
    color colors[2048];
    scaleColor(colorsIn, colors, numColors, depth.d, colorPower);

    // If no window mode, just output file and exit
    if (noWindow)
    {
        generate_png(coord, depth.d, filename, colors, numColors);
        return 0;
    }

    // Set up SDL
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* Main_Window;
    SDL_Renderer* Main_Renderer;
    Main_Window = SDL_CreateWindow("Mandelbrot", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, coord.width, coord.height, SDL_WINDOW_RESIZABLE);
    Main_Renderer = SDL_CreateRenderer(Main_Window, -1, SDL_RENDERER_ACCELERATED);
    SDL_Texture *texture = SDL_CreateTexture(Main_Renderer, SDL_PIXELFORMAT_RGBX8888, SDL_TEXTUREACCESS_STREAMING, coord.width, coord.height);
    int pitch;
    void *pixels;
    if (SDL_LockTexture(texture, NULL, &pixels, &pitch) != 0)
        errx(EXIT_FAILURE, "SDL_LockTexture: %s", SDL_GetError());
    //uint32_t (*pixel)[coord.height][pitch/sizeof(uint32_t)] = pixels;

    // Set up struct for tracking mouse movement
    mouse mouseTracker;
    mouseTracker.down = false;

    //Main Loop
    int maxRender = 2;
    int needsRender = maxRender;
    while (1)
    {
        // Render Loop
        if (needsRender > 0)
        {
            uint32_t (*pixel)[coord.height][pitch/sizeof(uint32_t)] = pixels;

            //unsigned long long timer = utime(); //DEBUG - Start Timer
            float pixelSize = pow(2, --needsRender);
            //printf("%d %d\n", needsRender, pixelSize);

            coordinates scaledCoord;
            scaledCoord.width = coord.width / pixelSize;
            scaledCoord.height = coord.height / pixelSize;
            scaledCoord.x  = coord.x;
            scaledCoord.xR = coord.xR;
            scaledCoord.xS = scaledCoord.xR/scaledCoord.width;
            scaledCoord.y  = coord.y;
            scaledCoord.yR = coord.yR;
            scaledCoord.yS = scaledCoord.yR/scaledCoord.height;     // y step value
            SDL_Rect srcrect = {0, 0, scaledCoord.width, scaledCoord.height};

            for (int y=0; y<scaledCoord.height; y++)
                for (int x=0; x<scaledCoord.width; x++)
                {
                    double xValue = scaledCoord.x + (x * scaledCoord.xS);
                    double yValue = scaledCoord.y - (y * scaledCoord.yS);
                    int result = mandel(xValue, yValue, depth.d);

                    int finalColor = 0;
                    if (result != -1)
                        finalColor = colors[result].hex << 8;

                    (*pixel)[y][x] = finalColor;
                }

            SDL_UnlockTexture(texture);
            SDL_RenderCopy(Main_Renderer, texture, &srcrect, NULL);

            //printf("%llu - Finish Render\n", utime()-timer); //DEBUG - End Timer

            SDL_RenderPresent(Main_Renderer);
        }

        SDL_Event e;
        //SDL_WaitEvent(&e);
        if (SDL_WaitEventTimeout(&e, 10) == 0) continue;
        if (e.type == SDL_MOUSEWHEEL)
        {
            if (e.wheel.y > 0)
                coord_zoom(&coord, 1);
            else
                coord_zoom(&coord, -1);
            if (depth.automatic == true)
            {
                adjust_depth(&coord, &depth);
                scaleColor(colorsIn, colors, numColors, depth.d, colorPower);
            }
            needsRender = maxRender;
        }

        if (e.type == SDL_WINDOWEVENT)
            if (e.window.event == SDL_WINDOWEVENT_RESIZED)
            {
                // Adjust view to new size
                coord.width = e.window.data1;
                coord.height = e.window.data2;
                coord.xR = coord.width * coord.xS;
                coord.yR = coord.height * coord.yS;

                // Destroy old texture
                SDL_DestroyTexture(texture);

                // Make New Texture
                texture = SDL_CreateTexture(Main_Renderer, SDL_PIXELFORMAT_RGBX8888, SDL_TEXTUREACCESS_STREAMING, coord.width, coord.height);

                // Lock with new texture
                if (SDL_LockTexture(texture, NULL, &pixels, &pitch) != 0)
                    errx(EXIT_FAILURE, "SDL_LockTexture: %s", SDL_GetError());

                // Rerender
                needsRender = maxRender;
            }

        if (e.type == SDL_MOUSEBUTTONDOWN)
            if (e.button.state == SDL_PRESSED)
            {
                mouseTracker.mouseX = e.motion.x;
                mouseTracker.mouseY = e.motion.y;
                mouseTracker.coordX = coord.x;
                mouseTracker.coordY = coord.y;
                mouseTracker.down = true;
            }

        if (e.type == SDL_MOUSEBUTTONUP)
            if (e.button.state == SDL_RELEASED)
                mouseTracker.down = false;

        if (e.type == SDL_MOUSEMOTION && mouseTracker.down == true)
        {
            coord.x = mouseTracker.coordX + ((mouseTracker.mouseX - e.motion.x) * coord.xS);
            coord.y = mouseTracker.coordY - ((mouseTracker.mouseY - e.motion.y) * coord.yS);
            needsRender = maxRender;
        }

        if (e.type == SDL_KEYUP)
        {
            if (e.key.keysym.sym == SDLK_p)
                print_coords(&coord, &depth);
            if (e.key.keysym.sym == SDLK_s)
                generate_png(coord, depth.d, filename, colors, numColors);
            if (e.key.keysym.sym == SDLK_EQUALS || e.key.keysym.sym == SDLK_MINUS)
            {
                depth.automatic = false;
                if (e.key.keysym.sym == SDLK_EQUALS)
                    depth.d += 5;
                if (e.key.keysym.sym == SDLK_MINUS)
                    if (depth.d > 5) depth.d -= 5;
                scaleColor(colorsIn, colors, numColors, depth.d, colorPower);
                needsRender = maxRender;
            }
        }

        if (e.type == SDL_QUIT)
        {
            SDL_Log("Program quit after %i ticks", e.quit.timestamp);
            break;
        }
    }

    return 0;
}
Esempio n. 14
0
static void
negamax(struct node *node)
{
	assert(node->alpha < node->beta);

	node_init(node);

	if (check_trivial_draw(node) == is_trivial_draw)
		return;

	ht_prefetch(node->tt, node->pos->zhash[0]);

	if (adjust_depth(node) == too_deep)
		return;

	if (handle_mate_search(node) == mate_search_handled)
		return;

	if (setup_bounds(node) == stand_pat_cutoff)
		return;

	if (setup_moves(node) == no_legal_moves)
		return;

	if (node->forced_pv == 0) {
		if (fetch_hash_value(node) == hash_cutoff)
			return;
	}
	else {
		int r = move_order_add_hint(node->mo, node->forced_pv, 0);
		(void) r;
		assert(r == 0);
	}

	if (try_null_move_prune(node) == prune_successfull)
		return;

	if (recheck_bounds(node) == alpha_beta_range_too_small)
		return;

	assert(node->beta > -max_value + 2);
	assert(node->alpha < max_value - 2);

	do {
		move_order_pick_next(node->mo);

		if (can_prune_moves(node))
			break;

		move m = mo_current_move(node->mo);

		int LMR_factor;

		setup_child_node(node, m, &LMR_factor);

		int value = negamax_child(node);

		if (LMR_factor != 0) {
			if (value > node->alpha) {
				reset_child_after_lmr(node);
				value = negamax_child(node);
			}
			else {
				debug_trace_tree_pop_move(node);
				continue;
			}
		}

		value = handle_beta_extension(node, m, value);

		if (value > node->value) {
			node->value = value;
			if (value > node->alpha) {
				node->alpha = value;
				new_best_move(node, m);

				if (node->alpha >= node->beta)
					fail_high(node);
				else
					node->expected_type = PV_node;
			}
		}
		debug_trace_tree_pop_move(node);
	} while (search_more_moves(node));

	ht_entry entry = hash_current_node_value(node);
	setup_best_move(node);

	assert(node->repetition_affected_any == 0 || !node->is_GHI_barrier);
	assert(node->repetition_affected_best == 0 || !node->is_GHI_barrier);

	if (node->depth > 0) {
		if (node->best_move != 0)
			entry = ht_set_move(entry, node->best_move);
		if (node->null_move_search_failed)
			entry = ht_set_no_null(entry);
		if (ht_value_type(entry) != 0 || node->best_move != 0)
			ht_pos_insert(node->tt, node->pos, entry);
	}
	if (node->value < node->lower_bound)
		node->value = node->lower_bound;
	node->forced_pv = 0;
}
Esempio n. 15
0
static void generate_component(component comp, fncode fn)
{
  clist args;

  set_lineno(comp->lineno, fn);

  switch (comp->vclass)
    {
    case c_assign:
      {
	ulong offset;
        bool is_static;
	variable_class vclass = env_lookup(comp->u.assign.symbol, &offset,
                                           false, true, &is_static);
	component val = comp->u.assign.value;

	if (val->vclass == c_closure)
	  {
	    /* Defining a function, give it a name */
	    if (vclass == global_var)
	      val->u.closure->varname = comp->u.assign.symbol;
	    else
	      {
		char *varname = allocate(fnmemory(fn), strlen(comp->u.assign.symbol) + 7);

		sprintf(varname, "local-%s", comp->u.assign.symbol);
		val->u.closure->varname = varname;
	      }
	  }

        if (is_static)
          {
            ins1(op_recall + vclass, offset, fn);
            generate_component(comp->u.assign.value, fn);
            mexecute(g_symbol_set, NULL, 2, fn);
            break;
          }

	generate_component(comp->u.assign.value, fn);

	set_lineno(comp->lineno, fn);

        if (vclass == global_var)
	  massign(offset, comp->u.assign.symbol, fn);
	else
	  ins1(op_assign + vclass, offset, fn);
	/* Note: varname becomes a dangling pointer when fnmemory(fn) is
	   deallocated, but it is never used again so this does not cause
	   a problem. */
	break;
      }
    case c_vref:
    case c_recall:
      {
        bool is_vref = comp->vclass == c_vref;
	ulong offset;
        bool is_static;
	variable_class vclass = env_lookup(comp->u.recall, &offset,
                                           true, is_vref, &is_static);

        if (is_static)
          {
            assert(vclass != global_var);
            ins1(op_recall + vclass, offset, fn);
            ulong gidx = is_vref ? g_make_symbol_ref : g_symbol_get;
            mexecute(gidx, NULL, 1, fn);
            break;
          }
	if (vclass != global_var)
          ins1((is_vref ? op_vref : op_recall) + vclass, offset, fn);
        else if (is_vref)
          {
            if (!mwritable(offset, comp->u.recall))
              return;
            ins_constant(makeint(offset), fn);
          }
        else
          mrecall(offset, comp->u.recall, fn);
        if (is_vref)
          mexecute(g_make_variable_ref, "make_variable_ref", 1, fn);
	break;
      }
    case c_constant:
      ins_constant(make_constant(comp->u.cst), fn);
      break;
    case c_closure:
      {
	uword idx;

	idx = add_constant(generate_function(comp->u.closure, false, fn), fn);
	if (idx < ARG1_MAX) ins1(op_closure_code1, idx, fn);
	else ins2(op_closure_code2, idx, fn);
	break;
      }
    case c_block:
      generate_block(comp->u.blk, fn);
      break;
    case c_labeled:
      start_block(comp->u.labeled.name, fn);
      generate_component(comp->u.labeled.expression, fn);
      end_block(fn);
      break;
    case c_exit:
      generate_component(comp->u.labeled.expression, fn);
      if (!exit_block(comp->u.labeled.name, fn)) {
	if (!comp->u.labeled.name)
	  log_error("no loop to exit from");
	else
	  log_error("no block labeled %s", comp->u.labeled.name);
      }
      break;
    case c_execute:
      {
	uword count;

	generate_args(comp->u.execute->next, fn, &count);
	set_lineno(comp->lineno, fn);
	generate_execute(comp->u.execute->c, count, fn);
	break;
      }
    case c_builtin:
      args = comp->u.builtin.args;

      switch (comp->u.builtin.fn)
	{
	case b_if: {
          block cb = new_codeblock(fnmemory(fn), NULL,
                                   new_clist(fnmemory(fn), args->next->c,
                                             new_clist(fnmemory(fn),
                                                       component_undefined,
                                                       NULL)),
                                   NULL, NULL, -1);
	  generate_if(args->c, new_component(fnmemory(fn),
                                             args->next->c->lineno,
                                             c_block, cb),
		      component_undefined, fn);
	  break;
        }
	case b_ifelse:
	  generate_if(args->c, args->next->c, args->next->next->c, fn);
	  break;
	case b_sc_and: case b_sc_or:
	  generate_if(comp, component_true, component_false, fn);
	  break;

	case b_while:
	  generate_while(args->c, args->next->c, fn);
	  break;

	case b_loop:
	  {
	    label loop = new_label(fn);

            env_start_loop();
	    set_label(loop, fn);
	    start_block(NULL, fn);
	    generate_component(args->c, fn);
	    branch(op_loop1, loop, fn);
	    end_block(fn);
            env_end_loop();
	    adjust_depth(1, fn);
	    break;
	  }

	case b_add: case b_subtract:
	case b_ref: case b_set:
	case b_bitor: case b_bitand:
	case b_not:
	case b_eq: case b_ne:
	case b_lt: case b_le: case b_ge: case b_gt:
	  {
	    uword count;

	    assert(comp->u.builtin.fn < last_builtin);
	    generate_args(args, fn, &count);
	    set_lineno(comp->lineno, fn);
	    ins0(builtin_ops[comp->u.builtin.fn], fn);
	    break;
	  }
	default:
	  {
	    uword count;

	    assert(comp->u.builtin.fn < last_builtin);
	    generate_args(args, fn, &count);
	    set_lineno(comp->lineno, fn);
	    mexecute(builtin_functions[comp->u.builtin.fn], NULL, count, fn);
	    break;
	  }
	}
      break;
    default: abort();
    }
}
Esempio n. 16
0
void generate_component(component comp, const char *mlabel, bool discard, fncode fn)
{
  clist args;

  switch (comp->vclass)
    {
    case c_assign:
      {
	u16 offset;
	mtype t;
	variable_class vclass = env_lookup(comp->l, comp->u.assign.symbol, &offset, &t, FALSE);
	component val = comp->u.assign.value;

	if (val->vclass == c_closure)
	  {
	    /* Defining a function, give it a name */
	    if (vclass == global_var)
	      val->u.closure->varname = comp->u.assign.symbol;
	    else
	      {
		char *varname = allocate(fnmemory(fn), strlen(comp->u.assign.symbol) + 7);

		sprintf(varname, "local-%s", comp->u.assign.symbol);
		val->u.closure->varname = varname;
	      }
	  }
	generate_component(comp->u.assign.value, NULL, FALSE, fn);
	if (t != stype_any)
	  ins0(OPmscheck4 + t, fn);
	if (vclass == global_var)
	  massign(comp->l, offset, comp->u.assign.symbol, fn);
	else if (vclass == closure_var)
	  ins1(OPmwritec, offset, fn);
	else
	  ins1(OPmwritel, offset, fn);
	/* Note: varname becomes a dangling pointer when fnmemory(fn) is
	   deallocated, but it is never used again so this does not cause
	   a problem. */
	break;
      }
    case c_recall:
      scompile_recall(comp->l, comp->u.recall, fn);
      break;
    case c_constant:
      ins_constant(make_constant(comp->u.cst, FALSE, fn), fn);
      break;
    case c_scheme:
      scheme_compile_mgc(comp->l, make_constant(comp->u.cst, TRUE, fn), discard, fn);
      discard = FALSE;
      break;
    case c_closure:
      generate_function(comp->u.closure, fn);
      break;
    case c_block:
      generate_block(comp->u.blk, discard, fn);
      discard = FALSE;
      break;
    case c_decl: 
      {
	vlist decl, next;

	/* declare variables one at a time (any x = y, y = 2; is an error) */
	for (decl = comp->u.decls; decl; decl = next)
	  {
	    next = decl->next;
	    decl->next = NULL;

	    env_declare(decl);
	    generate_decls(decl, fn);
	  }
	generate_component(component_undefined, NULL, FALSE, fn);
	break;
      }
    case c_labeled: {
      start_block(comp->u.labeled.name, FALSE, discard, fn);
      generate_component(comp->u.labeled.expression, comp->u.labeled.name, discard, fn);
      end_block(fn);
      discard = FALSE;
      break;
    }
    case c_exit:
      {
	bool discard_exit;
	label exitlab = exit_block(comp->u.labeled.name, FALSE, &discard_exit, fn);

	if (comp->u.labeled.expression != component_undefined && discard_exit)
	  warning(comp->l, "break result is ignored");
	generate_component(comp->u.labeled.expression, NULL, discard_exit, fn);
	if (exitlab)
	  branch(OPmba3, exitlab, fn);
	else 
	  {
	    if (!comp->u.labeled.name)
	      log_error(comp->l, "No loop to exit from");
	    else
	      log_error(comp->l, "No block labeled %s", comp->u.labeled.name);
	  }
	/* Callers expect generate_component to increase stack depth by 1  */
	if (discard_exit)
	  adjust_depth(1, fn);
	break;
      }
    case c_continue:
      {
	bool discard_exit; /* Meaningless for continue blocks */
	label exitlab = exit_block(comp->u.labeled.name, TRUE, &discard_exit, fn);

	if (exitlab)
	  branch(OPmba3, exitlab, fn);
	else 
	  {
	    if (comp->u.labeled.name[0] == '<')
	      log_error(comp->l, "No loop to continue");
	    else
	      log_error(comp->l, "No loop labeled %s", comp->u.labeled.name);
	  }
	/* Callers expect generate_component to increase stack depth by 1 (*/
	adjust_depth(1, fn);
	break;
      }
    case c_execute:
      {
	u16 count;

	generate_args(comp->u.execute->next, fn, &count);
	generate_execute(comp->u.execute->c, count, fn);
	break;
      }
    case c_builtin:
      args = comp->u.builtin.args;

      switch (comp->u.builtin.fn)
	{
	case b_if:
	  generate_if(args->c, args->next->c, NULL, TRUE, fn);
	  generate_component(component_undefined, NULL, FALSE, fn);
	  break;
	case b_ifelse:
	  generate_if(args->c, args->next->c, args->next->next->c, discard, fn);
	  discard = FALSE;
	  break;
	case b_sc_and: case b_sc_or:
	  generate_if(comp, component_true, component_false, discard, fn);
	  discard = FALSE;
	  break;

	case b_while:
	  enter_loop(fn);
	  generate_while(args->c, args->next->c, mlabel, discard, fn);
	  exit_loop(fn);
	  discard = FALSE;
	  break;

	case b_dowhile:
	  enter_loop(fn);
	  generate_dowhile(args->c, args->next->c, mlabel, discard, fn);
	  exit_loop(fn);
	  discard = FALSE;
	  break;

	case b_for:
	  enter_loop(fn);
	  generate_for(args->c, args->next->c, args->next->next->c,
		       args->next->next->next->c, mlabel, discard, fn);
	  exit_loop(fn);
	  discard = FALSE;
	  break;

	default:
	  {
	    u16 count;

	    assert(comp->u.builtin.fn < last_builtin);
	    generate_args(args, fn, &count);
	    ins0(builtin_ops[comp->u.builtin.fn], fn);
	    break;
	  }
	case b_cons:
	  {
	    u16 count;
	    u16 goffset;
	    mtype t;

	    assert(comp->u.builtin.fn < last_builtin);
	    generate_args(args, fn, &count);
	    goffset = global_lookup(fnglobals(fn),
				    builtin_functions[comp->u.builtin.fn], &t);
	    mexecute(comp->l, goffset, NULL, count, fn);
	    break;
	  }
	}
      break;
    default: assert(0);
    }
  if (discard)
    ins0(OPmpop, fn);
}