/**CFile*******************************************************************
  PackageName [pa]
  Synopsis    [Package 'pa' is a framework for implementation of
               process algebrae similar to Milner's CCS and Hoare's CSP.]

  FileName    [paParser.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 paParser.y is a bison file of parser for textual
               description of LTSs.]
  SeeAlso     [pa.h, paInt.h, paParser.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 "paInt.h"
#define YYERROR_VERBOSE
%}

%{
   static char FOATransition(Est_String state1,Est_String act,Est_String state2);
   static void outline(char *s);
   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 */

   /* STATIC VARIABLES? I DO NOT KNOW, IF THIS IS A GOOD OR A BAD IDEA */
   /*
   static int PaSort = 0;
   static int PaProc = 0;
   static Est_String PaState1 = NULL;
   static Est_String PaState2 = NULL;
   */

   int PaSort = 0;
   int PaProc = 0;
   Est_String PaState1 = NULL;
   Est_String PaState2 = NULL;
%}

%union {
  Est_String outline;
  Est_String word;
}

%token UNKNOWN
%token <outline> OUTLINE
%token <word> NAME ACTION ACTIONS
%token <word> INITIAL_STATE FINAL_STATES PROCESS SORT TRANSITIONS

%%
start   : sorts processes ;

sorts   : sort sorts
        | ;

sort    : OUTLINE {
            Est_String tmp;

            tmp = strdup($1);
            outline(tmp);
            free(tmp);
            free($1);
          }

        | SORT NAME {

            Est_String name;

            /*
            fprintf(stderr,"NAME %s\n",$2);
            */

            name = strdup($2);

            printf("  Sort %s ... ",name);
            PaSort = Pa_AddNewSort(name);
            free(name);
            free($2);

          }

          elements {
            printf("OK\n");
          }

        | error sorts {
            yyerrok;
          } ;

elements  : element ',' elements
          | element ;

element : NAME {

            Est_String name,errtext;

            name = strdup($1);
            if (!pa_sorts) {
              errtext = (Est_String) malloc(255);
              sprintf(errtext,"'%s'",name);
              yyerror(errtext);
              free(errtext);
              free(name);
              free($1);
              YYERROR;
            } else {
              Pa_FOASortAction(&pa_sortTable[PaSort],name);
              free(name);
              free($1);
            }

          } ;

processes : proces processes
            | ;

proces  : OUTLINE {
            Est_String tmp;

            tmp = strdup($1);
            outline(tmp);
            free(tmp);
            free($1);
          }

        | PROCESS NAME {

            Est_String name;

            /*
            fprintf(stderr,"NAME %s\n",$2);
            */

            name = strdup($2);

            printf("  Process %s ... ",name);
            PaProc = Pa_AddNewProcess(name);
            free(name);

          }

          SORT dogsort
          actions
          INITIAL_STATE initial_state
          final

          TRANSITIONS prehodi {
            printf("OK\n");
            free($2);
          }

        | error processes {
            yyerrok;
          } ;

dogsort : NAME {

            Est_String name;

            name = strdup($1);
            pa_processTable[PaProc].sort = Pa_FindSort(name);
            free(name);
            free($1);

          } ;

actions :
        | ACTIONS actionsname {
            printf("\n  Option ACTIONS is depreciated. Please, remove it! ");
          } ;

actionsname :
            | ACTION {free($1);} ',' actionsname
            | ACTION {free($1);} ;

initial_state : NAME {

                  Est_String name;

                  name = strdup($1);
                  pa_processTable[PaProc].initial =
                     Pa_FOAStateProcess(&pa_processTable[PaProc],name);
                  free(name);
                  free($1);

                } ;

final   :
        | FINAL_STATES finalnames {
          } ;

finalnames  :
            | NAME {

                Est_String name;
                int i;

                name = strdup($1);
                i = Pa_FOAStateProcess(&pa_processTable[PaProc],name);
                pa_processTable[PaProc].tableS[i].final = TRUE;

                /* MARK FINAL STATES WITH ADDITIONAL TRANSITION */
                /*
                int final;
                final = Pa_FOAStateProcess(&pa_processTable[PaProc],"FINAL");
                Pa_FOATransition(&pa_processTable[PaProc],
                   i,Pa_FindSortAction(&pa_sortTable[pa_processTable[PaProc].sort],"FINAL"),1,final);
                */

                free(name);
                free($1);

              } finalnames ;

prehodi   : enostanje prehodi
          | ;

enostanje : NAME {
              PaState1 = strdup($1);
            }

            '=' prehod {
              free($1);
            };

prehod  : enprehod '+' prehod
          | enprehod {
              free(PaState1);
            } ;

enprehod  : ACTION '.' NAME {

              Est_String akcija;
              Est_String errtext;

              akcija = strdup($1);
              PaState2 = strdup($3);

              if (FOATransition(PaState1,akcija,PaState2)) {
                errtext = (Est_String) malloc(255);
                sprintf(errtext,"Unknown action '%s'",akcija);
                yyerror(errtext);
                free(errtext);
                free(akcija);
                free(PaState2);
                free($1);
                free($3);
                YYERROR;
              } else {
                free(akcija);
                free(PaState2);
                free($1);
                free($3);
              }

            } ;

%%

#include <lex.pa.c>

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

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

int
Pa_ParseSortProcess(Est_String ime)
{
  YY_BUFFER_STATE buffer;

  printf("\n");
  yyin = fopen(ime,"r");
  if (yyin != NULL) {
    PaProc = -1;
    PaSort = -1;

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

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

  return 0;
}

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

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

static char
FOATransition(Est_String state1, Est_String act, Est_String state2)
{
  Pa_Process *p;
  int s1,s2;
  int a;
  int type;
  int len;
  Est_String action;

  p = &pa_processTable[PaProc];
  if (p->sort == -1) return 0;

  type = 0; /* THIS IS TYPE FOR ACTION TAU */
  action = strdup(act);
  len = strlen(action);
  if (action[len-1] == '?') {
    type = 0;
    action[len-1]='\0';
  } else if (action[len-1] == '!') {
    type = 1;
    action[len-1]='\0';
  }

  a = Pa_FindSortAction(&pa_sortTable[p->sort],action);
  if (a == -1) {
    return 1;
  }

  s1 = Pa_FOAStateProcess(p,state1);

  if (state2[0] == '@') {
    s2 = Pa_FOAGateProcess(p,&state2[1]);
  } else {
    s2 = Pa_FOAStateProcess(p,state2);
  }

  Pa_FOATransition(p,s1,a,type,s2);

  free(action);

  return 0;
}

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

static void
outline(char *s)
{
  if (strcmp(s,"")) printf("%s",&s[1]);
  printf("\n");
}

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

static int
error(const char *s)
{
  printf("    ERROR: ");
  if (strstr(s,"parse error, unexpected UNKNOWN")) {
     printf("unknown or badly placed symbol '%s'",patext);
  } else
  if (strcmp(s,"parse error, unexpected UNKNOWN, expecting ACTION")) {
     printf("unknown or badly placed symbol '%s'",patext);
  } else
  if (!strcmp(s,"parse error, unexpected NAME, expecting ACTION")) {
     printf("incorrect action name '%s', missing ! or ?",patext);
  } else
  if (!strcmp(s,"parse error, unexpected UNKNOWN, expecting '.'")) {
     printf("incorrect action name, extra '%s'",patext);
  } else
  if (!strcmp(s,"parse error, unexpected ACTION, expecting NAME")) {
     printf("incorrect state name '%s'",patext);
  } 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;
}
