/**CFile*******************************************************************
  PackageName [ccs]
  Synopsis    [Package 'ccs' provides an extended CCS parser.]

  FileName    [ccsVerilog.y]
  Revision    [$Revision: 76 $]
  Date        [$Date: 2013-04-26 14:26:09 +0200 (pet, 26 apr 2013) $]
  Authors     [Robert Meolic (meolic@uni-mb.si)]
  Description [File ccsVerilog.y is a bison file for Verilog parser.]
  SeeAlso     [ccs.h, ccsInt.h, ccsVerilog.l]

  Copyright   [This file is part of EST (Efficient Symbolic Tools).
               Copyright (C) 2003, 2013
               UM-FERI, Smetanova ulica 17, SI-2000 Maribor, Slovenia

               EST is free software; you can redistribute it and/or modify
               it under the terms of the GNU General Public License as
               published by the Free Software Foundation; either version 2
               of the License, or (at your option) any later version.

               EST is distributed in the hope that it will be useful,
               but WITHOUT ANY WARRANTY; without even the implied warranty of
               MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
               GNU General Public License for more details.

               You should have received a copy of the GNU General Public
               License along with this program; if not, write to the Free
               Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
               Boston, MA 02110-1301 USA.]
  ************************************************************************/

%{
#include "ccsInt.h"
#define YYERROR_VERBOSE
#define MAX_ARGS 10
%}

%{
   static void addWire(Est_String name);
   static int error(const char *s);
%}

%{
  extern int yylex(void);
  int yywrap();
  int yyerror(const char *s);
%}

%{
    /* UNEXPECTED SIDEEFFECT ON SOME SYSTEMS */
    /* THE VARIABLES DEFINED HERE ARE NOT ALWAYS LOCAL, THEY CAN BE GLOBAL! */
    /* THEREFORE, I USE A PREFIX FOR EACH VARIABLE */

    /* VERILOGcomp = FALSE (general model) */
    /* VERILOGcomp = TRUE (compositional model) */
    Est_Boolean VERILOGcomp = FALSE;

    FILE *VERILOGout = NULL;
    int VERILOGnum = 0;
    Est_String VERILOGarg[MAX_ARGS] = {NULL};
    Est_String VERILOGwires = NULL;
    Est_Boolean VERILOGcomma = FALSE;
    Est_Boolean VERILOGflipflop = FALSE;
    Est_Boolean VERILOGfork = FALSE;
    int VERILOGpass = 0; /* verilog parser has two passes */
%}

%union {
  Est_String word;
  Est_String line;
}


%token UNKNOWN
%token <word> MODULE ENDMODULE INPUT OUTPUT ASSIGN
%token <word> WIRE FORK NOT NAME
%token <word> AND ANDINV OR ORINV NAND NOR XOR
%token <word> C CINV ME MEZ
%token <word> DFF TFF DQBFF TQBFF
%token <word> RSFF JKFF RSQBFF JKQBFF

%%
start   : modules ;

modules : module modules
        | module ;

module  : MODULE NAME {

            Est_String name;
            int i;

            name = strdup($2);

            VERILOGnum = -7; /* void */

            for (i=0; i<MAX_ARGS; i++) {
              VERILOGarg[i] = NULL;
            }
            VERILOGwires = NULL;
            VERILOGcomma = FALSE;
            VERILOGflipflop = FALSE;
            VERILOGfork = FALSE;

            if (VERILOGpass == 1) {

            }

            if (VERILOGpass == 2) {

              if (!VERILOGcomp) {
                fprintf(VERILOGout,"circuit %s = /// (\n",name);
              } else {
                fprintf(VERILOGout,"/* COMPOSITIONAL MODE */\n\n");
              }

            }

            free(name);

          }

          '('
          list {}
          ')' ';'
          inout {}
          wires {}
          instances {}
          ENDMODULE {
            if (VERILOGpass == 1) {
            }

            if (VERILOGpass == 2) {

              if (!VERILOGcomp) {
                fprintf(VERILOGout,"\n)");
                if (VERILOGwires) {
                  fprintf(VERILOGout,"%s",VERILOGwires);
                  free(VERILOGwires);
                }
                fprintf(VERILOGout,"\n");

              } else {
                fprintf(VERILOGout,"\n");
              }
            }

          } ;

