/***********************************
  (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 $Log: emit.c,v $
 * Revision 1.5  1993/08/02  16:59:33  lotos
 * fix declaration of flagxxxx (warning)
 *
 * Revision 1.4  1993/06/23  16:27:36  lotos
 * adapt code generation to drive new ildi grammar
 *
 * Revision 1.3  1993/01/21  20:25:19  lotos
 * code generation for ildi
 *
 * Revision 1.2  1993/01/20  13:43:24  lotos
 * distribution issues
 *
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: emit.c,v 1.5 1993/08/02 16:59:33 lotos Exp $";
#endif

#include "emit.h"
#include "scopes.h"
#include "tfilter.h"
#include "nodes.h"
#include "grc.h"

PUBLIC int flagtopo= FALSE;
PUBLIC int flaglola= FALSE;
PUBLIC int flagildi= FALSE;

PRIVATE void
PrintNext ()
{
  if (flagtopo)
    (void) printf (">>\n");
  else if (flaglola)
    (void) printf ("[]\n");
  /*
  else if (flagildi)
  */
}

PRIVATE void
genlet1 (this, id1, val1, id2, val2, testcaselist)
  scope *this;
  char *id1, *id2;
  TNODE *val1, *val2;
  TNODE* testcaselist;
{
  if (flagtopo || flaglola) {
    (void) printf ("( let %s: %s= ", id1, this->decl);
    EmitValueExpression (val1);
    if (val2 != NULL) {
      (void) printf (",\n");
      (void) printf ("      %s: %s= ", id2, this->decl);
      EmitValueExpression (val2);
    }
    (void) printf (" in\n");
  }
  else if (flagildi) {
    (void) printf ("var %s: %s\n", id1, this->decl);
    (void) printf ("let %s= ", id1);
    EmitValueExpression (val1);
    (void) printf ("\n");
    if (val2 != NULL) {
      (void) printf ("var %s: %s\n", id2, this->decl);
      (void) printf ("let %s= ", id2);
      EmitValueExpression (val2);
      (void) printf ("\n");
    }
  }
}

PRIVATE void
genlet2 ()
{
  if (flagtopo || flaglola)
    (void) printf (")\n");
}

PRIVATE void
genall (scp, ldefs, testcaselist)
  scope* scp;
  STRlist ldefs;
  TNODE* testcaselist;
{
  scope* this;
  char* id;
  TNODE* val;

  if (ldefs == NULL)
    EmitTestCaseList (testcaselist);
  else {
    id= (char*) STRhead (ldefs);
    this= lookup (scp, id);
    for (val= this->set; val != NULL; val= val->brothers) {
      genlet1 (this, id, val,
	       (char*) NULL, (TNODE*) NULL, testcaselist);
      genall (scp, STRtail (ldefs), testcaselist);
      genlet2 ();
      if (val->brothers != NULL)
        PrintNext ();
    }
  }
}

PRIVATE void
gen_ne (id1, id2, scp, testcaselist)
  char *id1, *id2;
  scope* scp;
  TNODE* testcaselist;
{
  scope* this;
  TNODE* val1;
  TNODE* val2;
  int c1, c2;

  this= lookup (scp, id1);
  for (val1= this->set, c1= 0;
       val1 != NULL;
       val1= val1->brothers, c1++)
    for (val2= this->set, c2= 0;
	 val2 != NULL;
	 val2= val2->brothers, c2++)
      if (c1 != c2) {
	genlet1 (this, id1, val1, id2, val2, testcaselist);
	EmitTestCaseList (testcaselist);
	genlet2 ();
        PrintNext ();
      }
}

PRIVATE void
gen_lt (id1, id2, scp, testcaselist)
  char *id1, *id2;
  scope* scp;
  TNODE* testcaselist;
{
  scope* this;
  TNODE* val1;
  TNODE* val2;
  int c1, c2;

  this= lookup (scp, id1);
  for (val1= this->set, c1= 0;
       val1 != NULL;
       val1= val1->brothers, c1++)
    for (val2= this->set, c2= 0;
	 val2 != NULL;
	 val2= val2->brothers, c2++)
      if (c1 < c2) {
	genlet1 (this, id1, val1, id2, val2, testcaselist);
	EmitTestCaseList (testcaselist);
	genlet2 ();
        PrintNext ();
      }
}

