#ifndef alga_HH
#define alga_HH

#define PUBLIC
#define PRIVATE static

/***********************************************************************
 	ALGA: Assembler-Like Grammar trAnslation support.
***********************************************************************/
/***********************************
  (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   EPS General Public License (see file LICENSE)
 ***********************************/

/*
 *** "bsc_dcls.hh": BaSiC DeCLarationS.
 *
 * $Id: bsc_dcls.desc,v 1.1 1993/01/12 18:18:05 eps Exp $
 */

#include <stdio.h>
#include <stdlib.h>
#include <values.h>


/* boolean values */

#ifndef TRUE
#  define TRUE	1
#  define FALSE	0
#endif


/*

 *** "lnt_pass.hh": LiNT PASSing (complaints suppression) functions.
 *
 * $Id: lnt_pass.desc,v 1.4 1993/01/12 18:18:15 eps Exp $
 */

/* avoids "lint" complaints about pointer alinment */

#ifndef lint
#  define ALIN(type, ptr)	((type *)(ptr))
#else
#  define ALIN(type, ptr)	((type *)(int)&*(ptr))
#endif

/* useful to avoid "lint" complaints about null effect code */

#ifndef lint
#  define NOOP()	((void)0)
#else
   int __NOOP__= 0;

#  define NOOP()	((void)(++__NOOP__))
#endif

/* suppress "lint" complaints about constant conditions */

#ifndef lint
#  define TEST(cond)	(cond)
#else
   int __TEST__= 0;

#  define TEST(cond)	(__TEST__= (cond), __TEST__)
#endif

/* avoids "lint" complaints about constants in conditions */

#ifndef lint
#  define EVAL(exp)	(exp)
#else
   int __EVAL__= TRUE;

#  define EVAL(exp)	(__EVAL__? (exp): (exp))
#endif


/*

 *** "err_handl.hh": ERRor HANDLing functions.
 *
 * $Id: err_handl.desc,v 1.3 1993/01/12 16:36:30 eps Exp $
 */

extern char *prog_name;	/* program name (user provided) */

/* writes an error message with a NEWLINE appended
 * (if xcode is 0, returns, else exits with xcode)
 */

void	xerror ();

/* writes an error message with a NEWLINE appended, then aborts */

void	berror ();

/* writes an error message and appends a NEWLINE, then exits (code 1) */

void	error ();


/*

 *** "prg_error.hh": PRoGramming ERROR detection functions.
 *
 * $Id: prg_error.desc,v 1.3 1993/01/12 16:36:33 eps Exp $
 */

#if !defined(NCHECK) && defined(NDEBUG)
#  define NCHECK
#endif

/* if condition is true, writes a message and aborts */

void _cond_fail();

#ifndef NDEBUG
#  define abort_if(cond)				\
	  {						\
	    if (TEST(cond))				\
	      _cond_fail(__FILE__, __LINE__);		\
	  }
#else
#  define abort_if(cond)	{}
#endif

/* evaluates an expression if condition is true, else aborts */

void _cond_fail();

#ifndef NDEBUG
#  define eval_if(cond, exp)				\
	    ((TEST(cond)? NOOP()			\
		    : _cond_fail(__FILE__, __LINE__)	\
	     ), (exp))
#else
#  define eval_if(cond, exp)	(exp)
#endif

/* checks and returns a condition if it is true, else aborts */

void _check_fail();

#ifndef NCHECK
#  define check(cond)					\
	    ((TEST(cond)? NOOP()			\
		    : _check_fail(__FILE__, __LINE__)	\
	     ), TRUE)
#else
#  define check(cond)	(TRUE)
#endif


/*

 *** "mem_alloc.hh": MEMory ALLOCation functions.
 *
 * $Id: mem_alloc.desc,v 1.6 1993/01/12 18:32:50 eps Exp $
 */

/* allocates typed memory and if cannot, writes a message and exits */

void _alloc_error();

#define _talloc(lptr, rptr, nelem)				\
	  (((lptr)= ALIN(void, malloc((unsigned)		\
				      sizeof(*(rptr)) *		\
				      (nelem)))) == NULL?	\
	     _alloc_error(): NOOP()				\
	  )

#ifndef lint
#  define talloc(ptr, nelem)	_talloc(ptr, ptr, nelem)
#else
#  define talloc(ptr, nelem)	_talloc(ALIN(void, ptr), ptr, nelem)
#endif

/* reallocates typed memory and if cannot, writes a message and exits */

void _alloc_error();

#define _trealloc(lptr, rptr, nelem)				\
	  (((lptr)= ALIN(void, realloc(ALIN(char, rptr),	\
				       (unsigned)		\
				       sizeof(*(rptr)) *	\
				       (nelem)))) == NULL?	\
	     _alloc_error(): NOOP()				\
	  )

