// $Id: NFA.h,v 1.8 2003/07/13 19:23:50 vern Exp $
//
// Copyright (c) 1998, 1999, 2001, 2002, 2003
//      The Regents of the University of California.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that: (1) source code distributions
// retain the above copyright notice and this paragraph in its entirety, (2)
// distributions including binary code include the above copyright notice and
// this paragraph in its entirety in the documentation or other materials
// provided with the distribution, and (3) all advertising materials mentioning
// features or use of this software display the following acknowledgement:
// ``This product includes software developed by the University of California,
// Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
// the University nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#ifndef nfa_h
#define nfa_h

#include "RE.h"
#include "IntSet.h"

class NFA_State;
class EquivClass;

declare(PList,NFA_State);
typedef PList(NFA_State) NFA_state_list;

#define NO_ACCEPT 0

#define NO_UPPER_BOUND -1

#define SYM_BOL 256
#define SYM_EOL 257
#define NUM_SYM 258

#define SYM_EPSILON 259
#define SYM_CCL 260    


class NFA_State : public BroObj  {
public:
	NFA_State(int sym, EquivClass* ec);
	NFA_State(CCL* ccl);
	~NFA_State();

	void AddXtion(NFA_State* next_state)	{ xtions.append(next_state); }
	NFA_state_list* Transitions()		{ return &xtions; }
	void AddXtionsTo(NFA_state_list* ns);

	void SetAccept(int accept_val)	{ accept = accept_val; }
	int Accept() const		{ return accept; }

	// Returns a deep copy of this NFA state and everything it points
	// to.  Upon return, each state's marker is set to point to its
	// copy.
	NFA_State* DeepCopy();

	void SetMark(NFA_State* m)	{ mark = m; }
	NFA_State* Mark() const		{ return mark; }
	void ClearMarks();

	int TransSym() const	{ return sym; }
	CCL* TransCCL() const	{ return ccl; }
	int ID() const		{ return id; }

	NFA_state_list* EpsilonClosure();

	void Describe(ODesc* d) const;
	void Dump(FILE* f);

protected:
	int sym;	// if SYM_CCL, then use ccl
	CCL* ccl;	// if nil, then use sym
	int accept;
	int id;	// number that uniquely identifies this state
	NFA_state_list xtions;
	NFA_state_list* epsclosure;
	NFA_State* mark;
};

class EpsilonState : public NFA_State {
public:
	EpsilonState()	: NFA_State(SYM_EPSILON, 0)	{ }
};

class NFA_Machine : public BroObj {
public:
	NFA_Machine(NFA_State* first, NFA_State* final = 0);
	~NFA_Machine();

	NFA_State* FirstState() const	{ return first_state; }

	void SetFinalState(NFA_State* final)	{ final_state = final; }
	NFA_State* FinalState() const		{ return final_state; }

	void AddAccept(int accept_val);

	void MakeClosure()	{ MakePositiveClosure(); MakeOptional(); }
	void MakeOptional();
	void MakePositiveClosure();

	// re{lower,upper}; upper can be NO_UPPER_BOUND = infinity.
	void MakeRepl(int lower, int upper);

	void MarkBOL()		{ bol = 1; }
	void MarkEOL()		{ eol = 1; }

	NFA_Machine* DuplicateMachine();
	void LinkCopies(int n);
	void InsertEpsilon();
	void AppendEpsilon();

	void AppendState(NFA_State* new_state);
	void AppendMachine(NFA_Machine* new_mach);

	void Describe(ODesc* d) const;
	void Dump(FILE* f);
	void DumpStats(FILE* f);

protected:
	NFA_State* first_state;
	NFA_State* final_state;
	int bol, eol;
};

extern NFA_Machine* make_alternate(NFA_Machine* m1, NFA_Machine* m2);

// The epsilon closure is the set of all states reachable by an arbitrary
// number of epsilon transitions, which themselves do not have epsilon
// transitions going out, unioned with the set of states which have non-null
// accepting numbers.  "states" is deleted by the call.  The return value
// is the epsilon closure (sorted by state IDs()).
extern NFA_state_list* epsilon_closure(NFA_state_list* states);

// For sorting NFA states based on their ID fields (decreasing)
extern int NFA_state_cmp_neg(const void* v1, const void* v2);

#endif
