/***********************************************************************
     "d2ada.o": lotos Data language to ADA spec.
***********************************************************************/

/***********************************
  (C) Copyright 1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 $Log: d2ada.c,v $
 * Revision 3.4  1995/01/17  09:57:41  lotos
 * dynamic table sizing
 *
 * Revision 3.3  1993/06/10  14:06:26  lotos
 * new annotation CALL
 *
 * Revision 3.2  1993/05/28  10:58:04  lotos
 * comentarios por niveles
 *
 * Revision 3.1  1993/05/25  11:08:41  lotos
 * complete remake
 *
 * Revision 2.1  91/07/11  14:16:18  lotos
 * using alga
 *
 ***********************************/

#include "version.h"
#ifndef lint
static char rcsid[]= "$Id: d2ada.c,v 3.4 1995/01/17 09:57:41 lotos Exp $";
#endif

#define d2ada_IMP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "d2ada.hh"

/* KJT 20/01/23: added function prototypes */
int unlink(const char *pathname);

/* KJT 11/03/98: added for NS/OS */

#ifdef __NeXT__
char *strdup(s) register char *s; {

  register char *ns;

  return(((ns=malloc(strlen(s)+1))==0)?0:strcpy(ns,s)); }
#endif

/* translation initialization */

PRIVATE sREC *
trn_init ()
{
  init_indt(prog_flag.indt_incr);
  indent();
  (void) printf("%s %s; %s %s;\n", A_WITH, KAOS_PACK, A_USE, KAOS_PACK);
  indent();
  (void) printf("%s %s %s\n", A_PACKAGE, PACK_NAME, A_IS);
  incr_indt(DFLT_INDT);
  ign_empty_rec= TRUE;
  return get_rec();
}

/* skips ldc annotation (at the beginning) */

PRIVATE sREC *
skp_ldc_ant (rec)
  sREC *rec;
{
  abort_if(rec == NULL ||
	   nofld(rec) == 0)
  if (field(rec, 1, SYM) != BEGIN_ANNOTATION ||
      field(rec, 2, SYM) != LDC_ANNOTATION)
    return rec;
  while (rec= get_rec(),
	 field(rec, 1, SYM) != END_ANNOTATION)
    continue;
  return get_rec();
}

/* skips ldcinit annotation */

PRIVATE sREC *
skp_ldi_ant (rec)
  sREC *rec;
{
  abort_if(rec == NULL ||
	   nofld(rec) == 0)
  if (field(rec, 1, SYM) != BEGIN_ANNOTATION ||
      field(rec, 2, SYM) != LDCINIT_ANNOTATION)
    return rec;
  while (rec= get_rec(),
	 field(rec, 1, SYM) != END_ANNOTATION)
    continue;
  return get_rec();
}

/* skips ldc annotation (at the end) */

PRIVATE sREC *
skp_lde_ant (rec)
  sREC *rec;
{
  abort_if(rec == NULL ||
	   nofld(rec) == 0)
  if (field(rec, 1, SYM) != BEGIN_ANNOTATION ||
      field(rec, 2, SYM) != LDCEND_ANNOTATION)
    return rec;
  while (rec= get_rec(),
	 field(rec, 1, SYM) != END_ANNOTATION)
    continue;
  return get_rec();
}

PRIVATE int max_srt= -1;
PRIVATE sREC **srt_dcl= NULL;

/* translates sort declarations */

PRIVATE sREC *
trn_srt_dcls (rec)
  sREC *rec;
{
  int srt_uid;
  int i;

  abort_if(rec == NULL ||
	   nofld(rec) == 0 ||
	   field(rec, 1, SYM) != BEGIN_SORTS_DECL)
  abort_if(max_srt != -1)
  max_srt= field(rec, 2, INT);
  abort_if(srt_dcl != NULL)
  talloc(srt_dcl, max_srt + 1);
  for (i= 0; i <= max_srt; ++i)
    srt_dcl[i]= NULL;
  for (;;)
  { switch (rec= get_rec(), field(rec, 1, SYM))
    { case COMMENT:
	continue;
      case SORT_DECL:
	srt_uid= -field(rec, 3, INT);
	abort_if(srt_uid <= 0 ||
		 srt_uid > max_srt)
	srt_dcl[srt_uid]= dup_rec(rec);
	continue;
      case BEGIN_ANNOTATION:
      case LINE_QUOTE:
      case END_ANNOTATION:
	continue;
      case END_SORTS_DECL:
	break;
      default:
	abort_if(TRUE)
	break;
    }
    break;
  }
  return get_rec();
}