PRIVATE void
gen_le (id1, id2, scp, testcaselist)
  char *id1, *id2;
  scope* scp;
  TNODE* testcaselist;
{
  scope* this;
  TNODE* val1;
  TNODE* val2;
  int c1, c2;

  this= lookup (scp, id1);
  for (val1= this->set, c1= 0;
       val1 != NULL;
       val1= val1->brothers, c1++)
    for (val2= this->set, c2= 0;
	 val2 != NULL;
	 val2= val2->brothers, c2++)
      if (c1 <= c2) {
	genlet1 (this, id1, val1, id2, val2, testcaselist);
	EmitTestCaseList (testcaselist);
	genlet2 ();
        PrintNext ();
      }
}

PRIVATE void
gen_gt (id1, id2, scp, testcaselist)
  char *id1, *id2;
  scope* scp;
  TNODE* testcaselist;
{
  scope* this;
  TNODE* val1;
  TNODE* val2;
  int c1, c2;

  this= lookup (scp, id1);
  for (val1= this->set, c1= 0;
       val1 != NULL;
       val1= val1->brothers, c1++)
    for (val2= this->set, c2= 0;
	 val2 != NULL;
	 val2= val2->brothers, c2++)
      if (c1 > c2) {
	genlet1 (this, id1, val1, id2, val2, testcaselist);
	EmitTestCaseList (testcaselist);
	genlet2 ();
        PrintNext ();
      }
}

PRIVATE void
gen_ge (id1, id2, scp, testcaselist)
  char *id1, *id2;
  scope* scp;
  TNODE* testcaselist;
{
  scope* this;
  TNODE* val1;
  TNODE* val2;
  int c1, c2;

  this= lookup (scp, id1);
  for (val1= this->set, c1= 0;
       val1 != NULL;
       val1= val1->brothers, c1++)
    for (val2= this->set, c2= 0;
	 val2 != NULL;
	 val2= val2->brothers, c2++)
      if (c1 >= c2) {
	genlet1 (this, id1, val1, id2, val2, testcaselist);
	EmitTestCaseList (testcaselist);
	genlet2 ();
        PrintNext ();
      }
}

PRIVATE void
genblock (scp, ldefs, testcaselist)
  scope* scp;
  STRlist ldefs;
  TNODE* testcaselist;
{
  char *id1, *id2, *matrix;

  if (STRlength (ldefs) == 3) {
    id1= STRhead (ldefs);
    matrix= STRhead (STRtail (ldefs));
    id2= STRhead (STRtail (STRtail (ldefs)));
    if (strcmp (matrix, "<>") == 0) {
      gen_ne (id1, id2, scp, testcaselist);
      return;
    }
    if (strcmp (matrix, "<") == 0) {
      gen_lt (id1, id2, scp, testcaselist);
      return;
    }
    if (strcmp (matrix, "<=") == 0) {
      gen_le (id1, id2, scp, testcaselist);
      return;
    }
    if (strcmp (matrix, ">") == 0) {
      gen_gt (id1, id2, scp, testcaselist);
      return;
    }
    if (strcmp (matrix, ">=") == 0) {
      gen_ge (id1, id2, scp, testcaselist);
      return;
    }
  }
  genall (scp, ldefs, testcaselist);
  PrintNext ();
}

PRIVATE void
format (last)
  int last;
{
  int i;

  for (i= 0; i < last; i++) {
    if (i % 10 == 0) {
      printf ("\n");
      printf ("      ");
    }
    printf ("t%d, ", i);
  }
  printf ("t%d", last);
}

/****************    emit    ************************/