#ifndef lint
#  define trealloc(ptr, nelem)	_trealloc(ptr, ptr, nelem)
#else
#  define trealloc(ptr, nelem)	_trealloc(ALIN(void, ptr), ptr, nelem)
#endif

/* releases a previously allocated typed memory */

#define tfree(ptr)	((void) free(ALIN(char, ptr)))


/*

 *** "bsc_input.hh": BaSiC INPUT functions.
 *
 * $Id: bsc_input.desc,v 1.4 1993/01/12 16:36:39 eps Exp $
 */

typedef struct
{ char *chr;
  int size;
  int level;
  int i, imax;
  int next_chr;
  int lno;
  int eof;
} sIBUF;	/* input buffer structure */

/* input buffer (you mustn't use it) */
#ifndef alga_IMP
extern	sIBUF _IBUF;
#else
	sIBUF _IBUF= { NULL, 0, 0, 0, -1, '\0', 0, FALSE };
#endif

/* returns TRUE if the string is a word */

int	is_word ();

/* gets a word, or NULL if cannot (uses a static buffer) */

char *	get_word ();

/* returns TRUE if the string is a single line */

int	is_line ();

/* gets a line, or NULL if cannot (uses a static buffer) */

char *	get_line ();

/* ungets last input in current line, or returns FALSE if cannot */

int	unget ();

/* starts a new line if EOL was reached, else returns FALSE */

int	new_line ();

/* gets current line number, or 0 if no character was read */

#define get_lno()	(_IBUF.lno)

/* returns TRUE if EOF was reached or error detected */

#define is_eof()	(_IBUF.eof)

/* starts a new file (only if EOL was reached), else returns FALSE */

int	new_file ();


/*

 *** "fld_basic.hh": FieLD BASIC functions.
 *
 * $Id: fld_basic.desc,v 1.3 1993/01/12 16:36:43 eps Exp $
 */

#define ESYM	0		/* end/error symbol */
#define ESTR	NULL		/* end/error string */
#define EINT	MAXINT		/* end/error integer */

typedef char *tSYM_LST[];	/* symbol list type */

extern tSYM_LST sym_lst;	/* symbol list (user provided) */

/* returns TRUE if the string is a symbol */

#define is_sym(str)	is_word(str)

/* creates a new symbol (returns ESYM if null symbol) */

int	new_sym ();

/* returns the id number of a symbol, or ESYM if not found */

int	sym_id ();

/* returns the name of a symbol, or NULL if not found */

char *	sym_name ();

/* returns TRUE if the string is a single line one */

#define is_str(str)	is_line(str)

/* returns TRUE if the string is an integer */

int	is_int ();


/*

 *** "fld_input.hh": FieLD INPUT functions.
 *
 * $Id: fld_input.desc,v 1.3 1993/01/12 16:36:46 eps Exp $
 */

/* gets a symbol, or ESYM if cannot */

int	get_sym ();

/* gets a string, or ESTR if cannot */

char *	get_str ();

/* gets an integer, or EINT if cannot */

int	get_int ();


/*

 *** "rec_basic.hh": RECord BASIC functions.
 *
 * $Id: rec_basic.desc,v 1.3 1993/01/12 16:36:49 eps Exp $
 */

typedef enum { NUL, SYM, STR, INT } eFLD;	/* available fields */

typedef struct
{ eFLD FT;
  union
  { int SYM;
    char *STR;
    int INT;
  } F;
} sFLD;		/* field structure */

typedef struct
{ int NR;
  int NF;
  int size;
  sFLD *fld;
} sREC;		/* record structure */

/* creates a record */

sREC *	crt_rec ();

/* expands a record */

sREC *	exp_rec ();

/* clears a record */

sREC *	clr_rec ();

/* deletes a record */

void	del_rec ();

/* duplicates a record */

sREC *	dup_rec ();


/*

 *** "rec_input.hh": RECord INPUT functions.
 *
 * $Id: rec_input.desc,v 1.4 1993/01/12 16:36:51 eps Exp $
 */

/* starts input of next record, or returns FALSE if cannot */

sREC *_new_rec();

#define new_rec(rec)	(((rec)= _new_rec(rec)) != NULL)

/* adds a new field to a record (returns field error if cannot) */

sFLD *_add_fld();

#define add_fld(rec, type)	(_add_fld(rec, type)->F.type)

/* sets a field and adds to a record (returns field error if cannot) */

typedef struct
{ int (*SYM)();
  char *(*STR)();
  int (*INT)();
} sSET_FLD;	/* set field structure */