/* to storage operation declarations */
PRIVATE int max_opn= -1;
PRIVATE char **cmt_opn_dcl= NULL;
PRIVATE sREC **opn_dcl= NULL;
PRIVATE int *call_opn_dcl= NULL;

/* dumps operation declarations */

PRIVATE void
dmp_opn_dcls ()
{
  int opn_1st= TRUE;
  sREC *opn_info;
  char *opn_cmt;
  int opn_call;
  char *opn_name;
  int sort;
  int args;
  int max_args= 0;
  int *sarg= NULL;
  int i, j;

  for (j= 1; j <= max_opn; ++j)
  { opn_info= opn_dcl[j];
    opn_cmt= cmt_opn_dcl[j];
    opn_call= call_opn_dcl[j];
    if (opn_info == NULL)
      continue;
    if (field(opn_info, 5, SYM) != DEFINED && !opn_call)
      continue;
    if (opn_1st)
    { if (prog_flag.add_cmt > 1)
      { indent();
	(void) printf("-- %s %s\n", CMT_BEGIN, CMT_OPN_DCLS);
      }
      opn_1st= FALSE;
    }
    else if (prog_flag.add_cmt > 0)
      (void) printf("\n");
    opn_name= sym_name(field(opn_info, 2, SYM));
    sort= -field(opn_info, 6, INT);
    args= field(opn_info, 7, INT);
    if (args > max_args)
    { max_args= args;
      if (sarg == NULL)
	talloc(sarg, max_args);
      else
	trealloc(sarg, max_args);
    }
    for (i= 0; i < args; ++i)
      sarg[i]= -field(opn_info, 8 + i, INT);
    if (opn_cmt != NULL)
    { indent();
      (void) printf("-- %s\n", opn_cmt);
    }
    indent();
    (void) printf("%s %s", A_FUNCTION, opn_name);
    if (args > 0)
    { (void) printf("(");
      for (i= 1;; ++i)
      { (void) printf("%s%d: ", ARG_ROOT, i);
	if (field(srt_dcl[sarg[i - 1]], 5, SYM) == DEFINED)
	  (void) printf("%s", K_DATUM);
	else
	  (void) printf("%s", U_DATUM);
	if (i == args)
	  break;
	(void) printf("; ");
      }
      (void) printf(")");
    }
    (void) printf(" %s ", A_RETURN);
    if (field(srt_dcl[sort], 5, SYM) == DEFINED)
      (void) printf("%s", K_DATUM);
    else
      (void) printf("%s", U_DATUM);
    (void) printf(";\n");
  }
  if (!opn_1st)
  { if (prog_flag.add_cmt > 1)
    { indent();
      (void) printf("-- %s %s\n", CMT_END, CMT_OPN_DCLS);
    }
    if (sarg != NULL)
    { tfree(sarg);
      max_args= 0;
      sarg= NULL;
    }
  }
}

/* translates operation declarations */

PRIVATE sREC *
trn_opn_dcls (rec)
  sREC *rec;
{
  int opn_uid;
  char *opn_cmt= NULL;
  int i;

  abort_if(rec == NULL ||
	   nofld(rec) == 0 ||
	   field(rec, 1, SYM) != BEGIN_OPERATIONS_DECL)
  abort_if(max_opn != -1)
  max_opn= field(rec, 2, INT);
  abort_if(cmt_opn_dcl != NULL)
  talloc(cmt_opn_dcl, max_opn + 1);
  for (i= 0; i <= max_opn; ++i)
    cmt_opn_dcl[i]= NULL;
  abort_if(opn_dcl != NULL)
  talloc(opn_dcl, max_opn + 1);
  for (i= 0; i <= max_opn; ++i)
    opn_dcl[i]= NULL;
  abort_if(call_opn_dcl != NULL)
  talloc(call_opn_dcl, max_opn + 1);
  for (i= 0; i <= max_opn; ++i)
    call_opn_dcl[i]= FALSE;
  for (;;)
  { switch (rec= get_rec(), field(rec, 1, SYM))
    { case COMMENT:
	if (prog_flag.add_cmt > 0)
	  opn_cmt= strdup(field(rec, 2, STR) + 1);
	continue;
      case OPERATION_DECL:
	opn_uid= field(rec, 3, INT);
	abort_if(opn_uid <= 0 ||
		 opn_uid > max_opn)
	opn_dcl[opn_uid]= dup_rec(rec);
	if (opn_cmt != NULL)
	{ cmt_opn_dcl[opn_uid]= opn_cmt;
	  opn_cmt= NULL;
	}
	continue;
      case BEGIN_ANNOTATION:
	switch (field(rec, 2, SYM))
	{ case CALL_ANNOTATION:
	    call_opn_dcl[opn_uid]= TRUE;
	    break;
	  default:
	    abort_if(TRUE)
	    break;
	}
	continue;
      case LINE_QUOTE:
	continue;
      case END_ANNOTATION:
	continue;
      case END_OPERATIONS_DECL:
	break;
      default:
	abort_if(TRUE)
	break;
    }
    break;
  }
  dmp_opn_dcls();
  return get_rec();
}