/* _specification ::= [ _object + ] */
PUBLIC void
EmitSpecification (nd)
  TNODE* nd;
{
  TNODE* n;

  assert (nd->type == tspecification);

  if (flagtopo) {
    printf ("(*--> do topo %%F -p\n");
    printf ("**********************************)\n");
    printf ("\n");
    printf ("specification Types_Tester : noexit\n");
    printf ("\n");
  }
  else if (flaglola) {
    printf ("(*--> do topo %%F -lola\n");
    printf ("lola> test -1 OK RunTest\n");
    printf ("**********************************)\n");
    printf ("\n");
    printf ("specification Types_Tester\n");
    printf ("              [premiss, accpt, reject, pass, fail] : noexit\n");
    printf ("\n");
  }
  else if (flagildi) {
    printf ("--> do topo %s -ildi < %%F\n", RootFileName);
    printf ("\n");
  }

  if (flagtopo || flaglola) {
    sm (ofp, stdout);
    printf ("behaviour\n");
  }

  for (n= nd->sons; n != NULL; n= n->brothers) {
    EmitObject (n);
  }

  if (flagtopo) {
    printf ("  stop\n");
    printf ("endspec\n");
  }

  if (flaglola) {
    printf ("  stop\n");
    printf ("\n");
    printf ("where\n");
    printf ("  type TestCaseTypes is\n");
    printf ("    sorts TestCase\n");
    printf ("    opns");
    format (LastTestCase);
    printf (": -> TestCase\n");
    printf ("    endtype\n");
    printf ("\n");
    printf ("  process RunTest [accpt, reject, pass, fail, OK]: noexit :=\n");
    printf ("      accpt ?n: TestCase ; pass ; OK ; stop\n");
    printf ("    []\n");
    printf ("      reject ?n: TestCase ;\n");
    printf ("      ( fail ; stop\n");
    printf ("      []\n");
    printf ("        i ; OK ; stop\n");
    printf ("      )\n");
    printf ("    endproc\n");
    printf ("endspec\n");
  }
}

PUBLIC void
EmitObject (nd)
  TNODE* nd;
{
  int* rules;
  int rule;

  assert (nd->type == tobject);
  rules= grnl->data[(int)(nd->value0)];
  for (rule= 0; rules[rule] != 0; rule++)
    switch (rules[rule]) {

/* _object ::= _definition */
    case _object_1:
      break;

/* _object ::= _test_case_block */
    case _object_2:
      EmitTestCaseBlock (nd->sons);
      break;
    }
}

PUBLIC void
EmitTestCaseBlock (nd)
  TNODE* nd;
{
  int* rules;
  int rule;

  assert (nd->type == ttest_case_block);
  rules= grnl->data[(int)(nd->value0)];
  for (rule= 0; rules[rule] != 0; rule++)
    switch (rules[rule]) {

/* _test_case_block ::= _test_case */
    case _test_case_block_1:
      EmitTestCase (nd->sons);
      PrintNext ();
      break;

/* _test_case_block ::=
**    _local_definition_list '[' '[' _test_case_list ']' ']'
*/
    case _test_case_block_2:
      genblock ((scope*) fdclr (c_scopeout, nd->sons, -33),
                (STRlist) fdclr (c_ldefs, nd->sons, -34),
		nd->sons->brothers);
      break;
    }
}

/* _test_case_list ::= [ _test_case + ] */
PUBLIC void
EmitTestCaseList (nd)
  TNODE* nd;
{
  TNODE* n;

  assert (nd->type == ttest_case_list);
  for (n= nd->sons; n != NULL; n= n->brothers) {
    EmitTestCase (n);
    if (n->brothers != NULL) {
      PrintNext ();
    }
  }
}

PUBLIC void
EmitTestCase (nd)
  TNODE* nd;
{
  int* rules;
  int rule;
  int Npremisses;

  assert (nd->type == ttest_case);
  LastTestCase++;
  rules= grnl->data[(int)(nd->value0)];
  for (rule= 0; rules[rule] != 0; rule++)
    switch (rules[rule]) {

/* _test_case ::= _assertion ';' */
    case _test_case_1:
      EmitAssertion (nd->sons);
      break;

/* _test_case ::= _premisses IMPLICATION _assertion ';' */
    case _test_case_2:
      nd= nd->sons;

      if (flagtopo) {
	printf ("    [");
	(void) EmitPremisses (nd);
	printf ("]-> i (*| C printf (\"premiss OK %d\\n\"); |*) ; (\n",
	        LastTestCase);
	nd= nd->brothers;
	EmitAssertion (nd);
	printf ("    )\n");
	printf ("  []\n");
	printf ("    (*| priority -10 |*) i");
	printf (" (*| C printf (\"inconclusive %d\\n\"); |*) ; exit\n",
	        LastTestCase);
      }
      else if (flaglola) {
	printf ("    premiss !t%d ; ([",
	        LastTestCase);
	(void) EmitPremisses (nd);
	printf ("]-> (\n");
	nd= nd->brothers;
	EmitAssertion (nd);
	printf ("    ))\n");
      }
      else if (flagildi) {
        printf ("if (");
	Npremisses= EmitPremisses (nd);
	printf (")\n");
	nd= nd->brothers;
	EmitAssertion (nd);
	while (Npremisses > 0) {
	  printf ("else\n");
	  printf ("  write \"inconclusive %d (premiss #%d)\"\n",
		  LastTestCase, Npremisses);
	  printf ("fi\n");
	  Npremisses--;
	}
      }

      break;
    }
}