inout   : inputs {} inout
        | outputs {} inout
        | ;

inputs  : INPUT {

            if (VERILOGpass == 1) {
              /* ALL INPUTS ARE INITIALY ZERO */
              VERILOGnum = -2; /* set 0 */
            }

            if (VERILOGpass == 2) {
              VERILOGnum = -7; /* void */
            }

          }

          list {

            int i;

            if (VERILOGpass == 1) {

              for (i=0; i<VERILOGnum; i++) {

                /* ALL INPUTS ARE INITIALY ZERO */
                Bdd_AddFormula(VERILOGarg[i],bdd_termFalse);

                free(VERILOGarg[i]);
                VERILOGarg[i] = NULL;
              }

            }

            if (VERILOGpass == 2) {}

          } ';' ;

outputs : OUTPUT {

            VERILOGnum = -7; /* void */

          }

          list {} ';' ;

wires   : wire {} wires
          | ;

wire    : WIRE {

            if (VERILOGpass == 1) {

              VERILOGnum = -3; /* set X */

            }

            if (VERILOGpass == 2) {

              VERILOGnum = -1; /* add list */

            }

          }

          list {} ';' ;

instances : instance ';' {

              int i;

              if (VERILOGpass == 1) {
              }

              if (VERILOGpass == 2) {

                fprintf(VERILOGout," ");
                if (VERILOGflipflop) {

                  for (i=VERILOGnum-1; i>0; i--) {
                    fprintf(VERILOGout,"[%s/%c]",VERILOGarg[i],'a'+VERILOGnum-i-1);
                  }
                  VERILOGflipflop = FALSE;

                } else if (VERILOGfork) {

                  for (i=2; i<VERILOGnum; i++) {
                    fprintf(VERILOGout,"[%s/%c]",VERILOGarg[i],'a'+i-2);
                  }
                  fprintf(VERILOGout,"[%s/%c]",VERILOGarg[0],'a'+VERILOGnum-2);
                  fprintf(VERILOGout,"[%s/%c]",VERILOGarg[1],'a'+VERILOGnum-1);
                  VERILOGfork = FALSE;

                } else {

                  for (i=1; i<VERILOGnum; i++) {
                    fprintf(VERILOGout,"[%s/%c]",VERILOGarg[i],'a'+i-1);
                  }
                  fprintf(VERILOGout,"[%s/%c]",VERILOGarg[0],'a'+VERILOGnum-1);

                }

                if (!VERILOGcomp) {

                  VERILOGcomma = TRUE;

                } else {

                  for (i=1; i<VERILOGnum; i++) {
                    fprintf(VERILOGout,",\n  %s",VERILOGarg[i]);
                  }
                  fprintf(VERILOGout,"\n)\n");

                }
              }

              for (i=0; i<VERILOGnum; i++) {
                free(VERILOGarg[i]);
                VERILOGarg[i] = NULL;
              }

            } instances

          | ;

