#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#include"dict.h"
#include"pns.h"

struct rvalue {
  union {
    char* p;
    int i;
    void* v;
  };
  int line; // line number or first line, if text on multiple lines
  int lastline; // last line, if text on multiple lines
};

typedef struct rvalue YYSTYPE;

#define YYSTYPE_IS_DECLARED 1

struct rvl_chain {
  struct rvalue rvl;
  int n; // number of additional rvl_chain elements
  char alloc; // nonzero if rvl.p should be deallocated
  struct rvl_chain *next;
};

enum var_type {
  NONE, INTG, PLACE, PROC, TRANS, 
};

struct pa_var {
  enum var_type type; // variable type
  int line; // line on which variable was declared
  union {
    struct pa_proc *pr; // if variable stands for a process, see 'pr' for id
    int id; // used when the variable does not represent a process
  };
};

struct pa_proc {
  struct dict var; // the variables of the process
  int tnum; // the number of transitions
  int pnum; // the number of places
  int id; // identification number of process
  unsigned char thread:1; // 1 if process should be implemented as a thread 
  unsigned char supervisor:1; // 1 if the process is a supervisor component 
  char* name; 
  struct pa_proc *next; // next in list
};


void add_arc(struct rvalue *s1, struct rvalue *s2, struct rvalue *s3, struct rvalue *code);
// Processes the instructions that add arcs. 
// In the first pass it checks for errors. 
// In the second pass it creates an "arcs" object and adds it to the pn of the
// current process.

void add_c_block(struct rvalue proc, struct rvalue place, struct rvalue block,\
		 char type);
// If type = 'i', associates to 'place' of the process 'proc' the embedded 
// instructions of 'block'.
// If type = 's', associates to 'place' of the process 'proc' the select
// function call of 'block'.

void add_ineq(struct rvalue in1, struct rvalue in2, int type);
// Adds a constraint of the form 'in1' [ = | <= | < ] 'in2'.
// It has no effect in the first pass.

struct rvalue add_ineq_var(struct rvalue *pr, struct rvalue *v2, \
			   struct rvalue *v3);
// Creates an object for an inequality variable during the second pass.
// It checks variable names during the first pass.

struct pa_var* add_var(struct rvalue s);
// Adds a new variable to the variable list of the current process.
// The function does nothing if it is called during the second pass.

struct pa_var* add_var_sub(char *name, int line, enum var_type type, char fl);
// This is a subroutine of add_var. Adds a new variable to the variable list.
// If fl is nonzero, an error will be reported if the variable is already 
// defined. 
// Meant only for the first pass and for the context of a process block (this
// means that pres_pr must be nonzero). 

inline struct pa_var* add_variable(struct pa_proc *pr, char *name, int line, \
			    enum var_type type, char fl, struct pa_var** defn);
// This function is meant for the first pass.
// It adds a variable to the process pr, if pr is nonzero. Otherwise, the
// variable is added to the default process. Otherwise, if there is no
// default process, the variable is added to the list of global variables.
// If the variable is already defined and defn != 0, then *defn is set to the
// entry of the variable. The return value is 0 if there is an error, or the
// entry added to the variable list. An attempt to add an already defined 
// variable is an error. 
// Errors are reported if 'fl' is nonzero. 'line' denotes the line on which
// the variable 'name' is defined. Error checking includes whether variables
// are defined in the proper context (such as transitions and places in the
// context of a process).


void commit_process(int type, struct rvalue s);


void commit_constraint();
// Includes current constraint in the specification.
// It has no effect during the first pass.

void copy_process(int type, struct rvalue src, struct rvalue dst);
// 'src' describes the source (an already defined process) and 'dst' the
// new process of type 'type' to which 'src' should be copied. 
// If 'type' < 0, 'dst' will have the same type as 'src'. The function
// copies the PN structure (2nd pass), the variables (excepting certain  
// internal variables) (1st pass), and the specification fields (2nd pass). 
// It does not copy or update constraints affecting 'src'. 


char* default_tname(char *p1, char *p2);
// Creates a transition name for unnamed transitions based on the names of 
// of the states it connects. The result can be deallocated with free().

void free_rvlchain(struct qalloc *p);
// Frees the queue used to store the rvl elements and the allocated content
// of the queue elements. 

void init_pvar(struct rvalue var, struct rvalue list);
// Does error checking during the first pass.
// Initializes the marking vector of the process variable during the second
// pass.

void insert_command(struct rvalue *proc, struct rvalue type, \
		    struct rvalue block);
// Inserts in the specification object one of the following (as selected
// by 'type'): a build, include, or main command.
// During the first pass it checks for errors.

struct pa_var* is_process(char* name, int line);
// Checks whether a process variable has been defined. It returns its entry 
// in the global variable list or zero, if it is not defined. An error is
// reported if it is not defined.

int is_var(struct pa_proc *pr, struct rvalue name, enum var_type type);
// Checks whether 'name' is a variable of the type 'type' of the process 'pr'.
// Returns its id. Otherwise, if it is not defined, it returns -1 and reports
// an error. If pr == 0, pres_pr of actions.c is used instead of pr.

void live_trans(struct rvalue type, struct rvalue list);
// Does error checking during the first pass.
// Updates transition attributes during the second pass.

void parse_buffer(char* s);
specs* parse_file(FILE* f);


int registered_var(char* name, enum var_type type);
// If the variable is found (in the context of the current process) with the 
// correct type, the function returns its id. Otherwise, it returns -1. 

#define registered_place(x) registered_var(x, PLACE)
#define registered_transition(x) registered_var(x, TRANS)

void release_process();

void report_error(int line, char* str, ...);
// Writes specified error message.
// If line == 0, the default line number (that is, 'parseline') is written.
// If line < 0, no line number is written.

struct rvalue rvalue_list(struct rvalue* v, struct rvalue var, \
			  struct rvalue intg, char alloc);
// The function updates (or creates if v = 0) a chain of struct rvalue objects.
// 'alloc' indicates whether 'intg.p' is a string that can be deallocated when
// memory is freed.  
// It returns the updated v. 

struct rvalue set_coef(int coef, struct rvalue var, int line, int lastline);
// Returns an updated 'var' containing the coefficient information.
// The function has almost no effect in the first pass.

struct rvalue set_free_term(struct rvalue term);
// The function initializes the v field of the result with a pointer to a 
// 'variable' object in which the pn field is 0 (to indicate the free term).
// The function has almost no effect in the first pass.

struct rvalue set_ineq(struct rvalue *list, int sign, struct rvalue *term);
// The function returns an updated version of (*list) that includes (*term).
// It also does the proper initializations when 'list' = 0 and when 
// 'list' = 'term' = 0. 
// Note that the v field of the result contains an 'inequality' object.
// The function has almost no effect in the first pass.

void set_ineq_sub(inequality* pin, variable* var, int sign);
// This is a subroutine of set_ineq of more general interest. It inserts
// the variable 'var' in the inequality 'pin' with the sign indicated by 
// 'sign'.
// Important: the function will deallocate 'var' if the variable is already in
// 'pin'.

void set_vartype(enum var_type v);
// Sets the default variable type

void sync_trans(struct rvalue list, struct rvalue *alist);
// Deals with synchronization constraints.
// Verifies data during the first pass.
// Updates specification object during the second pass. 