PUBLIC void
EmitAssertion (nd)
  TNODE* nd;
{
  int* rules;
  int rule;

  assert (nd->type == tassertion);
  rules= grnl->data[(int)(nd->value0)];
  for (rule= 0; rules[rule] != 0; rule++)
    switch (rules[rule]) {

/* _assertion ::= _simple_equation */
    case _assertion_1:
      nd= nd->sons;

      if (flagtopo) {
	printf ("    [");
	EmitSimpleEquation (nd);
	printf ("]-> i (*| C printf (\"pass %d\\n\"); |*) ; exit\n",
	        LastTestCase);
	printf ("  []\n");
	printf ("    (*| priority -10 |*) i\n");
	printf ("    (*| C printf (\"fail %d\\n\"); |*) ; exit\n",
	        LastTestCase);
      }
      else if (flaglola) {
	printf ("    accpt !t%d; ([",
	        LastTestCase);
	EmitSimpleEquation (nd);
	printf ("]-> pass; stop)\n");
      }
      else if (flagildi) {
	printf ("write \"accept %d\"\n", LastTestCase);
	printf ("  check ");
	EmitSimpleEquation (nd);
	printf ("\n");
      }

      break;

/* _assertion ::= _value_expression */
    case _assertion_2:
      nd= nd->sons;

      if (flagtopo) {
	printf ("    [");
	EmitValueExpression (nd);
	printf ("]-> i (*| C printf (\"pass %d\\n\"); |*) ; exit\n",
	        LastTestCase);
	printf ("  []\n");
	printf ("    (*| priority -10 |*) i\n");
	printf ("    (*| C printf (\"fail %d\\n\"); |*) ; exit\n",
	        LastTestCase);
      }
      else if (flaglola) {
	printf ("    accpt !t%d; ([",
	        LastTestCase);
	EmitValueExpression (nd);
	printf ("]-> pass; stop)\n");
      }
      else if (flagildi) {
	printf ("write \"accept %d\"\n", LastTestCase);
	printf ("  check ");
	EmitValueExpression (nd);
	printf (" = TRUE\n");
      }

      break;

/* _assertion :: _value_expression '!' '=' _value_expression */
    case _assertion_3:
      nd= nd->sons;

      if (flagtopo) {
	printf ("    [");
	EmitValueExpression (nd);
	printf (" = ");
	nd= nd->brothers;
	EmitValueExpression (nd);
	printf ("]-> i (*| C printf (\"fail %d\\n\"); |*) ; exit\n",
	        LastTestCase);
	printf ("  []\n");
	printf ("    (*| priority -10 |*) i\n");
	printf ("    (*| C printf (\"pass %d\\n\"); |*) ; exit\n",
	        LastTestCase);
      }
      else if (flaglola) {
	printf ("    reject !t%d; ([",
	        LastTestCase);
	EmitValueExpression (nd);
	printf (" = ");
	nd= nd->brothers;
	EmitValueExpression (nd);
	printf ("]-> fail; stop)\n");
      }
      else if (flagildi) {
	printf ("write \"reject %d\"\n", LastTestCase);
	printf ("  check ");
	EmitValueExpression (nd);
	printf (" = ");
	nd= nd->brothers;
	EmitValueExpression (nd);
	printf ("\n");
      }

      break;
    }
}

