home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / cgkit / _slparser.py < prev    next >
Encoding:
Python Source  |  2007-01-11  |  23.3 KB  |  584 lines

  1. # Begin -- grammar generated by Yapps
  2. import sys, re
  3. #import yappsrt
  4.  
  5. ######################################################################
  6. ######################################################################
  7. ######################################################################
  8. ######################################################################
  9. # The following is the Yapps 2.2.1 runtime file (yappsrt.py)
  10.  
  11. #
  12. # Yapps 2 Runtime, part of Yapps 2 - yet another python parser system
  13. # Copyright 1999-2003 by Amit J. Patel <amitp@cs.stanford.edu>
  14. #
  15. # This version of the Yapps 2 Runtime can be distributed under the
  16. # terms of the MIT open source license, either found in the LICENSE file
  17. # included with the Yapps distribution
  18. # <http://theory.stanford.edu/~amitp/yapps/> or at
  19. # <http://www.opensource.org/licenses/mit-license.php>
  20. #
  21.  
  22. """Run time libraries needed to run parsers generated by Yapps.
  23.  
  24. This module defines parse-time exception classes, a scanner class, a
  25. base class for parsers produced by Yapps, and a context class that
  26. keeps track of the parse stack.
  27.  
  28. """
  29.  
  30. import sys, re
  31.  
  32. class SyntaxError(Exception):
  33.     """When we run into an unexpected token, this is the exception to use"""
  34.     def __init__(self, charpos=-1, msg="Bad Token", context=None):
  35.         Exception.__init__(self)
  36.         self.charpos = charpos
  37.         self.msg = msg
  38.         self.context = context
  39.         
  40.     def __str__(self):
  41.         if self.charpos < 0: return 'SyntaxError'
  42.         else: return 'SyntaxError@char%s(%s)' % (repr(self.charpos), self.msg)
  43.  
  44. class NoMoreTokens(Exception):
  45.     """Another exception object, for when we run out of tokens"""
  46.     pass
  47.  
  48. class Scanner:
  49.     """Yapps scanner.
  50.  
  51.     The Yapps scanner can work in context sensitive or context
  52.     insensitive modes.  The token(i) method is used to retrieve the
  53.     i-th token.  It takes a restrict set that limits the set of tokens
  54.     it is allowed to return.  In context sensitive mode, this restrict
  55.     set guides the scanner.  In context insensitive mode, there is no
  56.     restriction (the set is always the full set of tokens).
  57.     
  58.     """
  59.     
  60.     def __init__(self, patterns, ignore, input):
  61.         """Initialize the scanner.
  62.  
  63.         Parameters:
  64.           patterns : [(terminal, uncompiled regex), ...] or None
  65.           ignore : [terminal,...]
  66.           input : string
  67.  
  68.         If patterns is None, we assume that the subclass has
  69.         defined self.patterns : [(terminal, compiled regex), ...].
  70.         Note that the patterns parameter expects uncompiled regexes,
  71.         whereas the self.patterns field expects compiled regexes.
  72.         """
  73.         self.tokens = [] # [(begin char pos, end char pos, token name, matched text), ...]
  74.         self.restrictions = []
  75.         self.input = input
  76.         self.pos = 0
  77.         self.ignore = ignore
  78.         self.first_line_number = 1
  79.         
  80.         if patterns is not None:
  81.             # Compile the regex strings into regex objects
  82.             self.patterns = []
  83.             for terminal, regex in patterns:
  84.                 self.patterns.append( (terminal, re.compile(regex)) )
  85.  
  86.     def get_token_pos(self):
  87.         """Get the current token position in the input text."""
  88.         return len(self.tokens)
  89.  
  90.     def get_char_pos(self):
  91.         """Get the current char position in the input text."""
  92.         return self.pos
  93.     
  94.     def get_prev_char_pos(self, i=None):
  95.         """Get the previous position (one token back) in the input text."""
  96.         if self.pos == 0: return 0
  97.         if i is None: i = -1
  98.         return self.tokens[i][0]
  99.     
  100.     def get_line_number(self):
  101.         """Get the line number of the current position in the input text."""
  102.         # TODO: make this work at any token/char position
  103.         return self.first_line_number + self.get_input_scanned().count('\n')
  104.  
  105.     def get_column_number(self):
  106.         """Get the column number of the current position in the input text."""
  107.         s = self.get_input_scanned()
  108.         i = s.rfind('\n') # may be -1, but that's okay in this case
  109.         return len(s) - (i+1)
  110.     
  111.     def get_input_scanned(self):
  112.         """Get the portion of the input that has been tokenized."""
  113.         return self.input[:self.pos]
  114.  
  115.     def get_input_unscanned(self):
  116.         """Get the portion of the input that has not yet been tokenized."""
  117.         return self.input[self.pos:]
  118.  
  119.     def token(self, i, restrict=None):
  120.         """Get the i'th token in the input.
  121.  
  122.         If i is one past the end, then scan for another token.
  123.         
  124.         Args:
  125.  
  126.         restrict : [token, ...] or None; if restrict is None, then any
  127.         token is allowed.  You may call token(i) more than once.
  128.         However, the restrict set may never be larger than what was
  129.         passed in on the first call to token(i).
  130.         
  131.         """
  132.         if i == len(self.tokens):
  133.             self.scan(restrict)
  134.         if i < len(self.tokens):
  135.             # Make sure the restriction is more restricted.  This
  136.             # invariant is needed to avoid ruining tokenization at
  137.             # position i+1 and higher.
  138.             if restrict and self.restrictions[i]:
  139.                 for r in restrict:
  140.                     if r not in self.restrictions[i]:
  141.                         raise NotImplementedError("Unimplemented: restriction set changed")
  142.             return self.tokens[i]
  143.         raise NoMoreTokens()
  144.     
  145.     def __repr__(self):
  146.         """Print the last 10 tokens that have been scanned in"""
  147.         output = ''
  148.         for t in self.tokens[-10:]:
  149.             output = '%s\n  (@%s)  %s  =  %s' % (output,t[0],t[2],repr(t[3]))
  150.         return output
  151.     
  152.     def scan(self, restrict):
  153.         """Should scan another token and add it to the list, self.tokens,
  154.         and add the restriction to self.restrictions"""
  155.         # Keep looking for a token, ignoring any in self.ignore
  156.         while 1:
  157.             # Search the patterns for the longest match, with earlier
  158.             # tokens in the list having preference
  159.             best_match = -1
  160.             best_pat = '(error)'
  161.             for p, regexp in self.patterns:
  162.                 # First check to see if we're ignoring this token
  163.                 if restrict and p not in restrict and p not in self.ignore:
  164.                     continue
  165.                 m = regexp.match(self.input, self.pos)
  166.                 if m and len(m.group(0)) > best_match:
  167.                     # We got a match that's better than the previous one
  168.                     best_pat = p
  169.                     best_match = len(m.group(0))
  170.                     
  171.             # If we didn't find anything, raise an error
  172.             if best_pat == '(error)' and best_match < 0:
  173.                 msg = 'Bad Token'
  174.                 if restrict:
  175.                     msg = 'Trying to find one of '+', '.join(restrict)
  176.                 raise SyntaxError(self.pos, msg)
  177.  
  178.             # If we found something that isn't to be ignored, return it
  179.             if best_pat not in self.ignore:
  180.                 # Create a token with this data
  181.                 token = (self.pos, self.pos+best_match, best_pat,
  182.                          self.input[self.pos:self.pos+best_match])
  183.                 self.pos = self.pos + best_match
  184.                 # Only add this token if it's not in the list
  185.                 # (to prevent looping)
  186.                 if not self.tokens or token != self.tokens[-1]:
  187.                     self.tokens.append(token)
  188.                     self.restrictions.append(restrict)
  189.                 return
  190.             else:
  191.                 # This token should be ignored ..
  192.                 self.pos = self.pos + best_match
  193.  
  194. class Parser:
  195.     """Base class for Yapps-generated parsers.
  196.  
  197.     """
  198.     
  199.     def __init__(self, scanner):
  200.         self._scanner = scanner
  201.         self._pos = 0
  202.         
  203.     def _peek(self, *types):
  204.         """Returns the token type for lookahead; if there are any args
  205.         then the list of args is the set of token types to allow"""
  206.         tok = self._scanner.token(self._pos, types)
  207.         return tok[2]
  208.         
  209.     def _scan(self, type):
  210.         """Returns the matched text, and moves to the next token"""
  211.         tok = self._scanner.token(self._pos, [type])
  212.         if tok[2] != type:
  213.             raise SyntaxError(tok[0], 'Trying to find '+type+' :'+ ' ,'.join(self._scanner.restrictions[self._pos]))
  214.         self._pos = 1 + self._pos
  215.         return tok[3]
  216.  
  217. class Context:
  218.     """Class to represent the parser's call stack.
  219.  
  220.     Every rule creates a Context that links to its parent rule.  The
  221.     contexts can be used for debugging.
  222.  
  223.     """
  224.     
  225.     def __init__(self, parent, scanner, tokenpos, rule, args=()):
  226.         """Create a new context.
  227.  
  228.         Args:
  229.         parent: Context object or None
  230.         scanner: Scanner object
  231.         pos: integer (scanner token position)
  232.         rule: string (name of the rule)
  233.         args: tuple listing parameters to the rule
  234.  
  235.         """
  236.         self.parent = parent
  237.         self.scanner = scanner
  238.         self.tokenpos = tokenpos
  239.         self.rule = rule
  240.         self.args = args
  241.  
  242.     def __str__(self):
  243.         output = ''
  244.         if self.parent: output = str(self.parent) + ' > '
  245.         output += self.rule
  246.         return output
  247.     
  248. def print_line_with_pointer(text, p):
  249.     """Print the line of 'text' that includes position 'p',
  250.     along with a second line with a single caret (^) at position p"""
  251.     # Now try printing part of the line
  252.     text = text[max(p-80, 0):p+80]
  253.     p = p - max(p-80, 0)
  254.  
  255.     # Strip to the left
  256.     i = text[:p].rfind('\n')
  257.     j = text[:p].rfind('\r')
  258.     if i < 0 or (0 <= j < i): i = j
  259.     if 0 <= i < p:
  260.         p = p - i - 1
  261.         text = text[i+1:]
  262.  
  263.     # Strip to the right
  264.     i = text.find('\n', p)
  265.     j = text.find('\r', p)
  266.     if i < 0 or (0 <= j < i): i = j
  267.     if i >= 0:
  268.         text = text[:i]
  269.  
  270.     # Now shorten the text
  271.     while len(text) > 70 and p > 60:
  272.         # Cut off 10 chars
  273.         text = "..." + text[10:]
  274.         p = p - 7
  275.  
  276.     # Now print the string, along with an indicator
  277.     print >>sys.stderr, '> ',text
  278.     print >>sys.stderr, '> ',' '*p + '^'
  279.     
  280. def print_error(input, err, scanner):
  281.     """Print error messages, the parser stack, and the input text -- for human-readable error messages."""
  282.     # NOTE: this function assumes 80 columns :-(
  283.     # Figure out the line number
  284.     line_number = scanner.get_line_number()
  285.     column_number = scanner.get_column_number()
  286.     print >>sys.stderr, '%d:%d: %s' % (line_number, column_number, err.msg)
  287.  
  288.     context = err.context
  289.     if not context:
  290.         print_line_with_pointer(input, err.charpos)
  291.         
  292.     while context:
  293.         # TODO: add line number
  294.         print >>sys.stderr, 'while parsing %s%s:' % (context.rule, tuple(context.args))
  295.         print_line_with_pointer(input, context.scanner.get_prev_char_pos(context.tokenpos))
  296.         context = context.parent
  297.  
  298. def wrap_error_reporter(parser, rule):
  299.     try:
  300.         return getattr(parser, rule)()
  301.     except SyntaxError, e:
  302.         input = parser._scanner.input
  303.         print_error(input, e, parser._scanner)
  304.     except NoMoreTokens:
  305.         print >>sys.stderr, 'Could not complete parsing; stopped around here:'
  306.         print >>sys.stderr, parser._scanner
  307.         
  308. ######################################################################
  309. ######################################################################
  310. ######################################################################
  311. ######################################################################
  312. class YappsRT:
  313.     pass
  314.  
  315. yappsrt = YappsRT()
  316. yappsrt.Scanner = Scanner
  317. yappsrt.Parser = Parser
  318. yappsrt.Context = Context
  319. yappsrt.SyntaxError = SyntaxError
  320. yappsrt.NoMoreTokens = NoMoreTokens
  321. yappsrt.wrap_error_reporter = wrap_error_reporter
  322.  
  323. ######################################################################
  324.         
  325. # The following is generated by Yapps2.1.1:
  326.  
  327. class _SLParserBaseScanner(yappsrt.Scanner):
  328.     patterns = [
  329.         ('"-"', re.compile('-')),
  330.         ('"="', re.compile('=')),
  331.         ('"\\]"', re.compile('\\]')),
  332.         ('"\\["', re.compile('\\[')),
  333.         ('","', re.compile(',')),
  334.         ('";"', re.compile(';')),
  335.         ('"}"', re.compile('}')),
  336.         ('"{"', re.compile('{')),
  337.         ('"\\)"', re.compile('\\)')),
  338.         ('"\\("', re.compile('\\(')),
  339.         ('[ \n\t]+', re.compile('[ \n\t]+')),
  340.         ('END', re.compile('$')),
  341.         ('number', re.compile('[0-9]+(\\.[0-9]*)?([eE][0-9]+)?|\\.[0-9]+([eE][0-9]+)?')),
  342.         ('stringconstant', re.compile('"[^"]*"')),
  343.         ('shader_type', re.compile('(light|surface|volume|displacement|imager)')),
  344.         ('outputspec', re.compile('output')),
  345.         ('type', re.compile('(float|string|color|point|vector|normal|matrix|void)')),
  346.         ('detail', re.compile('(varying|uniform)')),
  347.         ('singletypes', re.compile('(float|string)')),
  348.         ('spacetypes', re.compile('(color|point|vector|normal|matrix)')),
  349.         ('identifier', re.compile('[_a-zA-Z][_a-zA-Z0-9]*')),
  350.         ('binop', re.compile('[+\\-/^*.]')),
  351.         ('preprocessorline', re.compile('#.*')),
  352.     ]
  353.     def __init__(self, str):
  354.         yappsrt.Scanner.__init__(self,None,['[ \n\t]+'],str)
  355.  
  356. class _SLParserBase(yappsrt.Parser):
  357.     Context = yappsrt.Context
  358.     def definitions(self, _parent=None):
  359.         _context = self.Context(_parent, self._scanner, self._pos, 'definitions', [])
  360.         shaders = []
  361.         while self._peek('END', 'preprocessorline', 'shader_type', 'type', 'identifier') != 'END':
  362.             _token = self._peek('preprocessorline', 'shader_type', 'type', 'identifier')
  363.             if _token == 'preprocessorline':
  364.                 preprocessorline = self._scan('preprocessorline')
  365.                 self.switchFile(preprocessorline)
  366.             elif _token == 'shader_type':
  367.                 shader_def = self.shader_def(_context)
  368.                 shaders.append(shader_def)
  369.             else: # in ['type', 'identifier']
  370.                 function_def = self.function_def(_context)
  371.         if self._peek() not in ['END', 'preprocessorline', 'shader_type', 'type', 'identifier']:
  372.             raise yappsrt.SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['preprocessorline', 'END', 'shader_type', 'type', 'identifier']))
  373.         END = self._scan('END')
  374.         return shaders
  375.  
  376.     def shader_def(self, _parent=None):
  377.         _context = self.Context(_parent, self._scanner, self._pos, 'shader_def', [])
  378.         shader_type = self._scan('shader_type')
  379.         identifier = self._scan('identifier')
  380.         self.newParams()
  381.         self._scan('"\\("')
  382.         if self._peek('"\\)"', 'outputspec', '";"', 'detail', 'type', '","') in ['outputspec', 'detail', 'type']:
  383.             formals = self.formals(_context)
  384.         self._scan('"\\)"')
  385.         self._scan('"{"')
  386.         self._scan('"}"')
  387.         return (shader_type,identifier,self.params)
  388.  
  389.     def function_def(self, _parent=None):
  390.         _context = self.Context(_parent, self._scanner, self._pos, 'function_def', [])
  391.         if self._peek('type', 'identifier') == 'type':
  392.             type = self._scan('type')
  393.         identifier = self._scan('identifier')
  394.         self._scan('"\\("')
  395.         if self._peek('"\\)"', 'outputspec', '";"', 'detail', 'type', '","') in ['outputspec', 'detail', 'type']:
  396.             formals = self.formals(_context)
  397.         self._scan('"\\)"')
  398.         self._scan('"{"')
  399.         self._scan('"}"')
  400.  
  401.     def formals(self, _parent=None):
  402.         _context = self.Context(_parent, self._scanner, self._pos, 'formals', [])
  403.         formal_var_defs = self.formal_var_defs(_context)
  404.         while self._peek('";"', '"\\)"', '","') == '";"':
  405.             self._scan('";"')
  406.             if self._peek('outputspec', '";"', 'detail', 'type', '","', '"\\)"') in ['outputspec', 'detail', 'type']:
  407.                 formal_var_defs = self.formal_var_defs(_context)
  408.         if self._peek() not in ['";"', '"\\)"', '","']:
  409.             raise yappsrt.SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['";"', '"\\)"', '","']))
  410.  
  411.     def formal_var_defs(self, _parent=None):
  412.         _context = self.Context(_parent, self._scanner, self._pos, 'formal_var_defs', [])
  413.         self.newType()
  414.         if self._peek('outputspec', 'detail', 'type') == 'outputspec':
  415.             outputspec = self._scan('outputspec')
  416.             self.output="output"
  417.         typespec = self.typespec(_context)
  418.         def_expressions = self.def_expressions(_context)
  419.  
  420.     def typespec(self, _parent=None):
  421.         _context = self.Context(_parent, self._scanner, self._pos, 'typespec', [])
  422.         if self._peek('detail', 'type') == 'detail':
  423.             detail = self._scan('detail')
  424.             self.detail = detail
  425.         type = self._scan('type')
  426.         self.type = type
  427.  
  428.     def def_expressions(self, _parent=None):
  429.         _context = self.Context(_parent, self._scanner, self._pos, 'def_expressions', [])
  430.         def_expression = self.def_expression(_context)
  431.         while self._peek('","', '";"', '"\\)"') == '","':
  432.             self._scan('","')
  433.             def_expression = self.def_expression(_context)
  434.         if self._peek() not in ['","', '";"', '"\\)"']:
  435.             raise yappsrt.SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['","', '";"', '"\\)"']))
  436.  
  437.     def def_expression(self, _parent=None):
  438.         _context = self.Context(_parent, self._scanner, self._pos, 'def_expression', [])
  439.         identifier = self._scan('identifier')
  440.         self.name = identifier
  441.         if self._peek('"\\["', '"="', '","', '";"', '"\\)"') == '"\\["':
  442.             self._scan('"\\["')
  443.             number = self._scan('number')
  444.             self._scan('"\\]"')
  445.             self.arraylen=int(number)
  446.         if self._peek('"="', '","', '";"', '"\\)"') == '"="':
  447.             def_init = self.def_init(_context)
  448.             self.default = def_init
  449.         self.storeParam()
  450.  
  451.     def def_init(self, _parent=None):
  452.         _context = self.Context(_parent, self._scanner, self._pos, 'def_init', [])
  453.         self._scan('"="')
  454.         expression = self.expression(_context)
  455.         return expression
  456.  
  457.     def expression(self, _parent=None):
  458.         _context = self.Context(_parent, self._scanner, self._pos, 'expression', [])
  459.         expr=""
  460.         _token = self._peek('"-"', 'number', 'stringconstant', 'singletypes', 'spacetypes', '"\\("', '"{"', 'identifier')
  461.         if _token not in ['"-"', 'singletypes', 'spacetypes']:
  462.             primary = self.primary(_context)
  463.             expr+=primary
  464.         elif _token == '"-"':
  465.             self._scan('"-"')
  466.             expression = self.expression(_context)
  467.             expr+="-"+expression
  468.         else: # in ['singletypes', 'spacetypes']
  469.             typecast = self.typecast(_context)
  470.             expression = self.expression(_context)
  471.             expr+=expression
  472.         while self._peek('binop', '","', '"\\)"', '"}"', '";"') == 'binop':
  473.             binop = self._scan('binop')
  474.             expression = self.expression(_context)
  475.             expr+=binop+expression
  476.         if self._peek() not in ['binop', '","', '"\\)"', '"}"', '";"']:
  477.             raise yappsrt.SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['binop', '","', '"\\)"', '"}"', '";"']))
  478.         return expr
  479.  
  480.     def primary(self, _parent=None):
  481.         _context = self.Context(_parent, self._scanner, self._pos, 'primary', [])
  482.         _token = self._peek('number', 'stringconstant', '"\\("', '"{"', 'identifier')
  483.         if _token == 'number':
  484.             number = self._scan('number')
  485.             return number
  486.         elif _token == 'stringconstant':
  487.             stringconstant = self._scan('stringconstant')
  488.             return stringconstant
  489.         elif _token == '"\\("':
  490.             tuple = self.tuple(_context)
  491.             return tuple
  492.         elif _token == '"{"':
  493.             array = self.array(_context)
  494.             return array
  495.         else: # == 'identifier'
  496.             identifier_or_procedurecall = self.identifier_or_procedurecall(_context)
  497.             return identifier_or_procedurecall
  498.  
  499.     def tuple(self, _parent=None):
  500.         _context = self.Context(_parent, self._scanner, self._pos, 'tuple', [])
  501.         tup = ""
  502.         self._scan('"\\("')
  503.         expression = self.expression(_context)
  504.         tup+=expression
  505.         while self._peek('"\\)"', '","') == '","':
  506.             self._scan('","')
  507.             expression = self.expression(_context)
  508.             tup+=", "+expression
  509.         if self._peek() not in ['"\\)"', '","']:
  510.             raise yappsrt.SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['","', '"\\)"']))
  511.         self._scan('"\\)"')
  512.         return "("+tup+")"
  513.  
  514.     def typecast(self, _parent=None):
  515.         _context = self.Context(_parent, self._scanner, self._pos, 'typecast', [])
  516.         _token = self._peek('singletypes', 'spacetypes')
  517.         if _token == 'singletypes':
  518.             singletypes = self._scan('singletypes')
  519.         else: # == 'spacetypes'
  520.             spacetypes = self._scan('spacetypes')
  521.             if self._peek('stringconstant', '"-"', 'number', 'singletypes', 'spacetypes', '"\\("', '"{"', 'identifier') == 'stringconstant':
  522.                 spacename = self.spacename(_context)
  523.                 self.space = spacename[1:-1]
  524.  
  525.     def spacename(self, _parent=None):
  526.         _context = self.Context(_parent, self._scanner, self._pos, 'spacename', [])
  527.         stringconstant = self._scan('stringconstant')
  528.         return stringconstant
  529.  
  530.     def identifier_or_procedurecall(self, _parent=None):
  531.         _context = self.Context(_parent, self._scanner, self._pos, 'identifier_or_procedurecall', [])
  532.         identifier = self._scan('identifier')
  533.         res = identifier; proc_args=""
  534.         if self._peek('"\\("', 'binop', '","', '"\\)"', '"}"', '";"') == '"\\("':
  535.             self._scan('"\\("')
  536.             if self._peek('"\\)"', '"-"', 'number', 'stringconstant', 'singletypes', 'spacetypes', '"\\("', '"{"', 'identifier') != '"\\)"':
  537.                 proc_args = self.proc_args(_context)
  538.             self._scan('"\\)"')
  539.             res+="("+proc_args+")"
  540.         return res
  541.  
  542.     def proc_args(self, _parent=None):
  543.         _context = self.Context(_parent, self._scanner, self._pos, 'proc_args', [])
  544.         expression = self.expression(_context)
  545.         res = expression
  546.         while self._peek('","', '"\\)"') == '","':
  547.             self._scan('","')
  548.             expression = self.expression(_context)
  549.             res+=", "+expression
  550.         if self._peek() not in ['","', '"\\)"']:
  551.             raise yappsrt.SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['","', '"\\)"']))
  552.         return res
  553.  
  554.     def array(self, _parent=None):
  555.         _context = self.Context(_parent, self._scanner, self._pos, 'array', [])
  556.         arr = ""
  557.         self._scan('"{"')
  558.         expression = self.expression(_context)
  559.         arr+=expression; self.appendSpace()
  560.         while self._peek('"}"', '","') == '","':
  561.             self._scan('","')
  562.             expression = self.expression(_context)
  563.             arr+=", "+expression; self.appendSpace()
  564.         if self._peek() not in ['"}"', '","']:
  565.             raise yappsrt.SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['","', '"}"']))
  566.         self._scan('"}"')
  567.         return "{"+arr+"}"
  568.  
  569.  
  570. def parse(rule, text):
  571.     P = _SLParserBase(_SLParserBaseScanner(text))
  572.     return yappsrt.wrap_error_reporter(P, rule)
  573.  
  574. if __name__ == '__main__':
  575.     from sys import argv, stdin
  576.     if len(argv) >= 2:
  577.         if len(argv) >= 3:
  578.             f = open(argv[2],'r')
  579.         else:
  580.             f = stdin
  581.         print parse(argv[1], f.read())
  582.     else: print >>sys.stderr, 'Args:  <rule> [<filename>]'
  583. # End -- grammar generated by Yapps
  584.