CACAO
instruction_gen.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # src/vm/jit/compiler2/instruction_table.csv - instruction table
3 #
4 # Copyright (C) 2013
5 # CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 #
7 # This file is part of CACAO.
8 #
9 # This program is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU General Public License as
11 # published by the Free Software Foundation; either version 2, or (at
12 # your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 # General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 # 02110-1301, USA.
23 #
24 #
25 
26 ##
27 # This file contains the generator for the instruction table
28 ##
29 
30 import sys
31 import argparse
32 import re
33 import string
34 
35 cpp_header = """/* src/vm/jit/compiler2/{filename} - {file_desc}
36 
37  Copyright (C) 2013
38  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
39 
40  This file is part of CACAO.
41 
42  This program is free software; you can redistribute it and/or
43  modify it under the terms of the GNU General Public License as
44  published by the Free Software Foundation; either version 2, or (at
45  your option) any later version.
46 
47  This program is distributed in the hope that it will be useful, but
48  WITHOUT ANY WARRANTY; without even the implied warranty of
49  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
50  General Public License for more details.
51 
52  You should have received a copy of the GNU General Public License
53  along with this program; if not, write to the Free Software
54  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
55  02110-1301, USA.
56 
57 */
58 
59 """
60 
61 cpp_generation_disclaimer = """/*
62 WARNING: THIS FILE IS AUTO-GENERATED! DO NOT ALTER!
63 Instead have a look at the generator ({generator})
64 and the input file ({input_file}).
65 */
66 
67 """
68 
69 cpp_footer = """
70 /*
71  * These are local overrides for various environment variables in Emacs.
72  * Please do not remove this and leave it at the end of the file, where
73  * Emacs will automagically detect them.
74  * ---------------------------------------------------------------------
75  * Local variables:
76  * mode: c++
77  * indent-tabs-mode: t
78  * c-basic-offset: 4
79  * tab-width: 4
80  * End:
81  * vim:noexpandtab:sw=4:ts=4:
82  */
83 """
84 
85 class Formatter(string.Formatter):
86  def convert_field(self, value, conversion):
87  if 'U' == conversion:
88  return value.upper()
89  elif 'l' == conversion:
90  return value.lower()
91  else:
92  return super(Formatter, self).convert_field(value, conversion)
93 
94 class Template:
95  def __init__(self,filename,file_desc, line, header='',footer=''):
96  self.file = open(filename,'w')
97  self.filename = filename
98  self.line = line
99  self.file_desc = file_desc
100  self.header = header
101  self.footer = footer
102  def print_header(self, entry):
103  try:
104  self.file.write(Formatter().format(self.header, filename = self.filename, file_desc = self.file_desc, **entry))
105  except KeyError as e:
106  print 'Unknown template key: ', e
107  sys.exit(1)
108 
109  def print_line(self, entry):
110  try:
111  self.file.write(Formatter().format(self.line, filename = self.filename, file_desc = self.file_desc, **entry))
112  except KeyError as e:
113  print 'Unknown template key: ', e
114  sys.exit(1)
115 
116  def print_footer(self, entry):
117  try:
118  self.file.write(Formatter().format(self.footer, filename = self.filename, file_desc = self.file_desc, **entry))
119  except KeyError as e:
120  print 'Unknown template key: ', e
121  sys.exit(1)
122 
123 def main(temps):
124  default_file = './instruction_table.csv'
125  comment_pattern = re.compile(r'^[^#]*')
126  #entry_pattern = re.compile(r'(?P<name>\w+),(?P<desc>"\w+")')
127  entry_pattern = re.compile(r'(?P<name>\w+)')
128 
129  # command line arguments
130  parser = argparse.ArgumentParser(description='Generate instruction table includes.')
131  parser.add_argument('table', nargs='?', type=file,
132  help='instruction table file [default='+default_file+']', default=default_file)
133  try:
134  args = parser.parse_args()
135  except IOError as e:
136  print str(e)
137  sys.exit(1)
138 
139  keys = {
140  'generator' : sys.argv[0],
141  'input_file': args.table.name,
142  }
143 
144  # print headers
145  for t in temps:
146  t.print_header(keys)
147  # iterate entries
148  line_nr = 0
149  for line in args.table:
150  line_nr += 1
151  # clean lines
152  sline = comment_pattern.match(line).group(0)
153  sline = sline.strip()
154  if not sline:
155  continue
156  entry = entry_pattern.match(sline)
157  if not entry:
158  print 'Error in line: ' + str(line_nr) + ' :' + line.strip()
159  continue
160 
161  entry = entry.groupdict()
162  # print line
163  for t in temps:
164  t.print_line(dict(keys.items() + entry.items()))
165 
166  # print footer
167  for t in temps:
168  t.print_footer(keys)
169 
170 def burg():
171  default_file = './instruction_table.csv'
172  comment_pattern = re.compile(r'^[^#]*')
173  #entry_pattern = re.compile(r'(?P<name>\w+),(?P<desc>"\w+")')
174  entry_pattern = re.compile(r'(?P<name>\w+)(,(?P<ops>\d+))?')
175 
176  # command line arguments
177  parser = argparse.ArgumentParser(description='Generate instruction table includes.')
178  parser.add_argument('table', nargs='?', type=file,
179  help='instruction table file [default='+default_file+']', default=default_file)
180  try:
181  args = parser.parse_args()
182  except IOError as e:
183  print str(e)
184  sys.exit(1)
185 
186  keys = {
187  'generator' : sys.argv[0],
188  'input_file': args.table.name
189  }
190 
191  bigdict = {}
192  excludes = []
193 
194 
195 
196  ex_header = cpp_header + cpp_generation_disclaimer
197 
198  ex_header = ex_header.replace("{filename}", "GrammarExcludedNodes.inc")
199  ex_header = ex_header.replace("{file_desc}", "Instructions that are excluded from pattern matching")
200  ex_header = ex_header.replace("{generator}", "src/vm/jit/compiler2/instruction_gen.py and contrib/patternmatching/")
201  ex_header = ex_header.replace("{input_file}", "instruction_table.csv")
202 
203  excludednodes = open('GrammarExcludedNodes.inc','w')
204 
205  excludednodes.write(ex_header)
206 
207  enumid = 0
208  line_nr = 0
209  for line in args.table:
210  line_nr += 1
211  # clean lines
212  sline = comment_pattern.match(line).group(0)
213  sline = sline.strip()
214  if not sline:
215  continue
216  entry = entry_pattern.match(sline)
217  if not entry:
218  print 'Error in line: ' + str(line_nr) + ' :' + line.strip()
219  continue
220 
221  entry = entry.groupdict()
222 
223  entry['enumid'] = enumid
224  if entry['ops']:
225  bigdict[enumid] = entry
226  else:
227  excludes.append(entry)
228 
229  enumid += 1
230 
231  for i in range(0, len(excludes)):
232  e = excludes[i]
233  excludednodes.write('Instruction::' + e['name'] + 'ID')# = ' + str(e['enumid']))
234  if len(excludes)-1 > i:
235  excludednodes.write(',')
236  excludednodes.write('\n')
237 
238  excludednodes.write(cpp_footer)
239 
240  # add NoInstID
241  noinstentry = {'enumid' : enumid, 'ops' : 0, 'name' : 'NoInst'}
242  bigdict[enumid] = noinstentry
243  # print bigdict
244 
245  brgfile = open('GrammarBase.brg','w')
246 
247  gram_header = cpp_header + cpp_generation_disclaimer
248 
249  gram_header = gram_header.replace("{filename}", "GrammarBase.brg")
250  gram_header = gram_header.replace("{file_desc}", "Generated Basic Grammar")
251  gram_header = gram_header.replace("{generator}", "src/vm/jit/compiler2/instruction_gen.py and contrib/patternmatching/")
252  gram_header = gram_header.replace("{input_file}", "instruction_table.csv")
253 
254  brgfile.write('%{\n' + gram_header + '%}\n%start stm\n')
255 
256  for op in bigdict.itervalues():
257  brgfile.write('%term ' + op['name'] + 'ID = ' + str(op['enumid']) + '\n')
258 
259  brgfile.write('%%\n');
260 
261  for op in bigdict.itervalues():
262  brgfile.write('stm: ' + op['name'] + 'ID')
263  if int(op['ops']) > 0:
264  brgfile.write('(')
265  for numops in range (0, int(op['ops'])):
266  brgfile.write('stm')
267  if (numops < int(op['ops']) - 1):
268  brgfile.write(',')
269  brgfile.write(')')
270 
271  brgfile.write(' "' + op['name'] + 'ID" 1 \n')
272 
273 
274 if __name__ == '__main__':
275  temps = [
276  Template('InstructionDeclGen.inc','Instruction Declarations','class {name};\n',
277  cpp_header+cpp_generation_disclaimer,cpp_footer),
278  Template('InstructionIDGen.inc','Instruction IDs','{name}ID,\n',
279  cpp_header+cpp_generation_disclaimer,cpp_footer),
280  Template('InstructionToInstGen.inc','Instruction conversion methods',
281  'virtual {name}* to_{name}() {{ return NULL; }}\n',
282  cpp_header+cpp_generation_disclaimer,cpp_footer),
283  Template('InstructionNameSwitchGen.inc','Instruction name switch',
284  'case {name}ID: return "{name}";\n',
285  cpp_header+cpp_generation_disclaimer,cpp_footer),
286  Template('InstructionVisitorGen.inc','Instruction Visitor',
287  'virtual void visit({name}* I, bool copyOperands);\n',
288  cpp_header+cpp_generation_disclaimer,cpp_footer),
289  Template('InstructionVisitorImplGen.inc','Instruction Visitor',
290  'void InstructionVisitor::visit({name}* I, bool copyOperands) {{visit_default(I);}}\n',
291  cpp_header+cpp_generation_disclaimer,cpp_footer),
292  ]
293  main(temps)
294  burg()
295 
296 
297 #
298 # These are local overrides for various environment variables in Emacs.
299 # Please do not remove this and leave it at the end of the file, where
300 # Emacs will automagically detect them.
301 # ---------------------------------------------------------------------
302 # Local variables:
303 # mode: python
304 # indent-tabs-mode: t
305 # c-basic-offset: 4
306 # tab-width: 4
307 # End:
308 # vim:noexpandtab:sw=4:ts=4:
309 #