/* _premisses ::= [ _premiss + ',' ] */
PUBLIC int
EmitPremisses (nd)
  TNODE* nd;
{
  TNODE* n;
  int Npremisses= 0;

  assert (nd->type == tpremisses);
  for (n= nd->sons; n != NULL; n= n->brothers) {
    Npremisses++;
    EmitPremiss (n);
    if (n->brothers != NULL) {
      if (flagtopo || flaglola)
	printf ("]-> [");
      else if (flagildi)
	printf (") if (");
    }
  }
  return Npremisses;
}

PUBLIC void
EmitPremiss (nd)
  TNODE* nd;
{
  int* rules;
  int rule;

  assert (nd->type == tpremiss);
  rules= grnl->data[(int)(nd->value0)];
  for (rule= 0; rules[rule] != 0; rule++)
    switch (rules[rule]) {

/* _premiss ::= _simple_equation */
    case _premiss_1:
      EmitSimpleEquation (nd->sons);
      break;

/* _premiss ::= _value_expression */
    case _premiss_2:
      EmitValueExpression (nd->sons);
      if (flagildi)
        printf (" = TRUE");
      break;
    }
}

/* _simple_equation ::= _value_expression '=' _value_expression */
PUBLIC void
EmitSimpleEquation (nd)
  TNODE* nd;
{
  assert (nd->type == tsimple_equation);
  nd= nd->sons;
  EmitValueExpression (nd);
  printf (" = ");
  nd= nd->brothers;
  EmitValueExpression (nd);
}

PUBLIC void
EmitValueExpressionList (nd)
  TNODE* nd;
{
  TNODE* n;

  assert (nd->type == tvalue_expression_list);
  for (n= nd->sons; n != NULL; n= n->brothers) {
    EmitValueExpression (n);
    if (n->brothers != NULL)
      printf (", ");
  }
}

PUBLIC void
EmitValueExpression (nd)
  TNODE* nd;
{
  int* rules;
  int rule;

  assert (nd->type == tvalue_expression);
  rules= grnl->data[(int)(nd->value0)];
  for (rule= 0; rules[rule] != 0; rule++)
    switch (rules[rule]) {

/* rule
**  _value_expression ::=
**      _term_expression [ OF _sort_identifier ]
*/
    case _value_expression_1:
      nd= nd->sons;
      EmitTermExpression (nd);
      nd= nd->brothers;
      if (nd != NULL)
	printf (" of %s", l2s (find_attr (c_lexv, nd)->value));
      break;

/* rule
**  _value_expression ::=
**      _value_expression _operation_identifier _term_expression
**      [ OF _sort_identifier ]
*/
    case _value_expression_2:
      nd= nd->sons;
      if (flagtopo || flaglola || flagildi) {
	EmitValueExpression (nd);
	nd= nd->brothers;
	printf (" %s ", l2s (find_attr (c_lexv, nd)->value));
	nd= nd->brothers;
	EmitTermExpression (nd);
	nd= nd->brothers;
	if (nd != NULL)
	  printf (" of %s", l2s (find_attr (c_lexv, nd)->value));
      }

/*
      if (flagildi) {
	printf ("%s (", l2s (find_attr (c_lexv, nd->brothers)->value));
	EmitValueExpression (nd);
	printf (", ");
	EmitTermExpression (nd->brothers->brothers);
	printf (")");
      }
*/

      break;
    }
}

PUBLIC void
EmitTermExpression (nd)
  TNODE* nd;
{
  int* rules;
  int rule;

  assert (nd->type == tterm_expression);
  rules= grnl->data[(int)(nd->value0)];
  for (rule= 0; rules[rule] != 0; rule++)
    switch (rules[rule]) {

/* rule
**  _term_expression ::=
**      _operation_identifier [ '(' _value_expression_list ')' ]
*/
    case _term_expression_1:
      nd= nd->sons;
      printf ("%s", l2s (find_attr (c_lexv, nd)->value));
      nd= nd->brothers;
      if (nd) {
        printf (" (");
        EmitValueExpressionList (nd);
        printf (")");
      }
      break;

/* rule
**  _term_expression ::=
**      '(' _value_expression ')'
*/
    case _term_expression_2:
      nd= nd->sons;
      printf (" (");
      EmitValueExpression (nd);
      printf (")");
      break;

/* rule
**  _term_expression ::=
**      '(' error ')'
    case _term_expression_3:
*/
    }
}

