grammar.py revision 6660
16501Snate@binkert.org# Copyright (c) 2006-2009 Nathan Binkert <nate@binkert.org> 26501Snate@binkert.org# All rights reserved. 36501Snate@binkert.org# 46501Snate@binkert.org# Redistribution and use in source and binary forms, with or without 56501Snate@binkert.org# modification, are permitted provided that the following conditions are 66501Snate@binkert.org# met: redistributions of source code must retain the above copyright 76501Snate@binkert.org# notice, this list of conditions and the following disclaimer; 86501Snate@binkert.org# redistributions in binary form must reproduce the above copyright 96501Snate@binkert.org# notice, this list of conditions and the following disclaimer in the 106501Snate@binkert.org# documentation and/or other materials provided with the distribution; 116501Snate@binkert.org# neither the name of the copyright holders nor the names of its 126501Snate@binkert.org# contributors may be used to endorse or promote products derived from 136501Snate@binkert.org# this software without specific prior written permission. 146501Snate@binkert.org# 156501Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 166501Snate@binkert.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 176501Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 186501Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 196501Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 206501Snate@binkert.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 216501Snate@binkert.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 226501Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 236501Snate@binkert.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 246501Snate@binkert.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 256501Snate@binkert.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 266501Snate@binkert.org 276501Snate@binkert.orgfrom ply import lex, yacc 286501Snate@binkert.org 296501Snate@binkert.orgclass TokenError(lex.LexError): 306501Snate@binkert.org def __init__(self, msg, t): 316501Snate@binkert.org super(TokenError, self).__init__(msg) 326501Snate@binkert.org self.token = t 336501Snate@binkert.org 346501Snate@binkert.orgclass ParseError(yacc.YaccError): 356501Snate@binkert.org def __init__(self, message, token=None): 366501Snate@binkert.org super(ParseError, self).__init__(message) 376501Snate@binkert.org self.token = token 386501Snate@binkert.org 396501Snate@binkert.orgclass Tokenizer(object): 406501Snate@binkert.org def __init__(self, lexer, data): 416501Snate@binkert.org if isinstance(data, basestring): 426501Snate@binkert.org indata = [ data ] 436501Snate@binkert.org elif isinstance(data, file): 446501Snate@binkert.org indata = data.xreadlines() 456501Snate@binkert.org else: 466501Snate@binkert.org indata = data 476501Snate@binkert.org 486501Snate@binkert.org def _input(): 496501Snate@binkert.org for i,line in enumerate(indata): 506501Snate@binkert.org lexer.lineno = i + 1 516501Snate@binkert.org lexer.input(line) 526501Snate@binkert.org while True: 536501Snate@binkert.org tok = lexer.token() 546501Snate@binkert.org if not tok: 556501Snate@binkert.org break 566501Snate@binkert.org yield tok 576501Snate@binkert.org self.input = _input() 586660Snate@binkert.org self.lexer = lexer 596501Snate@binkert.org 606501Snate@binkert.org def next(self): 616501Snate@binkert.org return self.input.next() 626501Snate@binkert.org 636501Snate@binkert.org def __iter__(self): 646501Snate@binkert.org return self 656501Snate@binkert.org 666501Snate@binkert.org def token(self): 676501Snate@binkert.org try: 686501Snate@binkert.org return self.next() 696501Snate@binkert.org except StopIteration: 706501Snate@binkert.org return None 716501Snate@binkert.org 726660Snate@binkert.org def __getattr__(self, attr): 736660Snate@binkert.org return getattr(self.lexer, attr) 746660Snate@binkert.org 756501Snate@binkert.orgclass Grammar(object): 766501Snate@binkert.org def __init__(self, output=None, debug=False): 776501Snate@binkert.org self.yacc_args = {} 786501Snate@binkert.org self.yacc_args['debug'] = debug 796501Snate@binkert.org 806501Snate@binkert.org if output: 816501Snate@binkert.org import os 826501Snate@binkert.org 836501Snate@binkert.org dir,tab = os.path.split(output) 846501Snate@binkert.org if not tab.endswith('.py'): 856501Snate@binkert.org raise AttributeError, 'The output file must end with .py' 866501Snate@binkert.org self.yacc_args['outputdir'] = dir 876501Snate@binkert.org self.yacc_args['tabmodule'] = tab[:-3] 886501Snate@binkert.org 896501Snate@binkert.org def t_error(self, t): 906501Snate@binkert.org raise lex.LexError("Illegal character %s @ %d:%d" % \ 916501Snate@binkert.org (`t.value[0]`, t.lineno, t.lexpos), `t.value[0]`) 926501Snate@binkert.org 936501Snate@binkert.org def p_error(self, t): 946501Snate@binkert.org if t: 956501Snate@binkert.org msg = "Syntax error at %d:%d\n>>%s<<" % \ 966501Snate@binkert.org (t.lineno, t.lexpos + 1, t.value) 976501Snate@binkert.org else: 986501Snate@binkert.org msg = "Syntax error at end of input" 996501Snate@binkert.org raise ParseError(msg, t) 1006501Snate@binkert.org 1016501Snate@binkert.org def __getattr__(self, attr): 1026501Snate@binkert.org if attr == 'parser': 1036501Snate@binkert.org import ply.yacc 1046501Snate@binkert.org parser = ply.yacc.yacc(module=self, **self.yacc_args) 1056501Snate@binkert.org self.parser = parser 1066501Snate@binkert.org return parser 1076501Snate@binkert.org 1086501Snate@binkert.org if attr == 'lexer': 1096501Snate@binkert.org import ply.lex 1106501Snate@binkert.org lexer = ply.lex.lex(module=self) 1116501Snate@binkert.org self.lexer = lexer 1126501Snate@binkert.org return lexer 1136501Snate@binkert.org 1146501Snate@binkert.org raise AttributeError, "'%s' object has no attribute '%s'" % \ 1156501Snate@binkert.org (self.__class__.__name__, attr) 1166501Snate@binkert.org 1176501Snate@binkert.org def parse(self, stmt, **kwargs): 1186501Snate@binkert.org self.lexer.lineno = 1 1196501Snate@binkert.org result = self.parser.parse(lexer=Tokenizer(self.lexer, stmt), **kwargs) 1206501Snate@binkert.org self.parser.restart() 1216501Snate@binkert.org 1226501Snate@binkert.org return result 1236501Snate@binkert.org 124