| # Copyright (c) 2006-2011 Nathan Binkert <nate@binkert.org> | |
| # All rights reserved. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions are | |
| # met: redistributions of source code must retain the above copyright | |
| # notice, this list of conditions and the following disclaimer; | |
| # redistributions in binary form must reproduce the above copyright | |
| # notice, this list of conditions and the following disclaimer in the | |
| # documentation and/or other materials provided with the distribution; | |
| # neither the name of the copyright holders 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| import os | |
| import ply.lex | |
| import ply.yacc | |
| class ParseError(Exception): | |
| def __init__(self, message, token=None): | |
| Exception.__init__(self, message) | |
| self.token = token | |
| class Grammar(object): | |
| def setupLexerFactory(self, **kwargs): | |
| if 'module' in kwargs: | |
| raise AttributeError, "module is an illegal attribute" | |
| self.lex_kwargs = kwargs | |
| def setupParserFactory(self, **kwargs): | |
| if 'module' in kwargs: | |
| raise AttributeError, "module is an illegal attribute" | |
| if 'output' in kwargs: | |
| dir,tab = os.path.split(output) | |
| if not tab.endswith('.py'): | |
| raise AttributeError, \ | |
| 'The output file must end with .py' | |
| kwargs['outputdir'] = dir | |
| kwargs['tabmodule'] = tab[:-3] | |
| self.yacc_kwargs = kwargs | |
| def __getattr__(self, attr): | |
| if attr == 'lexers': | |
| self.lexers = [] | |
| return self.lexers | |
| if attr == 'lex_kwargs': | |
| self.setupLexerFactory() | |
| return self.lex_kwargs | |
| if attr == 'yacc_kwargs': | |
| self.setupParserFactory() | |
| return self.yacc_kwargs | |
| if attr == 'lex': | |
| self.lex = ply.lex.lex(module=self, **self.lex_kwargs) | |
| return self.lex | |
| if attr == 'yacc': | |
| self.yacc = ply.yacc.yacc(module=self, **self.yacc_kwargs) | |
| return self.yacc | |
| if attr == 'current_lexer': | |
| if not self.lexers: | |
| return None | |
| return self.lexers[-1][0] | |
| if attr == 'current_source': | |
| if not self.lexers: | |
| return '<none>' | |
| return self.lexers[-1][1] | |
| if attr == 'current_line': | |
| if not self.lexers: | |
| return -1 | |
| return self.current_lexer.lineno | |
| raise AttributeError, \ | |
| "'%s' object has no attribute '%s'" % (type(self), attr) | |
| def parse_string(self, data, source='<string>', debug=None, tracking=0): | |
| if not isinstance(data, basestring): | |
| raise AttributeError, \ | |
| "argument must be a string, was '%s'" % type(f) | |
| import new | |
| lexer = self.lex.clone() | |
| lexer.input(data) | |
| self.lexers.append((lexer, source)) | |
| dict = { | |
| 'productions' : self.yacc.productions, | |
| 'action' : self.yacc.action, | |
| 'goto' : self.yacc.goto, | |
| 'errorfunc' : self.yacc.errorfunc, | |
| } | |
| parser = new.instance(ply.yacc.LRParser, dict) | |
| result = parser.parse(lexer=lexer, debug=debug, tracking=tracking) | |
| self.lexers.pop() | |
| return result | |
| def parse_file(self, f, **kwargs): | |
| if isinstance(f, basestring): | |
| source = f | |
| f = file(f, 'r') | |
| elif isinstance(f, file): | |
| source = f.name | |
| else: | |
| raise AttributeError, \ | |
| "argument must be either a string or file, was '%s'" % type(f) | |
| return self.parse_string(f.read(), source, **kwargs) | |
| def p_error(self, t): | |
| if t: | |
| msg = "Syntax error at %s:%d:%d\n>>%s<<" % \ | |
| (self.current_source, t.lineno, t.lexpos + 1, t.value) | |
| else: | |
| msg = "Syntax error at end of %s" % (self.current_source, ) | |
| raise ParseError(msg, t) | |
| def t_error(self, t): | |
| msg = "Illegal character %s @ %d:%d" % \ | |
| (`t.value[0]`, t.lineno, t.lexpos) | |
| raise ParseError(msg, t) |