text: /*
   * Copyright (C) 1985-1992  New York University
   * 
   * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
   * warranty (none) and distribution info and also the GNU General Public
   * License for more details.
  
   */
  
  #define GEN
  
  #include "hdr.h"
  #include "vars.h"
  #include "gvars.h"
  #include "type.h"
  #include "segment.h"
  #include "miscprots.h"
  #include "dbxprots.h"
  #include "axqrprots.h"
  #include "gmiscprots.h"
  #include "segmentprots.h"
  
  static void segment_put_n(Segment, int, int, char *);
  static void segment_realloc(Segment, unsigned);
  
  extern Segment	CODE_SEGMENT, DATA_SEGMENT, DATA_SEGMENT_MAIN;
  
  #ifdef MACHINE_CODE
  void print_data_segment()								/*;print_data_segment*/
  {
  	Segment	seg;
  	char		line[250], c;
  	int		i, w, *sp;
  
  	seg = DATA_SEGMENT; 
  	sp = (int *) seg->seg_data;
  	to_gen(" ");
  	to_gen_int("--- Global data segment # ", CURRENT_DATA_SEGMENT);
  	for (i = 0; i < seg->seg_maxpos; i++) {
  		w = *sp++;
  		if (w >= ' ' && w <= '~') c = w; 
  		else c = ' ';
  		sprintf(line, "     %5d  %8x %c %d", i, w, c, w);
  		to_gen(line);
  	}
  }
  #endif
  
  void segment_append(Segment s, Segment sa)					/*;segment_append*/
  {
  	/* append segment sa at end of segment s */
  
  	int	i, la;
  
  	seg_check(s);
  	if (s->seg_kind != SEGMENT_KIND_DATA)
  		chaos("segment_append not appending a data segment");
  	s->seg_pos = s->seg_maxpos;
  	la = sa->seg_maxpos;
  	for (i = 0; i < la; i++) {
  		segment_put_int(s, ((int *)(sa->seg_data))[i]);
  	}
  }
  
  void seg_check(Segment seg)										/*;seg_check*/
  {
  	if (seg->seg_id != SEG_ID)
  		chaos("invalid segment - check word invalid ");
  }
  
  void segment_empty(Segment s)								/*;segment_empty*/
  {
  	/* seg segment to empty state, but do no reallocate it */
  	seg_check(s);
  	s->seg_pos = 0;
  	s->seg_maxpos = 0;
  }
  
  void segment_free(Segment s)								/*;segment_free*/
  {
  	seg_check(s);
  	efreet(s->seg_data, "segment-data");
  	efreet((char *) s, "segment");
  }
  
  int segment_get_int(Segment s, int i)					/*;segment_get_int*/
  {
  	/* get value of word from location i in segment seg. */
  
  	int	*resp;
  
  	seg_check(s);
  	if (i >= s->seg_maxpos) {
  		chaos("segment.c: get_int retrieving from undefined location\n");
  		return 0;
  	}
  	if (s->seg_kind == SEGMENT_KIND_DATA) {
  		resp = (int *) s->seg_data + i;
  		return *resp;
  	}
  	else {
  #ifdef ALIGN_WORD
  		/* retrieve byte by byte to avoid alignment problems */
  		register int j;
  		int v;
  		register char *sp, *tp;
  
  		resp = (int *) (s->seg_data + i);
  		sp = (char *) resp;
  		tp = (char *) &v;
  		for (j = 0; j < sizeof(int); j++) *tp++ = *sp++;
  		return v;
  #else
  		resp = (int *) (s->seg_data + i);
  		return *resp;
  #endif
  	}
  }
  
  unsigned int segment_get_pos(Segment seg)				/*;segment_get_pos*/
  {
  	seg_check(seg);
  	return seg->seg_pos;
  }
  
  unsigned int segment_get_maxpos(Segment seg)			/*;segment_get_maxpos*/
  {
  	seg_check(seg);
  	return seg->seg_maxpos;
  }
  
  int segment_get_off(Segment s, int i)						/*;segment_get_off*/
  {
  	return segment_get_int(s, i);
  }
  
  void segment_put_byte(Segment s, int v)					/*;segment_put_byte*/
  {
  	unsigned	newpos, pos;
  
  	seg_check(s);
  
  	if (s->seg_kind != SEGMENT_KIND_CODE)
  		chaos("segment.c: segment_put_byte called on data segment");
  
  	pos = s->seg_pos;
  	newpos = pos + 1;
  	if (newpos >= s->seg_dim) {
  		segment_realloc(s, newpos);
  	}
  	s->seg_data[pos] = (char) v;
  	s->seg_pos = newpos;
  	if (s->seg_maxpos < newpos) s->seg_maxpos = newpos;
  }
  
  void segment_put_const(Segment seg, Const con)			/*;segment_put_const*/
  {
  	if (con->const_kind == CONST_INT) {
  		/* can safely put integers - defer others for later */
  		segment_put_word(seg, INTV(con));
  	}
  	else if(con->const_kind == CONST_REAL) {
  		segment_put_real(seg, REALV(con));
  	}
  	else if(con->const_kind == CONST_FIXED) {
  		segment_put_long(seg, FIXEDV(con));
  	}
  	else {
  #ifdef DEBUG
  		zpcon(con);
  #endif
  		chaos("segment.c - meaningless kind of literal");
  	}
  }
  
  void segment_put_int(Segment s, int v)						/*;segment_put_int*/
  {
  	unsigned	newpos, pos;
  	int		*d;
  
  	seg_check(s);
  	pos = s->seg_pos;
  	if (s->seg_kind == SEGMENT_KIND_DATA) {
  		newpos = pos + 1;
  		if (newpos >= s->seg_dim)
  			segment_realloc(s, newpos);
  		d = (int *) s->seg_data;
  		d[pos] = v;
  	}
  	else { /* if code segment */
  		newpos = pos + sizeof(int);
  		if (newpos >= s->seg_dim)
  			segment_realloc(s, newpos);
  #ifdef ALIGN_WORD
  		/* if must worry about alignment, do byte by byte */
  		{
  			int iv;
  			iv = v;
  			(void) segment_put_n(s, s->seg_pos, sizeof(int), (char *) &iv);
  		}
  #else
  		d = (int *) (s->seg_data + pos);
  		*d = v;
  #endif
  	}
  	s->seg_pos = newpos;
  	if (s->seg_maxpos < newpos) s->seg_maxpos = newpos;
  }
  
  void segment_put_long(Segment s, long v)				/*;segment_put_long*/
  {
  	long	lv = v;
  	segment_put_n(s, s->seg_pos, sizeof(long), (char *) &lv);
  }
  
  static void segment_put_n(Segment s, int i, int n, char *p)	/*;segment_put_n*/
  {
  	/* put n bytes from p at location i in segment seg, extending
  	 * segment if necessary 
  	 */
  
  	unsigned	newpos, pos;
  	int		*d;
  	char	*dc;
  
  	seg_check(s);
  	segment_set_pos(s, (unsigned) i, 0);
  	pos = s->seg_pos;
  	if (s->seg_size == 1) { /* if code segment */
  		newpos = pos + n;
  		if (newpos >= s->seg_dim)
  			segment_realloc(s, newpos);
  		dc = s->seg_data + pos;
  		while (n--)
  			*dc++ = *p++;
  	}
  	else { /* assume word size */
  		newpos = pos + n/sizeof(int);
  		if (newpos >= s->seg_dim)
  			segment_realloc(s, newpos);
  		d = (int *)( s->seg_data) + pos;
  		dc = (char *) d;
  		while (n--)
  			*dc++ = (unsigned char) *p++;
  	}
  	s->seg_pos = newpos;
  	if (s->seg_maxpos < newpos) s->seg_maxpos = newpos;
  }
  
  void segment_put_off(Segment s, int i, int v)				/*;segment_put_off*/
  {
  	/* put value of v, interpreted as offset (16 bits) at location i
  	 * in segment seg.
  	 * We assume this is used to overwrite a previously defined location
  	 * and raise chaos if this is not the case.
  	 */
  
  	unsigned	pos, oldpos;
  	int		*d;
  
  	seg_check(s);
  
  	if (i >= s->seg_maxpos)
  		chaos("segment.c: segment_put_off of undefined location");
  
  	pos = i;
  	if (s->seg_kind == SEGMENT_KIND_DATA) {
  		d = (int *) s->seg_data;
  		d[pos] = v;
  	}
  	else {
  #ifdef ALIGN_WORD
  		{  
  			int iv; 
  			iv = v;
  			oldpos = s->seg_pos; /* save pos since segment_put_n may alter it */
  			segment_put_n(s, i, sizeof(int), (char *)&iv);
  			s->seg_pos = oldpos;
  		}
  #else
  		d = (int *) (s->seg_data + pos);
  		*d = v;
  #endif
  	}
  }
  
  void segment_put_real(Segment s, double db)				/*;segment_put_real*/
  {
  	float	r = db;
  	segment_put_n(s, s->seg_pos, sizeof(float), (char *) &r);
  }
  
  void segment_put_ref(Segment seg, int segnum, int off)		/*;segment_put_ref*/
  {
  	if (seg->seg_kind == SEGMENT_KIND_DATA) {
  		segment_put_int(seg, segnum);
  		segment_put_int(seg, off);
  	}
  	else {
  		segment_put_byte(seg, segnum);
  		segment_put_int(seg, off);
  	}
  }
  
  void segment_put_word(Segment s, int v)					/*;segment_put_word*/
  {
  	segment_put_int(s, v);
  }
  
  void segment_set_pos(Segment s, unsigned pos, unsigned offtyp)
  														/*;segment_set_pos*/
  {
  	/* set position of segment to offset pos. offtyp is type of offset,
  	 * interpreted similarly to lseek(2); i.e., offtyp is 0 for offset
  	 * from start of segment, 1 for offset from current position, and 2
  	 * for offset from end of segment. Only the cases 0 and 2 are supported now.
  	 */
  
  	seg_check(s);
  	if (offtyp == 2) { /* to position at end ignore pos */
  		s->seg_pos = s->seg_maxpos;
  		return;
  	}
  	if (offtyp != 0)
  		chaos("segment_set_pos bad offset type");
  	s->seg_pos = pos;
  }
  
  static void segment_realloc(Segment s, unsigned newdim)		/*;segment_realloc*/
  {
  	/* extend dimension field if necessary to it is at least as large
  	 * as newdim
  	 */
  
  	unsigned	incr, dim;
  
  	seg_check(s);
  	dim = s->seg_dim;
  	if (dim >= newdim) return;
  	incr = newdim - dim;
  	if (incr < s->seg_extend) incr = s->seg_extend;
  	s->seg_dim += incr;
  	s->seg_data = erealloct(s->seg_data, s->seg_dim * s->seg_size,
  	  "segment-realloc");
  	/* update ptr to data if one is being kept */
  	if (s->seg_ptr != (int **) 0) {
  		*(s->seg_ptr) = (int *) s->seg_data;
  	}
  }
  
  Segment template_new(int t_kind, int t_size, int words, int **ptr)
  															/*;template_new*/
  {
  	Segment	s;
  
  	s = segment_new(SEGMENT_KIND_DATA, words);
  	s->seg_ptr = ptr; /* save address of pointer to be updated */
  	/* return pointer to start of segment */
  	*(s->seg_ptr) = (int *) s->seg_data;
  	segment_put_word(s, t_kind);
  	segment_put_word(s, t_size);
  	/* assume user will fill in rest direcly so point to end */
  	s->seg_pos = s->seg_maxpos = words;
  	return s;
  }
  
  unsigned int PC()														/*;PC*/
  {
  	/* corresponds to macro PC in SETL version */
  
  	seg_check(CODE_SEGMENT);
  	return CODE_SEGMENT->seg_maxpos;
  }
  
  #ifdef DEBUG
  void zpseg(Segment seg)												/*;zpseg*/
  {
  	printf("Segment %d x%x ", (int)seg, seg);
  	if (seg->seg_kind == SEGMENT_KIND_CODE) printf(" code");
  	else printf(" data");
  	printf(" size %d pos %d max_pos %d dim %d ext %d\n", seg->seg_size,
  	    seg->seg_pos, seg->seg_maxpos, seg->seg_dim, seg->seg_extend);
  	/* should print part of data here */
  }
  #endif
  