generator.py :  » Parser » SimpleParse » SimpleParse-2.1.1a2 » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Parser » SimpleParse 
SimpleParse » SimpleParse 2.1.1a2 » generator.py
"""Abstract representation of an in-memory grammar that generates parsers"""
from simpleparse.stt.TextTools import TextTools
import traceback

class Generator:
  '''Abstract representation of an in-memory grammar that generates parsers
  
  The generator class manages a collection of
  ElementToken objects.  These element token objects
  allow the generator to be separated from the import 
  particular parser associated with any particular EBNF
  grammar.  In fact, it is possible to create entire grammars
  using only the generator objects as a python API.
  '''
  def __init__( self ):
    """Initialise the Generator"""
    self.names = []
    self.rootObjects = []
    self.methodSource = None
    self.definitionSources = []
  def getNameIndex( self, name ):
    '''Return the index into the main list for the given name'''
    try:
      return self.names.index( name )
    except ValueError:
      
      for source in self.definitionSources:
        if source.has_key( name ):
          return self.addDefinition( name, source[name])
##      import pdb
##      pdb.set_trace()
      raise NameError( '''The name %s is not defined within this generator'''%(repr(name)), self )
  def getRootObjects( self, ):
    '''Return the list of root generator objects'''
    return self.rootObjects
  def getNames( self, ):
    '''Return the list of root generator objects'''
    return self.names
  def getRootObject( self, name ):
    """Get a particular root object by name"""
    return self.getRootObjects()[ self.getNameIndex(name)]
  
  def addDefinition( self, name, rootElement ):
    '''Add a new definition (object) to the generator'''
    try:
      self.names.index( name )
      raise NameError( '''Attempt to redefine an existing name %s'''%(name), self )
    except ValueError:
      self.names.append( name )
      self.rootObjects.append( rootElement )
      return self.getNameIndex( name )
  def buildParser( self, name, methodSource=None ):
    '''Build the given parser definition, returning a TextTools parsing tuple'''
    self.parserList = []
    self.terminalParserCache = {}
    self.methodSource = methodSource
    i = 0
    while i < len(self.rootObjects):
      # XXX Note: rootObjects will grow in certain cases where
      # a grammar is loading secondary grammars into itself
      rootObject = self.rootObjects[i]
      try:
        if len(self.parserList) <= i or self.parserList[i] is None:
          parser = tuple(rootObject.toParser( self ))
          self.setTerminalParser( i, parser )
      except NameError,err:
        currentRuleName = self.names[i]
        err.args = err.args + ('current declaration is %s'%(currentRuleName), )
        raise
      i = i + 1
    assert None not in self.parserList, str( self.parserList)
    return self.parserList [self.getNameIndex (name)]
  def setTerminalParser( self, index, parser ):
    """Explicitly set the parser value for given name"""
    while index >= len(self.parserList):
      self.parserList.append(None)
    self.parserList[index] = parser
  def getTerminalParser( self, index ):
    """Try to retrieve a parser from the parser-list"""
    try:
      return self.parserList[ index ]
    except IndexError:
      return None
  def cacheCustomTerminalParser( self, index, flags, parser ):
    """Optimization to reuse customized terminal parsers"""
    self.terminalParserCache[ (index,flags) ] = parser
  def getCustomTerminalParser( self, index, flags ):
    """Retrieved a cached customized terminal parser or None"""
    return self.terminalParserCache.get( (index, flags))
    
  def getParserList (self):
    return self.parserList


  def getObjectForName( self, name):
    """Determine whether our methodSource has a parsing method for the given name

    returns ( flags or 0 , tagobject)
    """
    testName = "_m_"+name
    if hasattr( self.methodSource, testName):
      method = getattr( self.methodSource, testName )
      if callable(method):
        return  TextTools.CallTag, method
      elif method == TextTools.AppendMatch:
        return method, name
      elif method in (TextTools.AppendToTagobj, TextTools.AppendTagobj):
        object = self.getTagObjectForName( name )
        if method == TextTools.AppendToTagobj:
          if not ( hasattr( object, 'append') and callable(object.append)):
            raise ValueError( """Method source %s declares production %s to use AppendToTagobj method, but doesn't given an object with an append method in _o_%s (gave %s)"""%(repr(self.methodSource), name,name, repr(object)))
        return method, object
      else:
        raise ValueError( """Unrecognised command value %s (not callable, not one of the Append* constants) found in methodSource %s, name=%s"""%( repr(method),repr(methodSource),name))
    return 0, name
  def getTagObjectForName( self, name ):
    """Get any explicitly defined tag object for the given name"""
    testName = "_o_"+name
    if hasattr( self.methodSource, testName):
      object = getattr( self.methodSource, testName )
      return object
    return name
  def addDefinitionSource( self, item ):
    """Add a source for definitions when the current grammar doesn't supply
    a particular rule (effectively common/shared items for the grammar)."""
    self.definitionSources.append( item )


### Compatability API
##  This API exists to allow much of the code written with SimpleParse 1.0
##  to work with SimpleParse 2.0
class GeneratorAPI1:
  """Stand-in class supporting operation of SimpleParse 1.0 applications

  There was really only the one method of interest, parserbyname,
  everything else was internal (and is now part of
  simpleparsegrammar.py).
  """
  def __init__( self, production, prebuilt=() ):
    from simpleparse.parser import Parser
    self.parser = Parser( production, prebuilts=prebuilt )
  def parserbyname( self, name ):
    """Retrieve a tag-table by production name"""
    return self.parser.buildTagger( name )

def buildParser( declaration, prebuiltnodes=() ):
  """API 1.0 primary entry point, returns a GeneratorAPI1 instance

  That object will respond to the parserbyname API expected by
  SimpleParse 1.0 applications.
  """
  return GeneratorAPI1( declaration, prebuiltnodes )

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.