grammar.py (6660:a886774d5ae1) | grammar.py (8452:3f2c329e9046) |
---|---|
1# Copyright (c) 2006-2009 Nathan Binkert <nate@binkert.org> | 1# Copyright (c) 2006-2011 Nathan Binkert <nate@binkert.org> |
2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are 6# met: redistributions of source code must retain the above copyright 7# notice, this list of conditions and the following disclaimer; 8# redistributions in binary form must reproduce the above copyright 9# notice, this list of conditions and the following disclaimer in the --- 9 unchanged lines hidden (view full) --- 19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are 6# met: redistributions of source code must retain the above copyright 7# notice, this list of conditions and the following disclaimer; 8# redistributions in binary form must reproduce the above copyright 9# notice, this list of conditions and the following disclaimer in the --- 9 unchanged lines hidden (view full) --- 19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 |
27from ply import lex, yacc | 27import os |
28 | 28 |
29class TokenError(lex.LexError): 30 def __init__(self, msg, t): 31 super(TokenError, self).__init__(msg) 32 self.token = t | 29import ply.lex 30import ply.yacc |
33 | 31 |
34class ParseError(yacc.YaccError): | 32class ParseError(Exception): |
35 def __init__(self, message, token=None): | 33 def __init__(self, message, token=None): |
36 super(ParseError, self).__init__(message) | 34 Exception.__init__(self, message) |
37 self.token = token 38 | 35 self.token = token 36 |
39class Tokenizer(object): 40 def __init__(self, lexer, data): 41 if isinstance(data, basestring): 42 indata = [ data ] 43 elif isinstance(data, file): 44 indata = data.xreadlines() 45 else: 46 indata = data | 37class Grammar(object): 38 def setupLexerFactory(self, **kwargs): 39 if 'module' in kwargs: 40 raise AttributeError, "module is an illegal attribute" 41 self.lex_kwargs = kwargs |
47 | 42 |
48 def _input(): 49 for i,line in enumerate(indata): 50 lexer.lineno = i + 1 51 lexer.input(line) 52 while True: 53 tok = lexer.token() 54 if not tok: 55 break 56 yield tok 57 self.input = _input() 58 self.lexer = lexer | 43 def setupParserFactory(self, **kwargs): 44 if 'module' in kwargs: 45 raise AttributeError, "module is an illegal attribute" |
59 | 46 |
60 def next(self): 61 return self.input.next() | 47 if 'output' in kwargs: 48 dir,tab = os.path.split(output) 49 if not tab.endswith('.py'): 50 raise AttributeError, \ 51 'The output file must end with .py' 52 kwargs['outputdir'] = dir 53 kwargs['tabmodule'] = tab[:-3] |
62 | 54 |
63 def __iter__(self): 64 return self | 55 self.yacc_kwargs = kwargs |
65 | 56 |
66 def token(self): 67 try: 68 return self.next() 69 except StopIteration: 70 return None 71 | |
72 def __getattr__(self, attr): | 57 def __getattr__(self, attr): |
73 return getattr(self.lexer, attr) | 58 if attr == 'lexers': 59 self.lexers = [] 60 return self.lexers |
74 | 61 |
75class Grammar(object): 76 def __init__(self, output=None, debug=False): 77 self.yacc_args = {} 78 self.yacc_args['debug'] = debug | 62 if attr == 'lex_kwargs': 63 self.setupLexerFactory() 64 return self.lex_kwargs |
79 | 65 |
80 if output: 81 import os | 66 if attr == 'yacc_kwargs': 67 self.setupParserFactory() 68 return self.yacc_kwargs |
82 | 69 |
83 dir,tab = os.path.split(output) 84 if not tab.endswith('.py'): 85 raise AttributeError, 'The output file must end with .py' 86 self.yacc_args['outputdir'] = dir 87 self.yacc_args['tabmodule'] = tab[:-3] | 70 if attr == 'lex': 71 self.lex = ply.lex.lex(module=self, **self.lex_kwargs) 72 return self.lex |
88 | 73 |
89 def t_error(self, t): 90 raise lex.LexError("Illegal character %s @ %d:%d" % \ 91 (`t.value[0]`, t.lineno, t.lexpos), `t.value[0]`) | 74 if attr == 'yacc': 75 self.yacc = ply.yacc.yacc(module=self, **self.yacc_kwargs) 76 return self.yacc |
92 | 77 |
93 def p_error(self, t): 94 if t: 95 msg = "Syntax error at %d:%d\n>>%s<<" % \ 96 (t.lineno, t.lexpos + 1, t.value) 97 else: 98 msg = "Syntax error at end of input" 99 raise ParseError(msg, t) | 78 if attr == 'current_lexer': 79 if not self.lexers: 80 return None 81 return self.lexers[-1][0] |
100 | 82 |
101 def __getattr__(self, attr): 102 if attr == 'parser': 103 import ply.yacc 104 parser = ply.yacc.yacc(module=self, **self.yacc_args) 105 self.parser = parser 106 return parser | 83 if attr == 'current_source': 84 if not self.lexers: 85 return '<none>' 86 return self.lexers[-1][1] |
107 | 87 |
108 if attr == 'lexer': 109 import ply.lex 110 lexer = ply.lex.lex(module=self) 111 self.lexer = lexer 112 return lexer | 88 if attr == 'current_line': 89 if not self.lexers: 90 return -1 91 return self.current_lexer.lineno |
113 | 92 |
114 raise AttributeError, "'%s' object has no attribute '%s'" % \ 115 (self.__class__.__name__, attr) | 93 raise AttributeError, \ 94 "'%s' object has no attribute '%s'" % (type(self), attr) |
116 | 95 |
117 def parse(self, stmt, **kwargs): 118 self.lexer.lineno = 1 119 result = self.parser.parse(lexer=Tokenizer(self.lexer, stmt), **kwargs) 120 self.parser.restart() | 96 def parse_string(self, data, source='<string>', debug=None, tracking=0): 97 if not isinstance(data, basestring): 98 raise AttributeError, \ 99 "argument must be a string, was '%s'" % type(f) |
121 | 100 |
101 import new 102 lexer = self.lex.clone() 103 lexer.input(data) 104 self.lexers.append((lexer, source)) 105 dict = { 106 'productions' : self.yacc.productions, 107 'action' : self.yacc.action, 108 'goto' : self.yacc.goto, 109 'errorfunc' : self.yacc.errorfunc, 110 } 111 parser = new.instance(ply.yacc.LRParser, dict) 112 result = parser.parse(lexer=lexer, debug=debug, tracking=tracking) 113 self.lexers.pop() |
|
122 return result 123 | 114 return result 115 |
116 def parse_file(self, f, **kwargs): 117 if isinstance(f, basestring): 118 source = f 119 f = file(f, 'r') 120 elif isinstance(f, file): 121 source = f.name 122 else: 123 raise AttributeError, \ 124 "argument must be either a string or file, was '%s'" % type(f) 125 126 return self.parse_string(f.read(), source, **kwargs) 127 128 def p_error(self, t): 129 if t: 130 msg = "Syntax error at %s:%d:%d\n>>%s<<" % \ 131 (self.current_source, t.lineno, t.lexpos + 1, t.value) 132 else: 133 msg = "Syntax error at end of %s" % (self.current_source, ) 134 raise ParseError(msg, t) 135 136 def t_error(self, t): 137 msg = "Illegal character %s @ %d:%d" % \ 138 (`t.value[0]`, t.lineno, t.lexpos) 139 raise ParseError(msg, t) |
|