/* translation ending */

PRIVATE sREC *
trn_end (rec)
  sREC *rec;
{
  decr_indt();
  indent();
  (void) printf("%s %s;\n", A_END, PACK_NAME);
  return rec;
}

/* writes program usage */

PRIVATE void
usage ()
{
  (void) fprintf(stderr, "usage: %s", prog_name);
  (void) fprintf(stderr, " [ -h ]");
  (void) fprintf(stderr, " [ -c[0-2] ]");
  (void) fprintf(stderr, " [ -i[num] ]");
  (void) fprintf(stderr, "\n");
}

/* writes program help */

PRIVATE void
help ()
{
  usage();
  (void) fprintf(stderr, "       -h        this help message\n");
  (void) fprintf(stderr, "       -c[0-2]   comment insertion level ");
  (void) fprintf(stderr, "(default 1)\n");
  (void) fprintf(stderr, "       -i[num]   indentation level size ");
  (void) fprintf(stderr, "(range 0-%u, default %u)\n",
		 MAX_INDT_INCR, DFL_INDT_INCR);
}

/* processes command line arguments */

PRIVATE void
proc_arg (argc, argv)
  int argc;
  char *argv[];
{
  int any_error= FALSE;
  int i, j;

  prog_name= strrchr(argv[0], '/');
  if (prog_name == NULL)
    prog_name= argv[0];
  else
    ++prog_name;
  for (i= 1; !any_error && i < argc; ++i)
    if (argv[i][j= 0] == '-')
      switch (argv[i][++j])
      { case 'h':
	  prog_flag.put_help= TRUE;
	  if (argv[i][++j] != '\0')
	    any_error= TRUE;
	  break;
	case 'c':
	{ int argcnt;
	  unsigned value;
	  char end;

	  argcnt= sscanf(&argv[i][++j], "%u %c", &value, &end);
	  if (argcnt == EOF)
	    prog_flag.add_cmt= 1;
	  else if (argcnt == 1 && value <= 2)
	    prog_flag.add_cmt= value;
	  else
	    any_error= TRUE;
	  break;
	}
	case 'i':
	{ int argcnt;
	  unsigned value;
	  char end;

	  argcnt= sscanf(&argv[i][++j], "%u %c", &value, &end);
	  if (argcnt == EOF)
	    prog_flag.indt_incr= DFL_INDT_INCR;
	  else if (argcnt == 1 && value <= MAX_INDT_INCR)
	    prog_flag.indt_incr= value;
	  else
	    any_error= TRUE;
	  break;
	}
	default:
	  any_error= TRUE;
	  break;
      }
    else
      any_error= TRUE;
  if (any_error)
  { usage();
    exit(2);
  }
  if (prog_flag.put_help)
  { help();
    exit(0);
  }
}

PUBLIC int
main (argc, argv)
  int argc;
  char *argv[];
{
  sREC *rec;

  proc_arg(argc, argv);
  rec= trn_init();
  rec= skp_ldc_ant(rec);
  rec= skp_ldi_ant(rec);
  rec= skp_lde_ant(rec);
  rec= trn_srt_dcls(rec);
  rec= trn_opn_dcls(rec);
  rec= trn_end(rec);
  exit(0);
  return 0;
}
