gnss-sdr/src/algorithms/libs/volk_gnsssdr/gen/volk_gnsssdr_kernel_defs.py

210 lines
8.0 KiB
Python

#
# Copyright 2011-2012 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
import os
import re
import sys
import glob
########################################################################
# Strip comments from a c/cpp file.
# Input is code string, output is code string without comments.
# http://stackoverflow.com/questions/241327/python-snippet-to-remove-c-and-c-comments
########################################################################
def comment_remover(text):
def replacer(match):
s = match.group(0)
if s.startswith('/'):
return ""
else:
return s
pattern = re.compile(
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
re.DOTALL | re.MULTILINE
)
return re.sub(pattern, replacer, text)
########################################################################
# Split code into nested sections according to ifdef preprocessor macros
########################################################################
def split_into_nested_ifdef_sections(code):
sections = list()
section = ''
header = 'text'
in_section_depth = 0
for i, line in enumerate(code.splitlines()):
m = re.match('^(\s*)#(\s*)(\w+)(.*)$', line)
line_is = 'normal'
if m:
p0, p1, fcn, stuff = m.groups()
if fcn in ('if', 'ifndef', 'ifdef'): line_is = 'if'
if fcn in ('else', 'elif'): line_is = 'else'
if fcn in ('endif',): line_is = 'end'
if line_is == 'if': in_section_depth += 1
if line_is == 'end': in_section_depth -= 1
if in_section_depth == 1 and line_is == 'if':
sections.append((header, section))
section = ''
header = line
continue
if in_section_depth == 1 and line_is == 'else':
sections.append((header, section))
section = ''
header = line
continue
if in_section_depth == 0 and line_is == 'end':
sections.append((header, section))
section = ''
header = 'text'
continue
section += line + '\n'
sections.append((header, section)) #and pack remainder into sections
sections = [sec for sec in sections if sec[1].strip()] #filter empty sections
#recurse into non-text sections to fill subsections
for i, (header, section) in enumerate(sections):
if header == 'text': continue
sections[i] = (header, split_into_nested_ifdef_sections(section))
return sections
########################################################################
# Recursive print of sections to test code above
########################################################################
def print_sections(sections, indent = ' '):
for header, body in sections:
if header == 'text':
print indent, ('\n'+indent).join(body.splitlines())
continue
print indent.replace(' ', '-') + '>', header
print_sections(body, indent + ' ')
########################################################################
# Flatten a section to just body text
########################################################################
def flatten_section_text(sections):
output = ''
for hdr, bdy in sections:
if hdr != 'text': output += flatten_section_text(bdy)
else: output += bdy
return output
########################################################################
# Extract kernel info from section, represent as an implementation
########################################################################
class impl_class:
def __init__(self, kern_name, header, body):
#extract LV_HAVE_*
self.deps = set(map(str.lower, re.findall('LV_HAVE_(\w+)', header)))
#extract function suffix and args
body = flatten_section_text(body)
try:
fcn_matcher = re.compile('^.*(%s\\w*)\\s*\\((.*)$'%kern_name, re.DOTALL | re.MULTILINE)
body = body.split('{')[0].rsplit(')', 1)[0] #get the part before the open ){ bracket
m = fcn_matcher.match(body)
impl_name, the_rest = m.groups()
self.name = impl_name.replace(kern_name+'_', '')
self.args = list()
fcn_args = the_rest.split(',')
for fcn_arg in fcn_args:
arg_matcher = re.compile('^\s*(.*\\W)\s*(\w+)\s*$', re.DOTALL | re.MULTILINE)
m = arg_matcher.match(fcn_arg)
arg_type, arg_name = m.groups()
self.args.append((arg_type, arg_name))
except Exception as ex:
raise Exception, 'I cant parse the function prototype from: %s in %s\n%s'%(kern_name, body, ex)
assert self.name
self.is_aligned = self.name.startswith('a_')
def __repr__(self):
return self.name
########################################################################
# Get sets of LV_HAVE_* from the code
########################################################################
def extract_lv_haves(code):
haves = list()
for line in code.splitlines():
if not line.strip().startswith('#'): continue
have_set = set(map(str.lower, re.findall('LV_HAVE_(\w+)', line)))
if have_set: haves.append(have_set)
return haves
########################################################################
# Represent a processing kernel, parse from file
########################################################################
class kernel_class:
def __init__(self, kernel_file):
self.name = os.path.splitext(os.path.basename(kernel_file))[0]
self.pname = self.name.replace('volk_gnsssdr_', 'p_')
code = open(kernel_file, 'r').read()
code = comment_remover(code)
sections = split_into_nested_ifdef_sections(code)
self._impls = list()
for header, section in sections:
if 'ifndef' not in header.lower(): continue
for sub_hdr, body in section:
if 'if' not in sub_hdr.lower(): continue
if 'LV_HAVE_' not in sub_hdr: continue
self._impls.append(impl_class(
kern_name=self.name, header=sub_hdr, body=body,
))
assert(self._impls)
self.has_dispatcher = False
for impl in self._impls:
if impl.name == 'dispatcher':
self._impls.remove(impl)
self.has_dispatcher = True
break
self.args = self._impls[0].args
self.arglist_types = ', '.join([a[0] for a in self.args])
self.arglist_full = ', '.join(['%s %s'%a for a in self.args])
self.arglist_names = ', '.join([a[1] for a in self.args])
def get_impls(self, archs):
archs = set(archs)
impls = list()
for impl in self._impls:
if impl.deps.intersection(archs) == impl.deps:
impls.append(impl)
return impls
def __repr__(self):
return self.name
########################################################################
# Extract information from the VOLK kernels
########################################################################
__file__ = os.path.abspath(__file__)
srcdir = os.path.dirname(os.path.dirname(__file__))
kernel_files = glob.glob(os.path.join(srcdir, "kernels", "volk_gnsssdr", "*.h"))
kernels = map(kernel_class, kernel_files)
if __name__ == '__main__':
print kernels