Source code for fio

# -*- coding: utf-8 -*-
"""**In/Out.**

FAdo IO.

.. *Authors:* Rogério Reis & Nelma Moreira

.. *This is part of FAdo project*   http://fado.dcc.fc.up.pt.

.. *Copyright:* 2014 Rogério Reis & Nelma Moreira {rvr,nam}@dcc.fc.up.pt

.. This program 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.

   This program 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.,
   675 Mass Ave, Cambridge, MA 02139, USA."""

from yappy_parser import Yappy, grules

from common import Epsilon, DFAerror, TRError
from fa import DFA, NFA, statePP
from transducers import SFT, GFT, Transducer


[docs]class ParserFAdo(Yappy): """A parser for FAdo standard automata descriptions .. inheritance-diagram:: ParserFAdo""" def __init__(self, no_table=1, table=".tableFAdo"): tokenizer = [("\n+", lambda x: ("EOL", "EOL")), ("#.*", ""), ("\s+", ""), #("@epsilon", lambda x: ("ids", "@epsilon")), ("@epsilon", lambda x: ("ids", Epsilon)), ("@NFA", lambda x: ("NFA", "NFA")), ("@DFA", lambda x: ("DFA", "DFA")), ("@TDFA", lambda x: ("TDFA", "TDFA")), ("@Transducer", lambda x: ("TRANS", "TRANS")), ("\*", lambda x: ("SEP", "SEP")), ("\$", lambda x: ("DOLLAR", "DOLLAR")), ("\^", lambda x: ("CARET", "CARET")), ("<", lambda x: ("mv", "LEFT")), (">", lambda x: ("mv", "RIGHT")), ('"[A-Za-z0-9\(\)\[\]\{\}:\.,_-]+"', lambda x: ("id", x[1:-1])), ("[A-Za-z0-9]+", lambda x: ("id", x))] grammar = grules([("r -> d r", self.defaultSemRule), ("r -> n r", self.defaultSemRule), ("r -> td r", self.defaultSemRule), ("r -> tr r", self.defaultSemRule), ("r -> dummy r", self.emptySemRule), ("r -> ", self.emptySemRule), ("d -> DFA l t1", self.startDFASemRule), ("n -> NFA l t1n", self.startNFASemRule), ("n -> NFA l1 i tn", self.startNFASemRule), ("td -> TDFA l tt1", self.startTDFASemRule), ("tr -> TRANS l5 ttr", self.startTRANSSemRule), ("tr -> TRANS l3 ttri", self.startTRANSSemRule), ("idt -> id", self.defaultSemRule), ("idt -> ids", self.defaultSemRule), ("l -> id l", self.finalSemRule), ("l -> DOLLAR l2", self.emptySemRule), ("l -> EOL", self.emptySemRule), ("l1 -> id l1", self.finalSemRule), ("l1 -> SEP", self.emptySemRule), ("l2 -> id l2 ", self.addAlphabet), ("l2 -> EOL", self.emptySemRule), ("i -> id i", self.initialSemRule), ("i -> DOLLAR l2", self.emptySemRule), ("i -> EOL", self.emptySemRule), ("l5 -> id l5", self.finalSemRule), ("l5 -> DOLLAR it", self.emptySemRule), ("l5 -> EOL", self.emptySemRule), ("l3 -> id l3", self.finalSemRule), ("l3 -> SEP l4", self.emptySemRule), ("l4 -> id l4", self.initialSemRule), ("l4 -> DOLLAR it", self.emptySemRule), ("l4 -> EOL", self.emptySemRule), ("it -> id it", self.addAlphabet), ("it -> DOLLAR ot", self.emptySemRule), ("it -> EOL", self.emptySemRule), ("ot -> id ot ", self.addAlphabetOut), ("ot -> EOL", self.emptySemRule), ("t1 -> EOL t1", self.emptySemRule), ("t1 -> id EOL t", self.firstDeclareState), ("t1 -> id id id EOL t", self.firstTransitionSemRule), ("t1 -> ", self.emptySemRule), ("tt1 -> EOL tt1", self.emptySemRule), ("tt1 - id EOL tt", self.firstDeclareState), ("tt1 -> id ids id mv tt", self.firstTTransitionSemRule), ("tt1 -> id id id mv tt", self.firstTTransitionSemRule), ("tt1 -> id DOLLAR id mv tt", self.firstTTransitionSemRule), ("tt1 -> id CARET id mv tt", self.firstTTransitionSemRule), ("tt1 -> ", self.emptySemRule), ("tt -> id EOL tt", self.declareState), ("tt -> id ids is mv EOL tt", self.transitionTSemRule), ("tt -> id id is mv EOL tt", self.transitionTSemRule), ("tt -> id DOLLAR is mv EOL tt", self.transitionTSemRule), ("tt -> id CARET is mv EOL tt", self.transitionTSemRule), ("tt -> EOL tt", self.emptySemRule), ("tt -> ", self.emptySemRule), ("t1n -> EOL t1n", self.emptySemRule), ("t1n -> id EOL tn", self.firstDeclareState), ("t1n -> id id id EOL tn", self.firstTransitionSemRule), ("t1n -> id ids id EOL tn", self.firstTransitionESemRule), ("t1n -> ", self.emptySemRule), ("t -> id EOL t", self.declareState), ("t -> id id id EOL t", self.transitionSemRule), ("t -> EOL t", self.emptySemRule), ("t -> ", self.emptySemRule), ("tn - EOL tn", self.emptySemRule), ("tn -> id EOL tn", self.declareState), ("tn -> id id id EOL tn", self.transitionSemRule), ("tn -> id ids id EOL tn", self.transitionESemRule), ("tn -> EOL tn", self.emptySemRule), ("tn -> ", self.emptySemRule), ("ttr - EOL ttr", self.emptySemRule), ("ttr -> id EOL ttr", self.declareState), ("ttr -> id idt idt id EOL ttrs", self.firstTransitionTransSemRule), ("ttr -> ", self.emptySemRule), ("ttrs -> id EOL ttrs", self.declareState), ("ttrs -> id idt idt id EOL ttrs", self.transitionTransSemRule), ("ttrs -> EOL ttrs", self.emptySemRule), ("ttrs -> ", self.emptySemRule), ("ttri - EOL ttri", self.emptySemRule), ("ttri -> id EOL ttri", self.declareState), ("ttri -> id idt idt id EOL ttri", self.transitionTransSemRule), ("ttri -> EOL ttri", self.emptySemRule), ("ttri -> ", self.emptySemRule), ("dummy -> EOL", self.emptySemRule) ]) self.theList = [] self.transitions = [] self.initials = [] self.states = set() self.finals = [] self.alphabet = set() self.alphabetOut = set() self.TRtype = None Yappy.__init__(self, tokenizer, grammar, table, no_table) def initLocal(self): """Starts local structures for a new automata""" self.transitions = [] self.initials = [] self.states = set() self.finals = [] self.alphabet = set() self.alphabetOut = set() # noinspection PyUnusedLocal @staticmethod def defaultSemRule(lst, context=None): """Defines the default semantic rule for Yappy :param list lst: list of the arguments semantics :param dict context: context for the semantic rules :returns: first argument semantics""" return lst[0] # noinspection PyUnusedLocal @staticmethod def emptySemRule(lst, context=None): """Defines the empty semantic rule for Yappy :param lst: lst of the arguments semantics :param dict context: context for the semantic rules :returns: empty list""" return [] # noinspection PyUnusedLocal def startDFASemRule(self, lst, context=None): """ :param context: :param lst: :param context:""" new = DFA() while self.states: x = self.states.pop() new.addState(x) new.Sigma = self.alphabet x = self.initials.pop() new.setInitial(new.stateIndex(x)) while self.finals: x = self.finals.pop() new.addFinal(new.stateIndex(x)) while self.transitions: (x1, x2, x3) = self.transitions.pop() new.addTransition(new.stateIndex(x1), x2, new.stateIndex(x3)) self.theList.append(new) self.initLocal() # noinspection PyUnusedLocal def startTDFASemRule(self, lst, context=None): """ :param lst: :param context: """ pass # noinspection PyUnusedLocal def startNFASemRule(self, lst, context=None): """ :param lst: :param context:""" new = NFA() new.Sigma = self.alphabet while self.states: x = self.states.pop() new.addState(x) while self.initials: x = self.initials.pop() new.addInitial(new.stateIndex(x)) while self.finals: x = self.finals.pop() new.addFinal(new.stateIndex(x)) while self.transitions: (x1, x2, x3) = self.transitions.pop() new.addTransition(new.stateIndex(x1), x2, new.stateIndex(x3)) self.theList.append(new) self.initLocal() # noinspection PyUnusedLocal def startTRANSSemRule(self, lst, context=None): """ :param lst: :param context:""" if self.TRtype is None: new = SFT() elif self.TRtype == "GFT": new = GFT() else: raise TRError new.Sigma = self.alphabet new.Output = self.alphabetOut while self.states: x = self.states.pop() new.addState(x) while self.initials: x = self.initials.pop() new.addInitial(new.stateIndex(x)) while self.finals: x = self.finals.pop() new.addFinal(new.stateIndex(x)) while self.transitions: (x1, x2, x3, x4) = self.transitions.pop() new.addTransition(new.stateIndex(x1), x2, x3, new.stateIndex(x4)) self.theList.append(new) self.initLocal() # noinspection PyUnusedLocal def finalSemRule(self, lst, context=None): """ :param lst: :param context:""" self.finals.append(lst[0]) self.states.add(lst[0]) # noinspection PyUnusedLocal def initialSemRule(self, lst, context=None): """ :param lst: :param context:""" self.initials.append(lst[0]) self.states.add(lst[0]) # noinspection PyUnusedLocal def firstTransitionSemRule(self, lst, context=None): """ :param lst: :param context:""" self.initials.append(lst[0]) self.states.add(lst[0]) self.states.add(lst[2]) self.transitions.append((lst[0], lst[1], lst[2])) # noinspection PyUnusedLocal def firstTTransitionSemRule(self, lst, context=None): """ :param lst: :param context:""" pass # noinspection PyUnusedLocal def firstTransitionTransSemRule(self, lst, context=None): """ :param lst: :param context:""" self.initials.append(lst[0]) self.states.add(lst[0]) self.states.add(lst[3]) if self.TRtype is None and (lst[1] != Epsilon and len(lst[1]) > 1) or (lst[2] != Epsilon and len(lst[2]) > 1): self.TRtype = "GFT" self.transitions.append((lst[0], lst[1], lst[2], lst[3])) # noinspection PyUnusedLocal def firstDeclareState(self, lst, context=None): """ :param lst: :param context:""" self.states.add(lst[0]) self.initials.append(lst[0]) # noinspection PyUnusedLocal def addAlphabet(self, lst, context=None): """ :param lst: :param context:""" self.alphabet.add(lst[0]) # noinspection PyUnusedLocal def addAlphabetOut(self, lst, context=None): """ :param lst: :param context:""" self.alphabetOut.add(lst[0]) # noinspection PyUnusedLocal def declareState(self, lst, context=None): """ :param lst: :param context:""" self.states.add(lst[0]) # noinspection PyUnusedLocal def firstTransitionESemRule(self, lst, context=None): """ :param lst: :param context:""" self.transitions.append((lst[0], Epsilon, lst[2])) self.initials.append(lst[0]) self.states.add(lst[0]) self.states.add(lst[2]) # noinspection PyUnusedLocal def transitionSemRule(self, lst, context=None): """ :param lst: :param context:""" self.transitions.append((lst[0], lst[1], lst[2])) self.states.add(lst[0]) self.states.add(lst[2]) # noinspection PyUnusedLocal def transitionTransSemRule(self, lst, context=None): """ :param lst: :param context:""" if self.TRtype is None and (lst[1] != Epsilon and len(lst[1]) > 1) or (lst[2] != Epsilon and len(lst[2]) > 1): self.TRtype = "GFT" self.transitions.append((lst[0], lst[1], lst[2], lst[3])) self.states.add(lst[0]) self.states.add(lst[3]) # noinspection PyUnusedLocal def transitionTSemRule(self, lst, context=None): """ :param lst: :param context:""" pass # noinspection PyUnusedLocal def transitionESemRule(self, lst, context=None): """ :param lst: :param context:""" self.transitions.append((lst[0], Epsilon, lst[2])) self.states.add(lst[0]) self.states.add(lst[2]) def result(self): """ :return:""" return self.theList
def readOneFromFile(fileName): """ Read the first of the FAdo objects from File :param fileName: name of the file :type fileName: str :rtype: DFA|FA|STF""" return readFromFile(fileName)[0]
[docs]def readFromFile(FileName): """Reads list of finite automata definition from a file. :param FileName: file name :type FileName: str :rtype: list The format of these files must be the as simple as possible: .. hlist:: :columns: 1 * ``#`` begins a comment * ``@DFA`` or ``@NFA`` begin a new automata (and determines its type) and must be followed by the list of the final states separated by blanks * fields are separated by a blank and transitions by a CR: ``state`` ``symbol`` ``new state`` * in case of a NFA declaration, the "symbol" @epsilon is interpreted as a epsilon-transition * the source state of the first transition is the initial state * in the case of a NFA, its declaration ``@NFA`` can, after the declaration of the final states, have a ``*`` followed by the list of initial states * both, NFA and DFA, may have a declaration of alphabet starting with a ``$`` followed by the symbols of the alphabet * a line with a sigle name, decrares a state .. productionlist:: Fado Format FAdo: FA | FA CR FAdo FA: DFA | NFA | Transducer DFA: "@DFA" LsStates Alphabet CR dTrans NFA: "@NFA" LsStates Initials Alphabet CR nTrans Transducer: "@Transducer" LsStates Initials Alphabet Output CR tTrans Initials: "*" LsStates | \epsilon Alphabet: "$" LsSymbols | \epsilon Output: "$" LsSymbols | \epsilon nSymbol: symbol | "@epsilon" LsStates: stateid | stateid , LsStates LsSymbols: symbol | symbol , LsSymbols dTrans: stateid symbol stateid | :| stateid symbol stateid CR dTrans nTrans: stateid nSymbol stateid | :| stateid nSymbol stateid CR nTrans tTrans: stateid nSymbol nSymbol stateid | :| stateid nSymbol nSymbol stateid CR nTrans .. note:: If an error occur, either syntactic or because of a violation of the declared automata type, an exception is raised .. versionchanged:: 0.9.6 .. versionchanged:: 1.0""" parser = ParserFAdo() parser.inputfile(FileName) return parser.result()
def readOneFromString(s): """Reads one finite automata definition from a file. .. seealso:: readFromFile for description of format :param str s: the string :rtype: DFA|NFA|SFT""" parser = ParserFAdo() parser.input(s) return parser.result()[0]
[docs]def saveToFile(FileName, fa, mode="a"): """ Saves a list finite automata definition to a file using the input format .. versionchanged:: 0.9.5 .. versionchanged:: 0.9.6 .. versionchanged:: 0.9.7 New format with quotes and alphabet :param FileName: file name :type FileName: str :param fa: the FA :type fa: list of FA :param mode: writing mode :type mode: str """ #TODO: write the complete information into file according with the new format def _save_SFTransducer(tr): """Writes transducer to a file :param tr: the transducer :type tr: Transducer""" f.write("@Transducer ") for s in tr.Final: f.write("{0:>s} ".format(statePP(tr.States[s]))) f.write("* ") for s in tr.Initial: f.write("{0:>s} ".format(statePP(fa.States[s]))) f.write("\n") for sin in tr.delta: for syin in tr.delta[sin]: for (syout, sout) in tr.delta[sin][syin]: f.write("{0:>s} {1:>s} {2:>s} {3:>s}\n".format(statePP(tr.States[sin]), str(syin), str(syout), statePP(tr.States[sout]))) f.write("\n") def _saveFA(aut): """Writes one fa to a file :param aut: the automaton :type aut: FA or list""" if isinstance(aut, DFA): f.write("@DFA ") NFAp = False elif isinstance(aut, NFA): f.write("@NFA ") NFAp = True else: raise DFAerror() if not NFAp and aut.Initial != 0: foo = {0: aut.Initial, aut.Initial: 0} aut.reorder(foo) for sf in aut.Final: f.write("{0:>s} ".format(statePP(aut.States[sf]))) if NFAp: f.write(" * ") for sf in aut.Initial: f.write("{0:>s} ".format(statePP(aut.States[sf]))) f.write("\n") for s in xrange(len(aut.States)): if s in aut.delta: for a in aut.delta[s].keys(): if isinstance(aut.delta[s][a], set): for s1 in aut.delta[s][a]: f.write( "{0:>s} {1:>s} {2:>}\n".format(statePP(aut.States[s]), str(a), statePP(aut.States[s1]))) else: f.write("{0:>s} {1:>s} {2:>s}\n".format(statePP(aut.States[s]), str(a), statePP(aut.States[aut.delta[s][a]]))) else: f.write("{0:>s} \n".format(statePP(aut.States[s]))) try: f = open(FileName, mode) except IOError: raise DFAerror() if type(fa) == list: for d in fa: if isinstance(d, Transducer): _save_SFTransducer(d) else: _saveFA(d) else: if isinstance(fa, Transducer): _save_SFTransducer(fa) else: _saveFA(fa) f.close()
def _exportToTeX(FileName, fa): """ Saves a finite automatom definition to a latex tabular. Saves a finite automata definition to a file using the input format .. versionchanged:: 0.9.4 :param FileName: file name :type FileName: str :param fa: the FA :type fa: FA :raises DFAerror: if a file error occurs""" try: f = open(FileName, "w") except IOError: raise DFAerror() #initial is the first one if fa.Initial: foo = {0: fa.Initial, fa.Initial: 0} fa.reorder(foo) f.write("$$\\begin{array}{r|") for i in xrange(len(fa.Sigma)): f.write("|c") f.write("}\n") for c in fa.Sigma: f.write("&{0:>s}".format(str(c))) f.write(" \\\\\hline\n") for s in xrange(len(fa.States)): if s in fa.delta: if fa.Initial == s: f.write("\\rightarrow") if s in fa.Final: f.write("\\star") f.write("{0:>s}".format(str(s))) for a in fa.delta[s].keys(): if isinstance(fa.delta[s][a], set): f.write("&\{") for s1 in fa.delta[s][a]: f.write("{0:>s} ".format(str(s1))) f.write("\}") else: s1 = fa.delta[s][a] f.write("&{0:>s}".format(str(s1))) f.write("\\\\\n") f.write("\end{array}$$") f.close()