Amend build script to generate an encodings-<isa>.rs file for each target ISA. Emit a function that can evaluate instruction predicates. Describe the 3-level tables used for representing insrruction encoding tables. Add Python classes representing the tables. The generated code is incomplete and not used anywhere yet.
128 lines
3.2 KiB
Python
128 lines
3.2 KiB
Python
"""
|
|
Source code generator.
|
|
|
|
The `srcgen` module contains generic helper routines and classes for generating
|
|
source code.
|
|
|
|
"""
|
|
from __future__ import absolute_import
|
|
import sys
|
|
import os
|
|
import re
|
|
|
|
|
|
class Formatter(object):
|
|
"""
|
|
Source code formatter class.
|
|
|
|
- Collect source code to be written to a file.
|
|
- Keep track of indentation.
|
|
|
|
Indentation example:
|
|
|
|
>>> f = Formatter()
|
|
>>> f.line('Hello line 1')
|
|
>>> f.writelines()
|
|
Hello line 1
|
|
>>> f.indent_push()
|
|
>>> f.comment('Nested comment')
|
|
>>> f.indent_pop()
|
|
>>> f.format('Back {} again', 'home')
|
|
>>> f.writelines()
|
|
Hello line 1
|
|
// Nested comment
|
|
Back home again
|
|
|
|
"""
|
|
|
|
shiftwidth = 4
|
|
|
|
def __init__(self):
|
|
self.indent = ''
|
|
self.lines = []
|
|
|
|
def indent_push(self):
|
|
"""Increase current indentation level by one."""
|
|
self.indent += ' ' * self.shiftwidth
|
|
|
|
def indent_pop(self):
|
|
"""Decrease indentation by one level."""
|
|
assert self.indent != '', 'Already at top level indentation'
|
|
self.indent = self.indent[0:-self.shiftwidth]
|
|
|
|
def line(self, s=None):
|
|
"""Add an indented line."""
|
|
if s:
|
|
self.lines.append('{}{}\n'.format(self.indent, s))
|
|
else:
|
|
self.lines.append('\n')
|
|
|
|
def outdented_line(self, s):
|
|
"""
|
|
Emit a line outdented one level.
|
|
|
|
This is used for '} else {' and similar things inside a single indented
|
|
block.
|
|
"""
|
|
self.lines.append('{}{}\n'.format(self.indent[0:-self.shiftwidth], s))
|
|
|
|
def writelines(self, f=None):
|
|
"""Write all lines to `f`."""
|
|
if not f:
|
|
f = sys.stdout
|
|
f.writelines(self.lines)
|
|
|
|
def update_file(self, filename, directory):
|
|
if directory is not None:
|
|
filename = os.path.join(directory, filename)
|
|
with open(filename, 'w') as f:
|
|
self.writelines(f)
|
|
|
|
class _IndentedScope(object):
|
|
def __init__(self, fmt, after):
|
|
self.fmt = fmt
|
|
self.after = after
|
|
|
|
def __enter__(self):
|
|
self.fmt.indent_push()
|
|
|
|
def __exit__(self, t, v, tb):
|
|
self.fmt.indent_pop()
|
|
if self.after:
|
|
self.fmt.line(self.after)
|
|
|
|
def indented(self, before=None, after=None):
|
|
"""
|
|
Return a scope object for use with a `with` statement:
|
|
|
|
>>> f = Formatter()
|
|
>>> with f.indented('prefix {', '} suffix'):
|
|
... f.line('hello')
|
|
>>> f.writelines()
|
|
prefix {
|
|
hello
|
|
} suffix
|
|
|
|
The optional `before` and `after` parameters are surrounding lines
|
|
which are *not* indented.
|
|
"""
|
|
if before:
|
|
self.line(before)
|
|
return self._IndentedScope(self, after)
|
|
|
|
def format(self, fmt, *args):
|
|
self.line(fmt.format(*args))
|
|
|
|
def comment(self, s):
|
|
"""Add a comment line."""
|
|
self.line('// ' + s)
|
|
|
|
def doc_comment(self, s):
|
|
"""Add a (multi-line) documentation comment."""
|
|
s = re.sub('^', self.indent + '/// ', s, flags=re.M) + '\n'
|
|
self.lines.append(s)
|
|
|
|
if __name__ == "__main__":
|
|
import doctest
|
|
doctest.testmod()
|