-module(regExprGen). -export([manager/0,state/2,create/1]). % Module for automata for regular languages on {a,b,c}. % % Each state is a process. Many strings can be parsed in parallel. % % create : creates an automaton together with its manager. Returns the PID of the manager. % An automaton is described by a list of quadruple, each quadruple describe the next state for, respectively, % a,b or c and whether the state is a final one (by means of the atoms final or notfinal). % In case of no next state for a character, the atom none is used. % States in the list are denoted by integers form 0 to n, 0 denoting the initial state. % Example: % The automaton corresponding to the regular expression abc*+c(bb)* % has the following transition table. % a b c Final States = q2, q3 % 0 1 3 < notfinal % 1 2 < notfinal % 2 2 < final % 3 4 < final % 4 3 < notfinal % % The list of quadruples representing the above table is the following one: % % [{1,none,3,notfinal},{none,2,none,notfinal},{none,none,2,final},{none,4,none,final},{none,3,none,notfinal}] % % % % A parsing request can be sent to the manager by means of a triple {requestParsing,ID,List} % where ID is the PID of whom makes the request, and List is the string to be parsed. % % For sake of simplicity a string is represented by a list of atoms that represents characters. % % The manager sends the request to the initial state and receives the answer that is then % delivered to whom made the request. % The original string to be parsed is kept through all the parsing process and sent back with the % answer in order one can send onother request even before one gets the answer of the previous request. % % manager : It is the function corresponding to the manager of the automaton. % Once spawned by the create function, the manager waits for the address of the initial state, % that the create function itself sends to it (This procedures is a simple trick necessary since % the manager and the initial state need the PID of each other.) % % state : It is the function corresponding to a state. Its arguments are the PID of the manager % and one atom (final or nofinal) representing whether the spawned state is final or not. % Once spawned by the create function, a state waits for a triple of PIDs % corresponding, respectively, to the states it has to be connected to for the characters a, b, or c. % In case a state is not connected to another state for a particular character (and hence the % string has to be rejected), the corresponding element in the triple is the atom none instead of a PID. % (As for the manager, this trick is needed in order to have automata with cliques. % % % The lists:zip function is a predefined one in Erlang. % We rewrite it here for sake of simplicity in case someone did not know it. myzip([],[]) -> []; myzip([H1|T1],[H2|T2]) -> [{H1,H2}|myzip(T1,T2)]. % The predefined function lists:nth(N,L) returns the N-th element of the list L % Here, in mynth, we need to take care that N could be the atom none and that we counts the states starting form 0. mynth(N,L) -> if (N==none) -> none; true -> lists:nth(N+1,L) end. create(List) -> %%we create the manager and the (process-)states. The PID of manager is returned. IDmanager = spawn(exprReg,manager,[]), States = [spawn(exprReg,state,[IDmanager,Final]) || {_,_,_,Final} <- List], %%we connect the manager to the initial state and the various states among themselves %%according to the transition table [QInit|_] = States, IDmanager!QInit, [IDQ!{mynth(NA,States),mynth(NB,States),mynth(NC,States)} || {IDQ,{NA,NB,NC,_}} <- myzip(States,List) ], IDmanager. manager() -> receive IDinitial -> loopmanager(IDinitial) end. loopmanager(IDinitial) -> receive {requestParsing,ID,List} -> IDinitial ! {List,ID,List}; {accepted,ID,List} -> ID ! {accepted,List}; {rejected,ID,List} -> ID ! {rejected,List} end, loopmanager(IDinitial). state(IDmanager,Final) -> receive {IDA,IDB,IDC} -> loop(IDA,IDB,IDC,IDmanager,Final) end. loop(IDA,IDB,IDC,IDmanager,Final) -> receive {[],ID,List} -> if (Final == final) -> IDmanager ! {accepted,ID,List}; true -> IDmanager ! {rejected,ID,List} end; {[ Char | Cs ],ID,List} -> Next = (if (Char == a) -> IDA; (Char == b) -> IDB; (Char == c) -> IDC end), if (Next == none) -> IDmanager ! {rejected,ID,List}; true -> Next ! {Cs,ID,List} end end, loop(IDA,IDB,IDC,IDmanager,Final).