int _set_sym();
char *_set_str();
int _set_int();

/* set field functions (you mustn't use it) */
#ifndef alga_IMP
extern	sSET_FLD _set_fld;
#else
	sSET_FLD _set_fld= { _set_sym, _set_str, _set_int };
#endif

#ifndef lint
#define set_fld(rec, type, value)	((*_set_fld.type)(rec, value))
#else
sREC *_set_rec;

#define set_fld(rec, type, value)		\
	  ((_set_rec= (rec)),			\
	   (_set_rec->fld[0].FT= type),		\
	   (_set_rec->fld[0].F.type= (value)),	\
	   ((*_set_fld.type)(_set_rec))		\
	  )
#endif


/*

 *** "rec_query.hh": RECord QUERY functions.
 *
 * $Id: rec_query.desc,v 1.3 1993/01/12 16:36:54 eps Exp $
 */

/* returns the type of a field */

#define fldty(rec, ndx)					\
	  eval_if((rec) != NULL &&			\
	          (rec)->fld != NULL &&			\
		  1 <= EVAL(ndx) && (ndx) <= (rec)->NF,	\
		  (rec)->fld[ndx].FT)

/* returns a field of a record */

#define field(rec, ndx, type)					\
	  eval_if((rec) != NULL &&				\
	          (rec)->fld != NULL &&				\
		  1 <= EVAL(ndx) && (ndx) <= (rec)->NF &&	\
		  (rec)->fld[ndx].FT == type,			\
		  (rec)->fld[ndx].F.type)

/* returns the number of fields of a record */

#define nofld(rec)	eval_if((rec) != NULL, ((rec)->NF))

/* returns the number of a record */

#define recno(rec)	eval_if((rec) != NULL, ((rec)->NR)


/*

 *** "rec_draw.hh": RECord DRAWing functions.
 *
 * $Id: rec_draw.desc,v 1.3 1993/01/12 16:36:56 eps Exp $
 */

/* draws a field on stderr */

void _dr_fld();

#define dr_fld(rec, ndx)				\
	  eval_if((rec) != NULL &&			\
	          (rec)->fld != NULL &&			\
	          1 <= EVAL(ndx) && (ndx) <= (rec)->NF,	\
		  _dr_fld((rec)->fld + (ndx)))

/* draws a record on stderr (for debugging) */

void	dr_rec ();


/*

 *** "indent.hh": code INDENTation functions.
 *
 * $Id: indent.desc,v 1.5 1993/01/12 16:36:59 eps Exp $
 */

/* default indentation increase indicator */

#define DFLT_INDT	-1

/* filling indicators for indentation advances */

#define FILL	TRUE
#define NOFILL	FALSE

typedef struct
{ int *size;
  int level;
  int limit;
  int dflt;
  int incr;
} sINDT;	/* indentation stack structure */

/* indentation stack (you mustn't use it) */
#ifndef alga_IMP
extern	sINDT _INDT;
#else
	sINDT _INDT= { NULL, 0, 0, 0, 0 };
#endif

/* initializes the indentation stack, and sets the default increase
 * (indentation is only enabled if a positive default is provided)
 */

void	init_indt ();

/* increases the indentation level */

#ifndef test_HP_bug	/* stupid HP C compilers!!! */
void	incr_indt ();

#else
void _exp_indt();

#define _incr_indt()					\
	  (_INDT.level == _INDT.limit? _exp_indt()	\
				     : NOOP(),		\
	   _INDT.size[++_INDT.level]=			\
	     _INDT.size[_INDT.level - 1] + _INDT.incr,	\
	   NOOP()					\
	  )

#define incr_indt(_incr)				\
	  (_INDT.incr= (_incr),				\
	   _INDT.dflt > 0?				\
	     (_INDT.incr < 0?				\
		(_INDT.incr= _INDT.dflt, NOOP())	\
	      : NOOP(),					\
	      _incr_indt()				\
	     )						\
	   : NOOP()					\
	  )
#endif

/* decreases the indentation level */

#ifndef test_HP_bug	/* stupid HP C compilers!!! */
void	decr_indt ();

#else
#define _decr_indt()	eval_if(_INDT.level > 0,		\
				(--_INDT.level, NOOP()))

#define decr_indt()	(_INDT.dflt > 0? _decr_indt(): NOOP())
#endif

/* indents from the current position */

void _wrt_indt();

#define _indent()	(_wrt_indt(_INDT.size[_INDT.level]))

#define indent()	(_INDT.dflt > 0? _indent(): NOOP())

/* advances the indentation while writes the text up to given increase
 * (or text length if higher), filling at end with blanks if asked for
 */

void	advc_indt ();

#endif
