grammar.py revision 13663:9b64aeabf9a5
110037SARM gem5 Developers# Copyright (c) 2006-2011 Nathan Binkert <nate@binkert.org>
210037SARM gem5 Developers# All rights reserved.
310037SARM gem5 Developers#
410037SARM gem5 Developers# Redistribution and use in source and binary forms, with or without
510037SARM gem5 Developers# modification, are permitted provided that the following conditions are
610037SARM gem5 Developers# met: redistributions of source code must retain the above copyright
710037SARM gem5 Developers# notice, this list of conditions and the following disclaimer;
810037SARM gem5 Developers# redistributions in binary form must reproduce the above copyright
910037SARM gem5 Developers# notice, this list of conditions and the following disclaimer in the
1010037SARM gem5 Developers# documentation and/or other materials provided with the distribution;
1110037SARM gem5 Developers# neither the name of the copyright holders nor the names of its
1210037SARM gem5 Developers# contributors may be used to endorse or promote products derived from
1310037SARM gem5 Developers# this software without specific prior written permission.
1410037SARM gem5 Developers#
1510037SARM gem5 Developers# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1610037SARM gem5 Developers# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1710037SARM gem5 Developers# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1810037SARM gem5 Developers# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1910037SARM gem5 Developers# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2010037SARM gem5 Developers# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2110037SARM gem5 Developers# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2210037SARM gem5 Developers# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2310037SARM gem5 Developers# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2410037SARM gem5 Developers# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2510037SARM gem5 Developers# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2610037SARM gem5 Developers
2710037SARM gem5 Developersimport os
2810037SARM gem5 Developers
2910037SARM gem5 Developersimport ply.lex
3010037SARM gem5 Developersimport ply.yacc
3110037SARM gem5 Developers
3210037SARM gem5 Developersclass ParseError(Exception):
3310037SARM gem5 Developers    def __init__(self, message, token=None):
3410037SARM gem5 Developers        Exception.__init__(self, message)
3510037SARM gem5 Developers        self.token = token
3610037SARM gem5 Developers
3710037SARM gem5 Developersclass Grammar(object):
3810037SARM gem5 Developers    def setupLexerFactory(self, **kwargs):
3910037SARM gem5 Developers        if 'module' in kwargs:
4010037SARM gem5 Developers            raise AttributeError("module is an illegal attribute")
4110037SARM gem5 Developers        self.lex_kwargs = kwargs
4210037SARM gem5 Developers
4310037SARM gem5 Developers    def setupParserFactory(self, **kwargs):
4410037SARM gem5 Developers        if 'module' in kwargs:
4510037SARM gem5 Developers            raise AttributeError("module is an illegal attribute")
4610037SARM gem5 Developers
4710037SARM gem5 Developers        if 'output' in kwargs:
4810037SARM gem5 Developers            dir,tab = os.path.split(output)
4910037SARM gem5 Developers            if not tab.endswith('.py'):
5010037SARM gem5 Developers                raise AttributeError('The output file must end with .py')
5110037SARM gem5 Developers            kwargs['outputdir'] = dir
5210037SARM gem5 Developers            kwargs['tabmodule'] = tab[:-3]
5310037SARM gem5 Developers
5410037SARM gem5 Developers        self.yacc_kwargs = kwargs
5510037SARM gem5 Developers
5610037SARM gem5 Developers    def __getattr__(self, attr):
5710037SARM gem5 Developers        if attr == 'lexers':
5810037SARM gem5 Developers            self.lexers = []
5910037SARM gem5 Developers            return self.lexers
6010037SARM gem5 Developers
6110037SARM gem5 Developers        if attr == 'lex_kwargs':
6210037SARM gem5 Developers            self.setupLexerFactory()
6310037SARM gem5 Developers            return self.lex_kwargs
6410037SARM gem5 Developers
6510037SARM gem5 Developers        if attr == 'yacc_kwargs':
6610037SARM gem5 Developers            self.setupParserFactory()
6710037SARM gem5 Developers            return self.yacc_kwargs
6810037SARM gem5 Developers
6910037SARM gem5 Developers        if attr == 'lex':
7010037SARM gem5 Developers            self.lex = ply.lex.lex(module=self, **self.lex_kwargs)
7110037SARM gem5 Developers            return self.lex
7210037SARM gem5 Developers
7310037SARM gem5 Developers        if attr == 'yacc':
7410037SARM gem5 Developers            self.yacc = ply.yacc.yacc(module=self, **self.yacc_kwargs)
7510037SARM gem5 Developers            return self.yacc
7610037SARM gem5 Developers
7710037SARM gem5 Developers        if attr == 'current_lexer':
7810037SARM gem5 Developers            if not self.lexers:
7910037SARM gem5 Developers                return None
8010037SARM gem5 Developers            return self.lexers[-1][0]
8110037SARM gem5 Developers
8210037SARM gem5 Developers        if attr == 'current_source':
8310037SARM gem5 Developers            if not self.lexers:
8410037SARM gem5 Developers                return '<none>'
8510037SARM gem5 Developers            return self.lexers[-1][1]
8610037SARM gem5 Developers
8710037SARM gem5 Developers        if attr == 'current_line':
8810037SARM gem5 Developers            if not self.lexers:
8910037SARM gem5 Developers                return -1
9010037SARM gem5 Developers            return self.current_lexer.lineno
9110037SARM gem5 Developers
9210037SARM gem5 Developers        raise AttributeError(
9310037SARM gem5 Developers            "'%s' object has no attribute '%s'" % (type(self), attr))
9410037SARM gem5 Developers
9510037SARM gem5 Developers    def parse_string(self, data, source='<string>', debug=None, tracking=0):
9610037SARM gem5 Developers        if not isinstance(data, basestring):
9710037SARM gem5 Developers            raise AttributeError(
9810037SARM gem5 Developers                "argument must be a string, was '%s'" % type(f))
9910037SARM gem5 Developers
10010037SARM gem5 Developers        import new
10110037SARM gem5 Developers        lexer = self.lex.clone()
10210037SARM gem5 Developers        lexer.input(data)
10310037SARM gem5 Developers        self.lexers.append((lexer, source))
10410037SARM gem5 Developers        dict = {
10510037SARM gem5 Developers            'productions' : self.yacc.productions,
10610037SARM gem5 Developers            'action'      : self.yacc.action,
10710037SARM gem5 Developers            'goto'        : self.yacc.goto,
10810037SARM gem5 Developers            'errorfunc'   : self.yacc.errorfunc,
10910037SARM gem5 Developers            }
11010037SARM gem5 Developers        parser = new.instance(ply.yacc.LRParser, dict)
11110037SARM gem5 Developers        result = parser.parse(lexer=lexer, debug=debug, tracking=tracking)
11210037SARM gem5 Developers        self.lexers.pop()
11310037SARM gem5 Developers        return result
11410037SARM gem5 Developers
11510037SARM gem5 Developers    def parse_file(self, f, **kwargs):
11610037SARM gem5 Developers        if isinstance(f, basestring):
11710037SARM gem5 Developers            source = f
11810037SARM gem5 Developers            f = file(f, 'r')
11910037SARM gem5 Developers        elif isinstance(f, file):
12010037SARM gem5 Developers            source = f.name
12110037SARM gem5 Developers        else:
12210037SARM gem5 Developers            raise AttributeError(
12310037SARM gem5 Developers                "argument must be either a string or file, was '%s'" % type(f))
12410037SARM gem5 Developers
12510037SARM gem5 Developers        return self.parse_string(f.read(), source, **kwargs)
12610037SARM gem5 Developers
12710037SARM gem5 Developers    def p_error(self, t):
12810037SARM gem5 Developers        if t:
12910037SARM gem5 Developers            msg = "Syntax error at %s:%d:%d\n>>%s<<" % \
13010037SARM gem5 Developers                  (self.current_source, t.lineno, t.lexpos + 1, t.value)
13110037SARM gem5 Developers        else:
13210037SARM gem5 Developers            msg = "Syntax error at end of %s" % (self.current_source, )
13310037SARM gem5 Developers        raise ParseError(msg, t)
13410037SARM gem5 Developers
13510037SARM gem5 Developers    def t_error(self, t):
13610037SARM gem5 Developers        msg = "Illegal character %s @ %d:%d" % \
13710037SARM gem5 Developers            (`t.value[0]`, t.lineno, t.lexpos)
13810037SARM gem5 Developers        raise ParseError(msg, t)
13910037SARM gem5 Developers