Files
James Gross 80de840881 Even More Syntax Cleanup (#293)
A lot of cleanup things in prep for a python 3 transition. Getting rid of the old exception syntax, converting prints over to logging, cutting random scraps of code to be proper unit tests,  cut away some older bits of code, etc.

This still works in python2. It's just a lot of tidying up. There are no major functionality changes.
2020-09-08 13:00:06 -04:00

176 lines
5.2 KiB
Python

from pycparser import c_parser
import pycparser.c_ast as c_ast
import vstruct
import vstruct.primitives as vs_prim
class StructParser:
def __init__(self, psize=4, bigend=False):
self.psize = psize
self.pclass = vs_prim.v_ptr32
self.cls_parsers = {
c_ast.Decl: self.c_getVsDecl,
c_ast.Struct: self.c_getVsStruct,
c_ast.FileAST: self.c_getFileAst,
c_ast.PtrDecl: self.c_getPointer,
#c_ast.FuncDecl: self.c_getFuncDecl,
c_ast.Constant: self.c_getConstant,
c_ast.TypeDecl: self.c_getVsType,
c_ast.ArrayDecl: self.c_getVsArray,
c_ast.IdentifierType: self.c_getIdentType,
}
self.vs_ctypes = {
('char',): vs_prim.v_int8,
('unsigned','char'): vs_prim.v_uint8,
('short',): vs_prim.v_int16,
('short','int'): vs_prim.v_int16,
('unsigned', 'short',): vs_prim.v_uint16,
('unsigned', 'short','int'):vs_prim.v_uint16,
('int',): vs_prim.v_int32,
('unsigned','int',): vs_prim.v_uint32,
('long',): vs_prim.v_int32,
('long','int'): vs_prim.v_int32,
('unsigned','long',): vs_prim.v_uint32,
('unsigned','long','int'): vs_prim.v_uint32,
}
if psize == 8:
self.pclass = vs_prim.v_ptr64
self.vs_ctypes.update({
('long',): vs_prim.v_int64,
('long', 'int'): vs_prim.v_int64,
('long', 'long'): vs_prim.v_int64,
('unsigned', 'long',): vs_prim.v_uint64,
('unsigned', 'long', 'int'): vs_prim.v_uint64,
('unsigned', 'long', 'long'): vs_prim.v_uint64,
})
def _getVsChildElements(self, astelem):
return [ self._getVsElement( c ) for c in astelem[1].children() ]
def _getVsElement(self, astelem):
# An ast element comes as a tuple of namething, realstuff
namething,elem = astelem
p = self.cls_parsers.get( elem.__class__ )
if p is None:
raise Exception('OMG NO PARSER FOR: %r' % elem)
return p( astelem )
def c_getPointer(self, pdecl):
vsclass = self._getVsChildElements( pdecl )[ 0 ]
return self.pclass
def c_getVsArray(self, ardecl):
cls, size = self._getVsChildElements(ardecl)
# Special case char arrays into v_bytes
if cls == vs_prim.v_int8:
return lambda: vs_prim.v_str(size=size)
return lambda: vstruct.VArray( [ cls() for i in range(size) ] )
def c_getIdentType(self, itelem):
ename, einst = itelem
c = self.vs_ctypes.get(tuple(einst.names))
if not c:
raise Exception('Un-plumbed type: %r' % (einst.names,))
return c
def c_getVsType(self, idelem):
ename, einst = idelem
cls = self._getVsChildElements(idelem)[0]
return cls
def c_getVsDecl(self, decelem):
decname = decelem[1].name
return decname,self._getVsChildElements(decelem)[0]
def c_getVsStruct(self, selem):
sname,sinst = selem
def bstruct():
vs = vstruct.VStruct()
vs._vs_name = sinst.name
for cname,chclass in self._getVsChildElements( selem ):
vobj = chclass()
vs.vsAddField(cname, vobj)
return vs
return bstruct
def c_getFileAst(self, elem):
return self._getVsChildElements(elem)
def c_getConstant(self, celem):
return int(celem[1].value)
def c_getFuncDecl(self, felem):
raise NotImplementedError("Implement function declaration parsing!")
def parseStructSource(self, src):
src = preProcessSource( src )
parser = c_parser.CParser()
ast = parser.parse(src)
#ast.show()
for child in ast.children():
xname, decl = self._getVsElement( child )
yield decl
def preProcessSource( src ):
'''
Carry out some *very* basic pre-processor parsing on the given source.
(only function now is remove "//" style comments!)
'''
lines = src.splitlines()
return '\n'.join( [ line.split('//')[0] for line in lines ] )
def ctorFromCSource(src, psize=4, bigend=False):
'''
Parse and return a callable constructor for the
input C structure source.
'''
p = StructParser(psize=psize, bigend=bigend)
return list(p.parseStructSource( src ))[0]
def vsFromCSource(src, psize=4, bigend=False):
'''
Return a vsobj for a structure parsed from C.
'''
return ctorFromCSource(src, psize, bigend)()
class CVStruct(object):
'''
struct example {
int x;
char y[30];
int *z;
};
'''
psize = 4
bigend = False
def __new__(self):
return vsFromCSource(self.__doc__, self.psize, self.bigend)
class awesome(CVStruct):
'''
struct awesome {
int x,z;
char stuff[20];
int y;
struct haha {
int blah;
} s;
int *q;
};
'''