blob: 6ac638bcd0df56daf7b82264e09d7e7539de21b1 [file] [log] [blame]
Nathan Binkert3d252f82011-07-05 18:30:04 -07001# Copyright (c) 2006-2011 Nathan Binkert <nate@binkert.org>
Nathan Binkert2ecaa992009-08-16 13:40:01 -07002# 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
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
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
Nathan Binkert3d252f82011-07-05 18:30:04 -070027import os
Nathan Binkert2ecaa992009-08-16 13:40:01 -070028
Nathan Binkert3d252f82011-07-05 18:30:04 -070029import ply.lex
30import ply.yacc
Nathan Binkert2ecaa992009-08-16 13:40:01 -070031
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070032
Nathan Binkert3d252f82011-07-05 18:30:04 -070033class ParseError(Exception):
Nathan Binkert2ecaa992009-08-16 13:40:01 -070034 def __init__(self, message, token=None):
Nathan Binkert3d252f82011-07-05 18:30:04 -070035 Exception.__init__(self, message)
Nathan Binkert2ecaa992009-08-16 13:40:01 -070036 self.token = token
37
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070038
Nathan Binkert2ecaa992009-08-16 13:40:01 -070039class Grammar(object):
Nathan Binkert3d252f82011-07-05 18:30:04 -070040 def setupLexerFactory(self, **kwargs):
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070041 if "module" in kwargs:
Andreas Sandbergfa211272019-01-25 11:32:25 +000042 raise AttributeError("module is an illegal attribute")
Nathan Binkert3d252f82011-07-05 18:30:04 -070043 self.lex_kwargs = kwargs
Nathan Binkert2ecaa992009-08-16 13:40:01 -070044
Nathan Binkert3d252f82011-07-05 18:30:04 -070045 def setupParserFactory(self, **kwargs):
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070046 if "module" in kwargs:
Andreas Sandbergfa211272019-01-25 11:32:25 +000047 raise AttributeError("module is an illegal attribute")
Nathan Binkert2ecaa992009-08-16 13:40:01 -070048
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070049 if "output" in kwargs:
50 dir, tab = os.path.split(output)
51 if not tab.endswith(".py"):
52 raise AttributeError("The output file must end with .py")
53 kwargs["outputdir"] = dir
54 kwargs["tabmodule"] = tab[:-3]
Nathan Binkert2ecaa992009-08-16 13:40:01 -070055
Nathan Binkert3d252f82011-07-05 18:30:04 -070056 self.yacc_kwargs = kwargs
57
58 def __getattr__(self, attr):
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070059 if attr == "lexers":
Nathan Binkert3d252f82011-07-05 18:30:04 -070060 self.lexers = []
61 return self.lexers
62
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070063 if attr == "lex_kwargs":
Nathan Binkert3d252f82011-07-05 18:30:04 -070064 self.setupLexerFactory()
65 return self.lex_kwargs
66
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070067 if attr == "yacc_kwargs":
Nathan Binkert3d252f82011-07-05 18:30:04 -070068 self.setupParserFactory()
69 return self.yacc_kwargs
70
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070071 if attr == "lex":
Nathan Binkert3d252f82011-07-05 18:30:04 -070072 self.lex = ply.lex.lex(module=self, **self.lex_kwargs)
73 return self.lex
74
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070075 if attr == "yacc":
Nathan Binkert3d252f82011-07-05 18:30:04 -070076 self.yacc = ply.yacc.yacc(module=self, **self.yacc_kwargs)
77 return self.yacc
78
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070079 if attr == "current_lexer":
Nathan Binkert3d252f82011-07-05 18:30:04 -070080 if not self.lexers:
81 return None
82 return self.lexers[-1][0]
83
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070084 if attr == "current_source":
Nathan Binkert3d252f82011-07-05 18:30:04 -070085 if not self.lexers:
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070086 return "<none>"
Nathan Binkert3d252f82011-07-05 18:30:04 -070087 return self.lexers[-1][1]
88
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070089 if attr == "current_line":
Nathan Binkert3d252f82011-07-05 18:30:04 -070090 if not self.lexers:
91 return -1
92 return self.current_lexer.lineno
93
Andreas Sandbergfa211272019-01-25 11:32:25 +000094 raise AttributeError(
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070095 "'%s' object has no attribute '%s'" % (type(self), attr)
96 )
Nathan Binkert3d252f82011-07-05 18:30:04 -070097
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -070098 def parse_string(self, data, source="<string>", debug=None, tracking=0):
Andreas Sandberg4b9c46c2021-01-21 17:09:38 +000099 if not isinstance(data, str):
Andreas Sandbergfa211272019-01-25 11:32:25 +0000100 raise AttributeError(
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -0700101 "argument must be a string, was '%s'" % type(f)
102 )
Nathan Binkert3d252f82011-07-05 18:30:04 -0700103
Nathan Binkert3d252f82011-07-05 18:30:04 -0700104 lexer = self.lex.clone()
105 lexer.input(data)
106 self.lexers.append((lexer, source))
Giacomo Travaglini735267e2020-02-28 13:42:03 +0000107
108 lrtab = ply.yacc.LRTable()
109 lrtab.lr_productions = self.yacc.productions
110 lrtab.lr_action = self.yacc.action
111 lrtab.lr_goto = self.yacc.goto
112
113 parser = ply.yacc.LRParser(lrtab, self.yacc.errorfunc)
Nathan Binkert3d252f82011-07-05 18:30:04 -0700114 result = parser.parse(lexer=lexer, debug=debug, tracking=tracking)
115 self.lexers.pop()
116 return result
117
118 def parse_file(self, f, **kwargs):
Andreas Sandberg4b9c46c2021-01-21 17:09:38 +0000119 if isinstance(f, str):
Nathan Binkert3d252f82011-07-05 18:30:04 -0700120 source = f
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -0700121 f = open(f, "r")
Nathan Binkert3d252f82011-07-05 18:30:04 -0700122 elif isinstance(f, file):
123 source = f.name
124 else:
Andreas Sandbergfa211272019-01-25 11:32:25 +0000125 raise AttributeError(
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -0700126 "argument must be either a string or file, was '%s'" % type(f)
127 )
Nathan Binkert3d252f82011-07-05 18:30:04 -0700128
129 return self.parse_string(f.read(), source, **kwargs)
Nathan Binkert2ecaa992009-08-16 13:40:01 -0700130
131 def p_error(self, t):
132 if t:
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -0700133 msg = "Syntax error at %s:%d:%d\n>>%s<<" % (
134 self.current_source,
135 t.lineno,
136 t.lexpos + 1,
137 t.value,
138 )
Nathan Binkert2ecaa992009-08-16 13:40:01 -0700139 else:
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -0700140 msg = "Syntax error at end of %s" % (self.current_source,)
Nathan Binkert2ecaa992009-08-16 13:40:01 -0700141 raise ParseError(msg, t)
142
Nathan Binkert3d252f82011-07-05 18:30:04 -0700143 def t_error(self, t):
Bobby R. Bruce2bc5a8b2022-08-22 12:34:19 -0700144 msg = "Illegal character %s @ %d:%d" % (
145 repr(t.value[0]),
146 t.lineno,
147 t.lexpos,
148 )
Nathan Binkert3d252f82011-07-05 18:30:04 -0700149 raise ParseError(msg, t)