instance  : ASSIGN NAME '=' NAME {

              Bdd_Edge f;

              /*
              fprintf(stderr,"assign\n");
              */

              VERILOGarg[0] = strdup($2);
              VERILOGarg[1] = strdup($4);
              VERILOGnum = 2;

              if (VERILOGpass == 1) {

                if (!Bdd_FindFormula(VERILOGarg[1],&f)) {
                  printf("Error in Verilog parser (ASSIGN)!");
                  YYERROR;
                }
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {

                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);

                }

                fprintf(VERILOGout,"  WIRE");

              }
            }

          | FORK NAME {

              /*
              fprintf(stderr,"fork\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              Bdd_Edge f;

              if (VERILOGpass == 1) {

                if (!Bdd_FindFormula(VERILOGarg[2],&f)) {
                  printf("Error in Verilog parser (FORK)!");
                  YYERROR;
                }
                Bdd_AddFormula(VERILOGarg[0],f);
                Bdd_AddFormula(VERILOGarg[1],f);

              }

              if (VERILOGpass == 2) {

                VERILOGfork = TRUE;

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {

                  fprintf(VERILOGout,"FORK HAS TWO OUTPUTS - NOT SUPORTED!\n");

                }

                fprintf(VERILOGout,"  FORK");
              }

            }

            ')'

          | NOT NAME {

              /*
              fprintf(stderr,"not\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              Bdd_Edge f;

              if (VERILOGpass == 1) {

                if (!Bdd_FindFormula(VERILOGarg[1],&f)) {
                  printf("Error in Verilog parser (NOT)!");
                  YYERROR;
                }
                f = Bdd_NOT(f);
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {

                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);

                }

                fprintf(VERILOGout,"  INV");
              }

            }

            ')'

          | AND NAME {

              /*
              fprintf(stderr,"and\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                f = bdd_termTrue;
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&g)) {
                    printf("Error in Verilog parser (AND)!");
                    YYERROR;
                  }
                  f = Bdd_ITE(f,g,bdd_termFalse);
                }
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {

                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);

                }

                fprintf(VERILOGout,"  AND-");
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (AND-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | ANDINV NAME {

              /* FIRST INPUT IS INVERTED */

              /*
              fprintf(stderr,"andinv\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&g)) {
                    printf("Error in Verilog parser (ANDINV)!");
                    YYERROR;
                  }

                  if (i==1) {
                    f = Bdd_NOT(g); /* FIRST INPUT IS INVERTED */
                  } else {
                    f = Bdd_ITE(f,g,bdd_termFalse);
                  }
                }
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);
                }

                fprintf(VERILOGout,"  AND-");
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (ANDINV-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (i==1) {
                    /* FIRST INPUT IS INVERTED */
                    if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"1");
                    else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"0");
                    else fprintf(VERILOGout,"X");
                  } else {
                    if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                    else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                    else fprintf(VERILOGout,"X");
                  }
                }
              }

            }

            ')'

          | OR NAME {

            /*
            fprintf(stderr,"or\n");
            */

            VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                f = bdd_termFalse;
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&g)) {
                    printf("Error in Verilog parser (OR)!");
                    YYERROR;
                  }
                  f = Bdd_ITE(f,bdd_termTrue,g);
                }
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {

                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);

                }

                fprintf(VERILOGout,"  OR-");
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (OR-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | ORINV NAME {

              /* FIRST INPUT IS INVERTED */

              /*
              fprintf(stderr,"orinv\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&g)) {
                    printf("Error in Verilog parser (ORINV)!");
                    YYERROR;
                  }
                  if (i==1) {
                    f = Bdd_NOT(g); /* FIRST INPUT IS INVERTED */
                  } else {
                    f = Bdd_ITE(f,bdd_termTrue,g);
                  }
                }
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);
                }

                fprintf(VERILOGout,"  OR-");
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (ORINV-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (i==1) {
                    /* FIRST INPUT IS INVERTED */
                    if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"1");
                    else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"0");
                    else fprintf(VERILOGout,"X");
                  } else {
                    if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                    else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                    else fprintf(VERILOGout,"X");
                  }
                }
              }

            }

            ')'

          | NAND NAME {

              /*
              fprintf(stderr,"nand\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                f = bdd_termTrue;
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&g)) {
                    printf("Error in Verilog parser (NAND)!");
                    YYERROR;
                  }
                  f = Bdd_ITE(f,g,bdd_termFalse);
                }
                f = Bdd_NOT(f);
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {

                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);

                }

                fprintf(VERILOGout,"  NAND-");
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (NAND-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");

                }

              }
            }

            ')'

          | NOR NAME {

              /*
              fprintf(stderr,"nor\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                f = bdd_termFalse;
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&g)) {
                    printf("Error in Verilog parser (NOR)!");
                    YYERROR;
                  }
                  f = Bdd_ITE(f,bdd_termTrue,g);
                }
                f = Bdd_NOT(f);
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);
                }

                fprintf(VERILOGout,"  NOR-");
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (NOR-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | XOR NAME {

              /*
              fprintf(stderr,"xor\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                if (VERILOGnum>3) {
                  printf("WARNING: Verilog parser consider only the first three arguments for XOR\n");
                }

                if (!Bdd_FindFormula(VERILOGarg[1],&f)) {
                  printf("Error in Verilog parser (XOR)!");
                  YYERROR;
                }
                if (!Bdd_FindFormula(VERILOGarg[2],&g)) {
                  printf("Error in Verilog parser (XOR)!");
                  YYERROR;
                }
                f = Bdd_ITE(f,Bdd_NOT(g),g);
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                   }

                } else {
                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);
                }

                fprintf(VERILOGout,"  XOR-");
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (XOR-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | C NAME {

              /* USAGE: C(OUTPUT,INPUT1,INPUT2) */
              /*
              fprintf(stderr,"C\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                if (VERILOGnum>3) {
                  printf("WARNING: Verilog parser consider only the first three arguments for C\n");
                }

                if (!Bdd_FindFormula(VERILOGarg[1],&f)) {
                  printf("Error in Verilog parser (C)!");
                  YYERROR;
                }
                if (!Bdd_FindFormula(VERILOGarg[2],&g)) {
                  printf("Error in Verilog parser (C)!");
                  YYERROR;
                }

                /* OUTPUT OF C ELEMENT IS INITIALY ZERO */
                f = Bdd_ITE(f,g,bdd_termFalse);
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {

                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);

                }

                fprintf(VERILOGout,"  C-");
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (C-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | CINV NAME {

              /* USAGE: CINV(OUTPUT,INVERTED-INPUT,INPUT) */
              /*
              fprintf(stderr,"CINV\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                if (VERILOGnum>3) {
                  printf("WARNING: Verilog parser consider only the first three arguments for CINV\n");
                }

                if (!Bdd_FindFormula(VERILOGarg[1],&f)) {
                  printf("Error in Verilog parser (CINV)!");
                  YYERROR;
                }
                if (!Bdd_FindFormula(VERILOGarg[2],&g)) {
                  printf("Error in Verilog parser (CINV)!");
                  YYERROR;
                }

                /* OUTPUT OF C ELEMENT IS INITIALY ZERO */
                /* FIRST INPUT IS INVERTED */
                f = Bdd_ITE(f,bdd_termFalse,g);
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);
                }

                fprintf(VERILOGout,"  C-");
                for (i=1; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (CINV-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (i==1) {
                    /* FIRST INPUT IS INVERTED */
                    if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"1");
                    else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"0");
                    else fprintf(VERILOGout,"X");
                  } else {
                    if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                    else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                    else fprintf(VERILOGout,"X");
                  }
                }
              }

            }

            ')'

          | ME NAME {

              /* USAGE: ME(G1.G2,R1,R2) */
              /*
              fprintf(stderr,"ME\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                if (VERILOGnum>4) {
                  printf("WARNING: Verilog parser consider only the first 4 arguments for ME\n");
                }

                if (!Bdd_FindFormula(VERILOGarg[2],&f)) {
                  printf("Error in Verilog parser (ME)!");
                  YYERROR;
                }
                if (!Bdd_FindFormula(VERILOGarg[3],&g)) {
                  printf("Error in Verilog parser (ME)!");
                  YYERROR;
                }

                /* IF BOTH INPUTS ARE INITIALY ONE, THE FIRST OUTPUT IS ACKNOWLEDGED */
                Bdd_AddFormula(VERILOGarg[0],f);
                g = Bdd_ITE(f,bdd_termFalse,g);
                Bdd_AddFormula(VERILOGarg[1],g);

              }

              if (VERILOGpass == 2) {

                VERILOGfork = TRUE;

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"ME HAS TWO OUTPUTS - NOT SUPORTED!\n");
                }

                fprintf(VERILOGout,"  ME-");
                for (i=2; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (ME-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | MEZ NAME {

              /* USAGE: MEZ(G1.G2,R1,R2,Z) */
              /*
              fprintf(stderr,"MEZ\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g,z;

              if (VERILOGpass == 1) {

                if (VERILOGnum>5) {
                  printf("WARNING: Verilog parser consider only the first 5 arguments for MEZ\n");
                }

                if (!Bdd_FindFormula(VERILOGarg[2],&f)) {
                  printf("Error in Verilog parser (MEZ)!");
                  YYERROR;
                }
                if (!Bdd_FindFormula(VERILOGarg[3],&g)) {
                  printf("Error in Verilog parser (MEZ)!");
                  YYERROR;
                }
                if (!Bdd_FindFormula(VERILOGarg[4],&z)) {
                  printf("Error in Verilog parser (MEZ)!");
                  YYERROR;
                }

                /* IF BOTH INPUTS ARE INITIALY ONE AND Z, NONE IS ACKNOWLEDGED */
                /* IF BOTH INPUTS ARE INITIALY ONE AND NOT Z, THE FIRST OUTPUT IS ACK */
                g = Bdd_ITE(f,bdd_termFalse,g);
                g = Bdd_ITE(z,bdd_termFalse,g);
                Bdd_AddFormula(VERILOGarg[1],g);
                f = Bdd_ITE(z,bdd_termFalse,f);
                Bdd_AddFormula(VERILOGarg[0],f);

              }

              if (VERILOGpass == 2) {

                VERILOGfork = TRUE;

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"MEZ HAS TWO OUTPUTS - NOT SUPORTED!\n");
                }

                fprintf(VERILOGout,"  MEZ-");
                for (i=2; i<VERILOGnum; i++) {
                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (MEZ-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | DFF NAME {

              /* USAGE: DFF(CLOCK,OUTPUT,D) */
              /*
              fprintf(stderr,"dff\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f;

              if (VERILOGpass == 1) {

                if (!Bdd_FindFormula(VERILOGarg[2],&f)) {
                  printf("Error in Verilog parser (DFF)!");
                  YYERROR;
                }

                /* ALL FLIP-FLOPS ARE INITIALY ZERO */
                Bdd_AddFormula(VERILOGarg[1],bdd_termFalse);

                /* CLOCK IS NOT USED */
                Bdd_AddFormula(VERILOGarg[0],bdd_termNull);
              }

              if (VERILOGpass == 2) {

                VERILOGflipflop = TRUE;

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);
                }

                fprintf(VERILOGout,"  D-");
                for (i=2; i>=1; i--) {  /* INPUTS AND STATE */

                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (DFF-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | DQBFF NAME {

              /* USAGE: DFF(CLOCK,INVERTED,OUTPUT,D) */
              /*
              fprintf(stderr,"dqbff\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f;

              if (VERILOGpass == 1) {

                if (!Bdd_FindFormula(VERILOGarg[3],&f)) {
                  printf("Error in Verilog parser (DQBFF)!");
                  YYERROR;
                }

                /* ALL FLIP-FLOPS ARE INITIALY ZERO */
                Bdd_AddFormula(VERILOGarg[1],bdd_termTrue); /* INVERTED OUTPUT */
                Bdd_AddFormula(VERILOGarg[2],bdd_termFalse);

                /* CLOCK IS NOT USED */
                Bdd_AddFormula(VERILOGarg[0],bdd_termNull);
              }

              if (VERILOGpass == 2) {

                VERILOGflipflop = TRUE;

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"DQBFF HAS TWO OUTPUTS - NOT SUPORTED!\n");
                }

                fprintf(VERILOGout,"  DQB-");
                for (i=3; i>=2; i--) {  /* INPUTS AND STATE */

                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (DQBFF-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | RSFF NAME {

              /* USAGE: RSFF(CLOCK,OUTPUT,S,R) */
              /*
              fprintf(stderr,"rsff\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                if (!Bdd_FindFormula(VERILOGarg[2],&f)) {
                  printf("Error in Verilog parser (RSFF)!");
                  YYERROR;
                }

                if (!Bdd_FindFormula(VERILOGarg[3],&g)) {
                  printf("Error in Verilog parser (RSFF)!");
                  YYERROR;
                }

                /* ALL FLIP-FLOPS ARE INITIALY ZERO */
                Bdd_AddFormula(VERILOGarg[1],bdd_termFalse);

                /* CLOCK IS NOT USED */
                Bdd_AddFormula(VERILOGarg[0],bdd_termNull);

              }

              if (VERILOGpass == 2) {

                VERILOGflipflop = TRUE;

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"circuit %s = /// (\n",VERILOGarg[0]);
                }

                fprintf(VERILOGout,"  RS-");
                for (i=3; i>=1; i--) {  /* INPUTS AND STATE */

                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (RSFF-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')'

          | RSQBFF NAME {

              /* USAGE: RSQBFF(CLOCK,INVERTED,OUTPUT,S,R) */
              /*
              fprintf(stderr,"rsqbff\n");
              */

              VERILOGnum = 0; /* add table */

            }

            '('

            list {

              int i;
              Bdd_Edge f,g;

              if (VERILOGpass == 1) {

                if (!Bdd_FindFormula(VERILOGarg[3],&f)) {
                  printf("Error in Verilog parser (RSQBFF)!");
                  YYERROR;
                }

                if (!Bdd_FindFormula(VERILOGarg[4],&g)) {
                  printf("Error in Verilog parser (RSQBFF)!");
                  YYERROR;
                }

                /* ALL FLIP-FLOPS ARE INITIALY ZERO */
                Bdd_AddFormula(VERILOGarg[1],bdd_termTrue); /* INVERTED OUTPUT */
                Bdd_AddFormula(VERILOGarg[2],bdd_termFalse);

                /* CLOCK IS NOT USED */
                Bdd_AddFormula(VERILOGarg[0],bdd_termNull);
              }

              if (VERILOGpass == 2) {

                VERILOGflipflop = TRUE;

                if (!VERILOGcomp) {

                  if (VERILOGcomma) {
                    fprintf(VERILOGout,",\n");
                  }

                } else {
                  fprintf(VERILOGout,"RSQBFF HAS TWO OUTPUTS - NOT SUPORTED!\n");
                }

                fprintf(VERILOGout,"  RSQB-");
                for (i=4; i>=2; i--) {  /* INPUTS AND STATE */

                  if (!Bdd_FindFormula(VERILOGarg[i],&f)) {
                    printf("Error in Verilog parser (RSQBFF-2)!");
                    YYERROR;
                  }

                  if (f.p != bdd_termFalse.p) {
                    f = Bdd_Expand(VERILOGarg[i],f);
                  }

                  if (Bdd_isEqv(f,bdd_termFalse)) fprintf(VERILOGout,"0");
                  else if (Bdd_isEqv(f,bdd_termTrue)) fprintf(VERILOGout,"1");
                  else fprintf(VERILOGout,"X");
                }
              }

            }

            ')' ;

list    : NAME {

            Est_String name;
            Bdd_Edge f;

            /* *************************** */
            /*  VERILOGnum                 */
            /*  case  0: add table         */
            /*  case -1: add list          */
            /*  case -2: set 0             */
            /*  case -3: set X             */
            /*  case -7: void              */
            /* *************************** */

            if (VERILOGnum == -3) {
              name  = strdup($1);
              f = Bdd_FoaTerminal(name);
              Bdd_AddFormula(name,f);
              free(name);
            }

            if (VERILOGnum == -2) {
              name  = strdup($1);
              Bdd_AddFormula(name,bdd_termFalse);
              free(name);
            }

            if (VERILOGnum == -1) {
              name  = strdup($1);
              addWire(name);
              free(name);
            }

            if (VERILOGnum >= 0) {
              if (VERILOGnum >= MAX_ARGS) {
                printf("Verilog parser error: to many arguments\n");
                YYERROR;
              } else {
                VERILOGarg[VERILOGnum++] = strdup($1);
              }
            }

          } morelist

        | ;

morelist  : ',' list
          | ;

%%

#include <lex.verilog.c>

/*-----------------------------------------------------------------------*/
/* Definition of exported functions                                      */
/*-----------------------------------------------------------------------*/

/**Function****************************************************************
  Synopsis    []
  Description []
  SideEffects [Verilog parser has two passes.]
  SeeAlso     []
  ************************************************************************/

int
Ccs_ConvertVerilog(Est_String in, Est_String out)
{
  YY_BUFFER_STATE buffer;

  printf("\n");

  /* PASS 1 - determine the initial values for wires */

  VERILOGpass = 1;

  yyin = fopen(in,"r");
  if (yyin != NULL) {

    buffer = yy_create_buffer(yyin,YY_BUF_SIZE);
    yy_switch_to_buffer(buffer);
    yyparse();
    yy_delete_buffer(buffer);

    fclose(yyin);
  } else {
    printf("\n  ERROR: Cannot open file %s\n",in);
  }

  /* PASS 2 - create CCS file */

  VERILOGpass = 2;

  yyin = fopen(in,"r");
  if (yyin != NULL) {

    VERILOGout = fopen(out,"w");
    if (VERILOGout != NULL) {
      buffer = yy_create_buffer(yyin,YY_BUF_SIZE);
      yy_switch_to_buffer(buffer);
      yyparse();
      yy_delete_buffer(buffer);
      fclose(VERILOGout);
    } else {
      printf("\n  ERROR: Cannot create file %s\n",out);
    }

    fclose(yyin);
  } else {
    printf("\n  ERROR: Cannot open file %s\n",in);
  }

  return 0;
}

/*-----------------------------------------------------------------------*/
/* Definition of static functions                                        */
/*-----------------------------------------------------------------------*/

void
addWire(Est_String name) {
  if (!VERILOGwires) {
    VERILOGwires = (Est_String) malloc(strlen(name)+2);
    sprintf(VERILOGwires,"\\%s",name);
  } else {
    VERILOGwires = (Est_String) realloc(VERILOGwires,strlen(VERILOGwires)+strlen(name)+2);
    strcat(VERILOGwires,"\\");
    strcat(VERILOGwires,name);
  }
}

/**Function****************************************************************
  Synopsis    []
  Description []
  SideEffects []
  SeeAlso     []
  ************************************************************************/

static int
error(const char *s)
{
  printf("\n  ERROR: ");
  if (strstr(s,"parse error, unexpected UNKNOWN")) {
     printf("unknown or badly placed symbol '%s'",verilogtext);
  } else
  if (strcmp(s,"parse error, unexpected UNKNOWN, expecting ACTION")) {
     printf("unknown or badly placed symbol '%s'",verilogtext);
  } else
  if (!strcmp(s,"parse error, unexpected NAME, expecting ACTION")) {
     printf("incorrect action name '%s', missing ! or ?",verilogtext);
  } else
  if (!strcmp(s,"parse error, unexpected ACTION, expecting NAME")) {
     printf("incorrect process name '%s'",verilogtext);
  } else {
    printf("%s",s);
  }
  printf("\n");
  return 1;
}

/*-----------------------------------------------------------------------*/
/* Definition of parser internal functions                               */
/*-----------------------------------------------------------------------*/

/**Function****************************************************************
  Synopsis    []
  Description []
  SideEffects []
  SeeAlso     []
  ************************************************************************/

int
yywrap()
{
  return 1;
}

/**Function****************************************************************
  Synopsis    []
  Description []
  SideEffects []
  SeeAlso     []
  ************************************************************************/

int
yyerror(const char *s)
{
  error(s);
  return 1;
}
