Merge commit '7621e2f8dec938cf48181c8b10afc9b01f444e68' into beta

This commit is contained in:
Ilya Laktyushin
2025-12-06 02:17:48 +04:00
commit 8344b97e03
28070 changed files with 7995182 additions and 0 deletions
@@ -0,0 +1,79 @@
PYBINDING_DEPS = tools/python-yasm/bytecode.pxi
PYBINDING_DEPS += tools/python-yasm/errwarn.pxi
PYBINDING_DEPS += tools/python-yasm/expr.pxi
PYBINDING_DEPS += tools/python-yasm/floatnum.pxi
PYBINDING_DEPS += tools/python-yasm/intnum.pxi
PYBINDING_DEPS += tools/python-yasm/symrec.pxi
PYBINDING_DEPS += tools/python-yasm/value.pxi
EXTRA_DIST += tools/python-yasm/pyxelator/cparse.py
EXTRA_DIST += tools/python-yasm/pyxelator/genpyx.py
EXTRA_DIST += tools/python-yasm/pyxelator/ir.py
EXTRA_DIST += tools/python-yasm/pyxelator/lexer.py
EXTRA_DIST += tools/python-yasm/pyxelator/node.py
EXTRA_DIST += tools/python-yasm/pyxelator/parse_core.py
EXTRA_DIST += tools/python-yasm/pyxelator/work_unit.py
EXTRA_DIST += tools/python-yasm/pyxelator/wrap_yasm.py
EXTRA_DIST += tools/python-yasm/setup.py
EXTRA_DIST += tools/python-yasm/yasm.pyx
EXTRA_DIST += $(PYBINDING_DEPS)
if HAVE_PYTHON_BINDINGS
# Use Pyxelator to generate Pyrex function headers.
_yasm.pxi: ${HEADERS}
@rm -rf .tmp
@mkdir .tmp
$(PYTHON) $(srcdir)/tools/python-yasm/pyxelator/wrap_yasm.py \
"YASM_DIR=${srcdir}" "CPP=${CPP}" "CPPFLAGS=${CPPFLAGS}"
@rm -rf .tmp
CLEANFILES += _yasm.pxi
# Need to build a local copy of the main Pyrex input file to include _yasm.pxi
# from the build directory. Also need to fixup the other .pxi include paths.
yasm.pyx: $(srcdir)/tools/python-yasm/yasm.pyx
sed -e 's,^include "\([^_]\),include "${srcdir}/tools/python-yasm/\1,' \
$(srcdir)/tools/python-yasm/yasm.pyx > $@
CLEANFILES += yasm.pyx
# Actually run Cython
yasm_python.c: yasm.pyx _yasm.pxi $(PYBINDING_DEPS)
$(PYTHON) -c "from Cython.Compiler.Main import main; main(command_line=1)" \
-o $@ yasm.pyx
CLEANFILES += yasm_python.c
# Now the Python build magic...
python-setup.txt: Makefile
echo "includes=${DEFS} ${DEFAULT_INCLUDES} ${INCLUDES} ${AM_CPPFLAGS} ${CPPFLAGS}" > python-setup.txt
echo "sources=${libyasm_a_SOURCES} ${nodist_libyasm_a_SOURCES}" >> python-setup.txt
echo "srcdir=${srcdir}" >> python-setup.txt
echo "gcc=${GCC}" >> python-setup.txt
CLEANFILES += python-setup.txt
.python-build: python-setup.txt yasm_python.c ${libyasm_a_SOURCES} ${nodist_libyasm_a_SOURCES}
$(PYTHON) `test -f tools/python-yasm/setup.py || echo '$(srcdir)/'`tools/python-yasm/setup.py build
touch .python-build
python-build: .python-build
CLEANFILES += .python-build
python-install: .python-build
$(PYTHON) `test -f tools/python-yasm/setup.py || echo '$(srcdir)/'`tools/python-yasm/setup.py install "--install-lib=$(DESTDIR)$(pythondir)"
python-uninstall:
rm -f `$(PYTHON) -c "import sys;sys.path.insert(0, '${DESTDIR}${pythondir}'); import yasm; print yasm.__file__"`
else
python-build:
python-install:
python-uninstall:
endif
EXTRA_DIST += tools/python-yasm/tests/Makefile.inc
include tools/python-yasm/tests/Makefile.inc
@@ -0,0 +1,107 @@
# Python bindings for Yasm: Pyrex input file for bytecode.h
#
# Copyright (C) 2006 Michael Urman, Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
cdef class Bytecode:
cdef yasm_bytecode *bc
cdef object __weakref__ # make weak-referenceable
def __cinit__(self, bc):
self.bc = NULL
if PyCObject_Check(bc):
self.bc = <yasm_bytecode *>__get_voidp(bc, Bytecode)
else:
raise NotImplementedError
def __dealloc__(self):
# Only free if we're not part of a section; if we're part of a section
# the section takes care of freeing the bytecodes.
if self.bc.section == NULL:
yasm_bc_destroy(self.bc)
property len:
def __get__(self): return self.bc.len
def __set__(self, value): self.bc.len = value
property mult_int:
def __get__(self): return self.bc.mult_int
def __set__(self, value): self.bc.mult_int = value
property line:
def __get__(self): return self.bc.line
def __set__(self, value): self.bc.line = value
property offset:
def __get__(self): return self.bc.offset
def __set__(self, value): self.bc.offset = value
property bc_index:
def __get__(self): return self.bc.bc_index
def __set__(self, value): self.bc.bc_index = value
property symbols:
# Someday extend this to do something modifiable, e.g. return a
# list-like object.
def __get__(self):
cdef yasm_symrec *sym
cdef int i
if self.bc.symrecs == NULL:
return []
s = []
i = 0
sym = self.bc.symrecs[i]
while sym != NULL:
s.append(__make_symbol(sym))
i = i+1
sym = self.bc.symrecs[i]
return s
#
# Keep Bytecode reference paired with bc using weak references.
# This is broken in Pyrex 0.9.4.1; Pyrex 0.9.5 has a working version.
#
from weakref import WeakValueDictionary as __weakvaldict
__bytecode_map = __weakvaldict()
#__bytecode_map = {}
cdef object __make_bytecode(yasm_bytecode *bc):
__error_check()
vptr = PyCObject_FromVoidPtr(bc, NULL)
data = __bytecode_map.get(vptr, None)
if data:
return data
bcobj = Bytecode(__pass_voidp(bc, Bytecode))
__bytecode_map[vptr] = bcobj
return bcobj
# Org bytecode
def __org__new__(cls, start, value=0, line=0):
cdef yasm_bytecode *bc
bc = yasm_bc_create_org(start, line, value)
obj = Bytecode.__new__(cls, __pass_voidp(bc, Bytecode))
__bytecode_map[PyCObject_FromVoidPtr(bc, NULL)] = obj
return obj
__org__new__ = staticmethod(__org__new__)
class Org(Bytecode):
__new__ = __org__new__
#cdef class Section:
@@ -0,0 +1,73 @@
# Python bindings for Yasm: Pyrex input file for errwarn.h
#
# Copyright (C) 2006 Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
class YasmError(Exception): pass
cdef int __error_check() except 1:
cdef yasm_error_class errclass
cdef unsigned long xrefline
cdef char *errstr, *xrefstr
# short path for the common case
if not <int>yasm_error_occurred():
return 0
# look up our preferred python error, fall back to YasmError
# Order matters here. Go from most to least specific within a class
if yasm_error_matches(YASM_ERROR_ZERO_DIVISION):
exception = ZeroDivisionError
# Enable these once there are tests that need them.
#elif yasm_error_matches(YASM_ERROR_OVERFLOW):
# exception = OverflowError
#elif yasm_error_matches(YASM_ERROR_FLOATING_POINT):
# exception = FloatingPointError
#elif yasm_error_matches(YASM_ERROR_ARITHMETIC):
# exception = ArithmeticError
#elif yasm_error_matches(YASM_ERROR_ASSERTION):
# exception = AssertionError
#elif yasm_error_matches(YASM_ERROR_VALUE):
# exception = ValueError # include notabs, notconst, toocomplex
#elif yasm_error_matches(YASM_ERROR_IO):
# exception = IOError
#elif yasm_error_matches(YASM_ERROR_NOT_IMPLEMENTED):
# exception = NotImplementedError
#elif yasm_error_matches(YASM_ERROR_TYPE):
# exception = TypeError
#elif yasm_error_matches(YASM_ERROR_SYNTAX):
# exception = SyntaxError #include parse
else:
exception = YasmError
# retrieve info (clears error)
yasm_error_fetch(&errclass, &errstr, &xrefline, &xrefstr)
if xrefline and xrefstr:
PyErr_Format(exception, "%s: %d: %s", errstr, xrefline, xrefstr)
else:
PyErr_SetString(exception, errstr)
if xrefstr: free(xrefstr)
free(errstr)
return 1
+136
View File
@@ -0,0 +1,136 @@
# Python bindings for Yasm: Pyrex input file for expr.h
#
# Copyright (C) 2006 Michael Urman, Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
cdef extern from *:
# Defined as a macro, so not automatically brought in by pyxelator
cdef yasm_expr *yasm_expr_simplify(yasm_expr *e, int calc_bc_dist)
import operator
__op = {}
for ops, operation in [
((operator.__add__, operator.add, '+'), YASM_EXPR_ADD),
((operator.__and__, operator.and_, '&'), YASM_EXPR_AND),
((operator.__div__, operator.div, '/'), YASM_EXPR_SIGNDIV),
((operator.__floordiv__, operator.floordiv, '//'), YASM_EXPR_SIGNDIV),
((operator.__ge__, operator.ge, '>='), YASM_EXPR_GE),
((operator.__gt__, operator.gt, '>'), YASM_EXPR_GT),
((operator.__inv__, operator.inv, '~'), YASM_EXPR_NOT),
((operator.__invert__, operator.invert), YASM_EXPR_NOT),
((operator.__le__, operator.le, '<='), YASM_EXPR_LE),
((operator.__lt__, operator.lt, '<'), YASM_EXPR_LT),
((operator.__mod__, operator.mod, '%'), YASM_EXPR_SIGNMOD),
((operator.__mul__, operator.mul, '*'), YASM_EXPR_MUL),
((operator.__neg__, operator.neg), YASM_EXPR_NEG),
((operator.__not__, operator.not_, 'not'), YASM_EXPR_LNOT),
((operator.__or__, operator.or_, '|'), YASM_EXPR_OR),
((operator.__sub__, operator.sub, '-'), YASM_EXPR_SUB),
((operator.__xor__, operator.xor, '^'), YASM_EXPR_XOR),
]:
for op in ops:
__op[op] = operation
del operator, op, ops, operation
cdef object __make_expression(yasm_expr *expr):
return Expression(__pass_voidp(expr, Expression))
cdef class Expression:
cdef yasm_expr *expr
def __cinit__(self, op, *args, **kwargs):
self.expr = NULL
if isinstance(op, Expression):
self.expr = yasm_expr_copy((<Expression>op).expr)
return
if PyCObject_Check(op):
self.expr = <yasm_expr *>__get_voidp(op, Expression)
return
cdef size_t numargs
cdef unsigned long line
op = __op.get(op, op)
numargs = len(args)
line = kwargs.get('line', 0)
if numargs == 0 or numargs > 2:
raise NotImplementedError
elif numargs == 2:
self.expr = yasm_expr_create(op, self.__new_item(args[0]),
self.__new_item(args[1]), line)
else:
self.expr = yasm_expr_create(op, self.__new_item(args[0]), NULL,
line)
cdef yasm_expr__item* __new_item(self, value) except NULL:
cdef yasm_expr__item *retval
if isinstance(value, Expression):
return yasm_expr_expr(yasm_expr_copy((<Expression>value).expr))
#elif isinstance(value, Symbol):
# return yasm_expr_sym((<Symbol>value).sym)
#elif isinstance(value, Register):
# return yasm_expr_reg((<Register>value).reg)
elif isinstance(value, FloatNum):
return yasm_expr_float(yasm_floatnum_copy((<FloatNum>value).flt))
elif isinstance(value, IntNum):
return yasm_expr_int(yasm_intnum_copy((<IntNum>value).intn))
else:
try:
intnum = IntNum(value)
except:
raise ValueError("Invalid item value type '%s'" % type(value))
else:
retval = yasm_expr_int((<IntNum>intnum).intn)
(<IntNum>intnum).intn = NULL
return retval
def __dealloc__(self):
if self.expr != NULL: yasm_expr_destroy(self.expr)
def simplify(self, calc_bc_dist=False):
self.expr = yasm_expr_simplify(self.expr, calc_bc_dist)
def extract_segoff(self):
cdef yasm_expr *retval
retval = yasm_expr_extract_segoff(&self.expr)
if retval == NULL:
raise ValueError("not a SEG:OFF expression")
return __make_expression(retval)
def extract_wrt(self):
cdef yasm_expr *retval
retval = yasm_expr_extract_wrt(&self.expr)
if retval == NULL:
raise ValueError("not a WRT expression")
return __make_expression(retval)
def get_intnum(self, calc_bc_dist=False):
cdef yasm_intnum *retval
retval = yasm_expr_get_intnum(&self.expr, calc_bc_dist)
if retval == NULL:
raise ValueError("not an intnum expression")
return __make_intnum(yasm_intnum_copy(retval))
@@ -0,0 +1,49 @@
# Python bindings for Yasm: Pyrex input file for floatnum.h
#
# Copyright (C) 2006 Michael Urman, Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
cdef class FloatNum:
cdef yasm_floatnum *flt
def __cinit__(self, value):
self.flt = NULL
if isinstance(value, FloatNum):
self.flt = yasm_floatnum_copy((<FloatNum>value).flt)
return
if PyCObject_Check(value): # should check Desc
self.flt = <yasm_floatnum *>PyCObject_AsVoidPtr(value)
return
if isinstance(value, float): string = str(float)
else: string = value
self.flt = yasm_floatnum_create(string)
def __dealloc__(self):
if self.flt != NULL: yasm_floatnum_destroy(self.flt)
def __neg__(self):
result = FloatNum(self)
yasm_floatnum_calc((<FloatNum>result).flt, YASM_EXPR_NEG, NULL)
return result
def __pos__(self): return self
+170
View File
@@ -0,0 +1,170 @@
# Python bindings for Yasm: Pyrex input file for intnum.h
#
# Copyright (C) 2006 Michael Urman, Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
cdef class IntNum
cdef object __intnum_op_ex(object x, yasm_expr_op op, object y):
value = __intnum_op(x, op, y)
__error_check()
return value
cdef object __intnum_op(object x, yasm_expr_op op, object y):
if isinstance(x, IntNum):
result = IntNum(x)
if y is None:
yasm_intnum_calc((<IntNum>result).intn, op, NULL)
else:
# Coerce to intnum if not already
if isinstance(y, IntNum):
rhs = y
else:
rhs = IntNum(y)
yasm_intnum_calc((<IntNum>result).intn, op, (<IntNum>rhs).intn)
return result
elif isinstance(y, IntNum):
# Reversed operation - x OP y still, just y is intnum, x isn't.
result = IntNum(x)
yasm_intnum_calc((<IntNum>result).intn, op, (<IntNum>y).intn)
return result
else:
raise NotImplementedError
cdef object __make_intnum(yasm_intnum *intn):
return IntNum(__pass_voidp(intn, IntNum))
cdef class IntNum:
cdef yasm_intnum *intn
def __cinit__(self, value, base=None):
cdef unsigned char buf[16]
self.intn = NULL
if isinstance(value, IntNum):
self.intn = yasm_intnum_copy((<IntNum>value).intn)
return
if PyCObject_Check(value):
self.intn = <yasm_intnum *>__get_voidp(value, IntNum)
return
if isinstance(value, str):
if base == 2:
self.intn = yasm_intnum_create_bin(value)
elif base == 8:
self.intn = yasm_intnum_create_oct(value)
elif base == 10 or base is None:
self.intn = yasm_intnum_create_dec(value)
elif base == 16:
self.intn = yasm_intnum_create_hex(value)
elif base == "nasm":
self.intn = yasm_intnum_create_charconst_nasm(value)
else:
raise ValueError("base must be 2, 8, 10, 16, or \"nasm\"")
elif isinstance(value, (int, long)):
_PyLong_AsByteArray(long(value), buf, 16, 1, 1)
self.intn = yasm_intnum_create_sized(buf, 1, 16, 0)
else:
raise ValueError
def __dealloc__(self):
if self.intn != NULL: yasm_intnum_destroy(self.intn)
def __long__(self):
cdef unsigned char buf[16]
yasm_intnum_get_sized(self.intn, buf, 16, 128, 0, 0, 0)
return _PyLong_FromByteArray(buf, 16, 1, 1)
def __repr__(self):
return "IntNum(%d)" % self
def __int__(self): return int(self.__long__())
def __complex__(self): return complex(self.__long__())
def __float__(self): return float(self.__long__())
def __oct__(self): return oct(int(self.__long__()))
def __hex__(self): return hex(int(self.__long__()))
def __add__(x, y): return __intnum_op(x, YASM_EXPR_ADD, y)
def __sub__(x, y): return __intnum_op(x, YASM_EXPR_SUB, y)
def __mul__(x, y): return __intnum_op(x, YASM_EXPR_MUL, y)
def __div__(x, y): return __intnum_op_ex(x, YASM_EXPR_SIGNDIV, y)
def __floordiv__(x, y): return __intnum_op_ex(x, YASM_EXPR_SIGNDIV, y)
def __mod__(x, y): return __intnum_op_ex(x, YASM_EXPR_SIGNMOD, y)
def __neg__(self): return __intnum_op(self, YASM_EXPR_NEG, None)
def __pos__(self): return self
def __abs__(self):
if yasm_intnum_sign(self.intn) >= 0: return IntNum(self)
else: return __intnum_op(self, YASM_EXPR_NEG, None)
def __nonzero__(self): return not yasm_intnum_is_zero(self.intn)
def __invert__(self): return __intnum_op(self, YASM_EXPR_NOT, None)
def __lshift__(x, y): return __intnum_op(x, YASM_EXPR_SHL, y)
def __rshift__(x, y): return __intnum_op(x, YASM_EXPR_SHR, y)
def __and__(x, y): return __intnum_op(x, YASM_EXPR_AND, y)
def __or__(x, y): return __intnum_op(x, YASM_EXPR_OR, y)
def __xor__(x, y): return __intnum_op(x, YASM_EXPR_XOR, y)
cdef object __op(self, yasm_expr_op op, object x):
if isinstance(x, IntNum):
rhs = x
else:
rhs = IntNum(x)
yasm_intnum_calc(self.intn, op, (<IntNum>rhs).intn)
return self
def __iadd__(self, x): return self.__op(YASM_EXPR_ADD, x)
def __isub__(self, x): return self.__op(YASM_EXPR_SUB, x)
def __imul__(self, x): return self.__op(YASM_EXPR_MUL, x)
def __idiv__(self, x): return self.__op(YASM_EXPR_SIGNDIV, x)
def __ifloordiv__(self, x): return self.__op(YASM_EXPR_SIGNDIV, x)
def __imod__(self, x): return self.__op(YASM_EXPR_MOD, x)
def __ilshift__(self, x): return self.__op(YASM_EXPR_SHL, x)
def __irshift__(self, x): return self.__op(YASM_EXPR_SHR, x)
def __iand__(self, x): return self.__op(YASM_EXPR_AND, x)
def __ior__(self, x): return self.__op(YASM_EXPR_OR, x)
def __ixor__(self, x): return self.__op(YASM_EXPR_XOR, x)
def __cmp__(self, x):
cdef yasm_intnum *t
t = yasm_intnum_copy(self.intn)
if isinstance(x, IntNum):
rhs = x
else:
rhs = IntNum(x)
yasm_intnum_calc(t, YASM_EXPR_SUB, (<IntNum>rhs).intn)
result = yasm_intnum_sign(t)
yasm_intnum_destroy(t)
return result
def __richcmp__(x, y, op):
cdef yasm_expr_op aop
if op == 0: aop = YASM_EXPR_LT
elif op == 1: aop = YASM_EXPR_LE
elif op == 2: aop = YASM_EXPR_EQ
elif op == 3: aop = YASM_EXPR_NE
elif op == 4: aop = YASM_EXPR_GT
elif op == 5: aop = YASM_EXPR_GE
else: raise NotImplementedError
v = __intnum_op(x, aop, y)
return bool(not yasm_intnum_is_zero((<IntNum>v).intn))
+819
View File
@@ -0,0 +1,819 @@
#!/usr/bin/env python
"""
(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
Released under GNU LGPL license.
"""
import sys
from lexer import Lexer
from parse_core import Symbols, Parser
import node as node_module
class Node(node_module.Node):
def is_typedef(self):
for x in self:
if isinstance(x,Node):
if x.is_typedef():
return 1
return 0
#def explain(self):
#l = []
#for x in self:
#if isinstance(x,Node):
#l.append(x.explain())
#else:
#l.append(str(x))
#return string.join(l," ")
##(self.__class__.__name__,string.join(l) )
def psource(self):
if hasattr(self,'lines'):
print "# "+string.join(self.lines,"\n# ")+"\n"
###################################################################
#
###################################################################
#
class BasicType(Node):
" int char short etc. "
def __init__(self,name):
Node.__init__(self,name)
class Qualifier(Node):
"""
"""
def __init__(self,name):
Node.__init__(self,name)
self.name=name
class StorageClass(Node):
"""
"""
def __init__(self,name):
Node.__init__(self,name)
self.name=name
class Typedef(StorageClass):
"""
"""
def __init__(self,s='typedef'):
Node.__init__(self,s)
#def explain(self):
#return "type"
class Ellipses(Node):
"""
"""
def __init__(self,s='...'):
Node.__init__(self,s)
class GCCBuiltin(BasicType):
"""
"""
pass
class Identifier(Node):
"""
"""
def __init__(self,name="",*items):
if name or 1:
Node.__init__(self,name,*items)
else:
Node.__init__(self)
self.name=name
class Function(Node,Parser):
"""
"""
def __init__(self,*items):
Node.__init__(self,*items)
def parse(self,lexer,symbols):
symbols = Symbols(symbols)
args = ''
#lexer.get_token()
if lexer.tok != ')':
if not lexer.tok:
self.parse_error(lexer)
#lexer.unget_token() # unget start of decl
while lexer.tok != ')':
node = ParameterDeclaration()
node.parse(lexer,symbols)
self.append( node )
if lexer.tok != ')' and lexer.tok != ',':
self.parse_error(lexer)
if lexer.tok == ',':
lexer.get_token()
lexer.get_token()
class Pointer(Node):
"""
"""
def __init__(self,*items):
Node.__init__(self,*items)
class Array(Node,Parser):
"""
"""
def __init__(self,*items):
Node.__init__(self,*items)
def parse(self,lexer,symbols):
lexer.get_token() # a number or ']'
# XX
# HACK HACK: constant c expressions can appear in here:
# eg. [ 15 * sizeof (int) - 2 * sizeof (void *) ]
# XX
toks = []
while lexer.tok != ']':
#self.append( lexer.kind )
toks.append( lexer.tok )
lexer.get_token()
child = " ".join(toks)
if child == "":
child = None
self.append( child )
lexer.get_token() # read past the ']'
class Tag(Node):
"""
"""
pass
class Compound(Node,Parser):
"Struct or Union"
def __init__(self,*items,**kw):
Node.__init__(self,*items,**kw)
def parse(self,lexer,symbols):
symbols = Symbols(symbols)
tag = "" # anonymous
if lexer.tok != '{':
tag = lexer.tok
if not ( tag[0]=='_' or tag[0].isalpha() ):
self.parse_error(lexer ,"expected tag, got '%s'"%tag )
lexer.get_token()
if tag:
self.append(Tag(tag))
else:
self.append(Tag())
self.tag = tag
if lexer.tok == '{':
fieldlist = []
lexer.get_token()
if lexer.tok != '}':
if not lexer.tok: self.parse_error(lexer)
while lexer.tok != '}':
node = StructDeclaration()
node.parse(lexer,symbols)
fieldlist.append( node )
self += fieldlist
lexer.get_token()
if self.verbose:
print "%s.__init__() #<--"%(self)
class Struct(Compound):
"""
"""
pass
class Union(Compound):
"""
"""
pass
class Enum(Node,Parser):
"""
"""
def __init__(self,*items,**kw):
Node.__init__(self,*items,**kw)
def parse(self,lexer,symbols):
tag = "" # anonymous
if lexer.tok != '{':
tag = lexer.tok
if not ( tag[0]=='_' or tag[0].isalpha() ):
self.parse_error(lexer ,"expected tag, got '%s'"%tag )
lexer.get_token()
if tag:
self.append(Tag(tag))
else:
self.append(Tag())
self.tag = tag
if lexer.tok == '{':
lexer.get_token()
if lexer.tok != '}': # XX dopey control flow
if not lexer.tok: # XX dopey control flow
self.parse_error(lexer) # XX dopey control flow
while lexer.tok != '}': # XX dopey control flow
if lexer.kind is not None:
self.expected_error(lexer ,"identifier" )
ident = Identifier(lexer.tok)
if symbols[ident[0]] is not None:
self.parse_error(lexer,"%s already defined."%ident[0])
symbols[ident[0]]=ident
self.append( ident )
lexer.get_token()
if lexer.tok == '=':
lexer.get_token()
# ConstantExpr
# XX hack hack XX
while lexer.tok!=',' and lexer.tok!='}':
lexer.get_token()
# if type( lexer.kind ) is not int:
# #self.parse_error(lexer ,"expected integer" )
# # XX hack hack XX
# while lexer.tok!=',' and lexer.tok!='}':
# lexer.get_token()
# else:
# # put initializer into the Identifier
# ident.append( lexer.kind )
# lexer.get_token()
if lexer.tok != '}':
if lexer.tok != ',':
self.expected_error(lexer,"}",",")
lexer.get_token() # ','
lexer.get_token()
if self.verbose:
print "%s.__init__() #<--"%(self)
class Declarator(Node,Parser):
"""
"""
def __init__(self,*items):
Node.__init__(self,*items)
self.ident = None
def parse(self,lexer,symbols):
#Parser.parse_enter(self,lexer)
stack = []
# read up to identifier, pushing tokens onto stack
self.ident = self.parse_identifier(lexer,symbols,stack)
self.name = ''
if self.ident is not None:
self.append( self.ident )
self.name = self.ident.name
# now read outwards from identifier
self.parse_declarator(lexer,symbols,stack)
#Parser.parse_leave(self,lexer)
def parse_identifier(self,lexer,symbols,stack):
if self.verbose:
print "%s.parse_identifier()"%self
ident = None
if lexer.tok != ';':
while lexer.tok and lexer.kind is not None:
stack.append( (lexer.tok, lexer.kind) )
lexer.get_token()
if lexer.tok:
ident = Identifier( lexer.tok )
#stack.append( (ident.name, ident) )
lexer.get_token()
if self.verbose:
print "%s.parse_identifier()=%s"%(self,repr(ident))
return ident
def parse_declarator(self,lexer,symbols,stack,level=0):
if self.verbose:
print " "*level+"%s.parse_declarator(%s) # --->"%\
(self,stack)
if lexer.tok == '[':
while lexer.tok == '[':
node = Array()
node.parse(lexer,symbols)
self.append(node)
if lexer.tok == '(':
self.parse_error(lexer ,"array of functions" )
elif lexer.tok == '(':
lexer.get_token()
node = Function()
node.parse(lexer,symbols)
self.append( node )
if lexer.tok == '(':
self.parse_error(lexer ,"function returns a function" )
if lexer.tok == '[':
self.parse_error(lexer ,"function returns an array" )
while stack:
tok, kind = stack[-1] # peek
if tok == '(':
stack.pop()
self.consume(lexer,')')
self.parse_declarator(lexer,symbols,stack,level+1)
elif tok == '*':
stack.pop()
self.append( Pointer() )
else:
tok, kind = stack.pop()
self.append( kind )
if self.verbose:
print " "*level+"%s.parse_declarator(%s) # <---"%\
(self,stack)
class AbstractDeclarator(Declarator):
""" used in ParameterDeclaration; may lack an identifier """
def parse_identifier(self,lexer,symbols,stack):
if self.verbose:
print "%s.parse_identifier()"%self
ident = None
ident = Identifier()
while 1:
if lexer.tok == ';':
self.parse_error(lexer)
if lexer.tok == ')':
break
if lexer.tok == ',':
break
if lexer.tok == '[':
break
if lexer.kind is None:
#print "%s.new identifier"%self
ident = Identifier( lexer.tok )
lexer.get_token()
#stack.append( (ident.name, ident) )
break
stack.append( (lexer.tok, lexer.kind) )
lexer.get_token()
if self.verbose:
print "%s.parse_identifier()=%s"%(self,repr(ident))
return ident
class FieldLength(Node):
"""
"""
pass
class StructDeclarator(Declarator):
"""
"""
def parse(self,lexer,symbols):
if lexer.tok != ':':
Declarator.parse(self,lexer,symbols)
if lexer.tok == ':':
lexer.get_token()
# ConstantExpr
length = int(lexer.tok)
#print "length = ",length
self.append( FieldLength(length) )
lexer.get_token()
class DeclarationSpecifiers(Node,Parser):
"""
"""
def __init__(self,*items):
Node.__init__(self,*items)
def __eq__(self,other):
" unordered (set/bag) equality "
if not isinstance(other,Node):
return 0
for i in range(len(self)):
if not self[i] in other:
return 0
for i in range(len(other)):
if not other[i] in self:
return 0
return 1
def parse(self,lexer,symbols):
self.parse_spec(lexer,symbols)
self.reverse()
def parse_spec(self,lexer,symbols):
typespec = None
while lexer.tok:
if isinstance( lexer.kind, TypeAlias ) or\
isinstance( lexer.kind, BasicType ):
if typespec is not None:
self.parse_error(lexer ,"type already specified as %s"\
%typespec )
typespec=lexer.kind
self.append( lexer.kind )
lexer.get_token()
elif isinstance( lexer.kind, Qualifier ):
self.append( lexer.kind )
lexer.get_token()
elif isinstance( lexer.kind, StorageClass ):
self.append( lexer.kind )
lexer.get_token()
elif lexer.tok=='struct':
lexer.get_token()
self.parse_struct(lexer,symbols)
break #?
elif lexer.tok=='union':
lexer.get_token()
self.parse_union(lexer,symbols)
break #?
elif lexer.tok=='enum':
lexer.get_token()
self.parse_enum(lexer,symbols)
break #?
elif lexer.kind is None:
# identifier
break
else:
break
def parse_struct(self,lexer,symbols):
if self.verbose:
print "%s.parse_struct()"%(self)
node = Struct()
node.parse(lexer,symbols)
_node = None
if node.tag:
_node = symbols.get_tag( node.tag )
if _node is not None:
if not isinstance( _node, Struct ):
self.parse_error(lexer,"tag defined as wrong kind")
if len(node)>1:
if len(_node)>1:
self.parse_error(lexer,"tag already defined as %s"%_node)
#symbols.set_tag( node.tag, node )
#else:
# refer to the previously defined struct
##node = _node
#node = _node.clone()
if 0:
# refer to the previously defined struct
if len(node)==1:
_node = symbols.deep_get_tag( node.tag )
if _node is not None:
node=_node
# But what about any future reference to the struct ?
if node.tag:
symbols.set_tag( node.tag, node )
self.append( node )
def parse_union(self,lexer,symbols):
if self.verbose:
print "%s.parse_union(%s)"%(self,node)
node = Union()
node.parse(lexer,symbols)
_node = None
if node.tag:
_node = symbols.get_tag( node.tag )
if _node is not None:
if not isinstance( _node, Union ):
self.parse_error(lexer,"tag %s defined as wrong kind"%repr(node.tag))
if len(node)>1:
if len(_node)>1:
self.parse_error(lexer,"tag already defined as %s"%_node)
#symbols.set_tag( node.tag, node )
#else:
#node = _node
#if len(node)==1:
#_node = symbols.deep_get_tag( node.tag )
#if _node is not None:
#node=_node
if node.tag:
symbols.set_tag( node.tag, node )
self.append( node )
def parse_enum(self,lexer,symbols):
if self.verbose:
print "%s.parse_enum(%s)"%(self,node)
node = Enum()
node.parse(lexer,symbols)
_node = None
if node.tag:
_node = symbols.get_tag( node.tag )
if _node is not None:
if not isinstance( _node, Enum ):
self.parse_error(lexer,"tag defined as wrong kind")
if len(node)>1:
if len(_node)>1:
self.parse_error(lexer,"tag already defined as %s"%_node)
#symbols.set_tag( node.tag, node )
#else:
#node = _node
#if len(node)==1:
#_node = symbols.deep_get_tag( node.tag )
#if _node is not None:
#node=_node
if node.tag:
symbols.set_tag( node.tag, node )
self.append( node )
def is_typedef(self):
return self.find(Typedef) is not None
def needs_declarator(self):
for node in self:
if isinstance( node, Struct ):
return False
if isinstance( node, Enum ):
return False
if isinstance( node, Union ):
return False
return True
class TypeSpecifiers(DeclarationSpecifiers):
" used in ParameterDeclaration "
def parse_spec(self,lexer,symbols):
typespec = None
while lexer.tok:
if isinstance( lexer.kind, TypeAlias ) or\
isinstance( lexer.kind, BasicType ):
if typespec is not None:
self.parse_error(lexer ,"type already specified as %s"\
%typespec )
typespec=lexer.kind
self.append( lexer.kind )
lexer.get_token()
elif isinstance( lexer.kind, Qualifier ):
self.append( lexer.kind )
lexer.get_token()
elif isinstance( lexer.kind, StorageClass ):
self.parse_error(lexer ,"'%s' cannot appear here"%lexer.tok )
elif lexer.tok=='struct':
lexer.get_token()
self.parse_struct(lexer,symbols)
break #?
elif lexer.tok=='union':
lexer.get_token()
self.parse_union(lexer,symbols)
break #?
elif lexer.tok=='enum':
lexer.get_token()
self.parse_enum(lexer,symbols)
break #?
elif lexer.kind is None:
# identifier
break
else:
break
class Initializer(Node,Parser):
"""
"""
def __init__(self,*items):
Node.__init__(self,*items)
def parse(self,lexer,symbols):
self.parse_error(lexer,"not implemented")
class TypeAlias(Node):
" typedefed things "
def __init__(self,name,decl=None):
Node.__init__(self,name)#,decl)
self.name=name
self.decl=decl
class Declaration(Node,Parser):
"""
"""
def __init__(self,*items):
Node.__init__(self,*items)
#self.acted=False
def parse(self,lexer,symbols):
if not lexer.tok:
return
Parser.parse_enter(self,lexer)
declspec = DeclarationSpecifiers()
declspec.parse(lexer,symbols)
if len(declspec)==0:
if lexer.tok == ';':
lexer.get_token()
# empty declaration...
return
self.parse_error(lexer,
"expected specifiers, got '%s'"%lexer.tok )
self.append(declspec)
while 1:
decl = Declarator()
decl.parse(lexer,symbols)
if len(decl)==0:
if declspec.needs_declarator():
self.parse_error(lexer,
"expected declarator, got '%s'"%lexer.tok )
self.append(decl)
ident = decl.ident
if ident is not None:
#if len(ident):
# install symbol
node = symbols[ident[0]]
if node is not None:
# we allow functions to be defined (as same) again
#print node.deepstr(),'\n', self.deepstr()
_node = node.clone()
_node.delete(Identifier)
_self = self.clone()
_self.delete(Identifier)
if _node != _self:
self.parse_error(lexer,
"\n%s\n already defined as \n%s\n"%\
(self.deepstr(),node.deepstr()))
else:
if self.is_typedef():
#lexer.mktypedef( ident[0], self )
tp = TypeAlias(ident[0],decl)
lexer.mktypedef( ident[0], tp )
else:
symbols[ident[0]] = self
if lexer.tok == '=':
# parse initializer
lexer.get_token()
init = Initializer()
init.parse(lexer,symbols)
ident.append( init ) # as in Enum
#else: struct, union or enum
if lexer.tok == ';':
# no more declarators
break
if lexer.tok == '{':
# ! ahhh, function body !!!
# sys.stderr.write(
# "WARNING: function body found at line %s\n"%lexer.lno )
bcount = 1
while bcount:
lexer.get_brace_token()
if lexer.tok == '}':
bcount -= 1
if lexer.tok == '{':
bcount += 1
lexer.get_token()
Parser.parse_leave(self,lexer)
return
self.consume(lexer,',')
self.consume(lexer,';')
Parser.parse_leave(self,lexer)
def is_typedef(self):
spec=self[0]
assert isinstance(spec,DeclarationSpecifiers), self.deepstr()
return spec.is_typedef()
class ParameterDeclaration(Declaration):
"""
"""
def parse(self,lexer,symbols):
typespec = TypeSpecifiers()
typespec.parse(lexer,symbols)
self.append(typespec)
decl = AbstractDeclarator()
decl.parse(lexer,symbols)
self.append(decl)
ident = decl.ident
if ident is not None and ident[0]:
node = symbols[ident[0]]
if node is not None:
self.parse_error(lexer,
"%s already defined as %s"%(ident,node))
else:
symbols[ident[0]] = self
class StructDeclaration(Declaration):
"""
"""
def parse(self,lexer,symbols):
if not lexer.tok:
return
declspec = DeclarationSpecifiers()
declspec.parse(lexer,symbols)
self.append(declspec)
if len(declspec)==0:
if lexer.tok == ';':
lexer.get_token()
# empty declaration...
return
self.parse_error(lexer,
"expected specifiers, got '%s'"%lexer.tok )
while 1:
decl = StructDeclarator()
decl.parse(lexer,symbols)
if len(decl)==0:
self.parse_error(lexer,
"expected declarator, got '%s'"%lexer.tok )
self.append(decl)
ident = decl.ident
if ident is not None:
node = symbols[ident[0]]
if node is not None:
self.parse_error(lexer ,
"%s already defined as %s"%(ident,node))
else:
if declspec.is_typedef():
self.parse_error(lexer,"typedef in struct or union")
else:
symbols[ident[0]] = self
if lexer.tok == ';':
break
self.consume(lexer,',')
self.consume(lexer,';')
class TransUnit(Node,Parser):
"""
"""
def __init__(self,*items,**kw):
Node.__init__(self,*items,**kw)
def parse(self,s,verbose=0):
self.symbols = Symbols()
self.lexer = Lexer(s,verbose=verbose) #,host=__module__)
node = None
while self.lexer.tok:
node=Declaration()
node.parse(self.lexer,self.symbols)
#sys.stderr.write( "# line %s\n"%self.lexer.lno )
if node:
self.append(node)
#node.psource()
#print node.deepstr(),'\n'
#node.act()
def strip(self,files):
" leave only the declarations from <files> "
i=0
while i<len(self):
if self[i].file in files:
i=i+1
else:
self.pop(i)
def strip_filter(self,cb):
" leave only the declarations such that cb(file) "
i=0
while i<len(self):
if cb(self[i].file):
i=i+1
else:
self.pop(i)
def assert_no_dups(self):
check={}
for node in self.nodes():
assert not check.has_key(id(node))
check[id(node)]=1
try:
import NoModule
import psyco
from psyco.classes import *
except ImportError:
class _psyco:
def jit(self): pass
def bind(self, f): pass
def proxy(self, f): return f
psyco = _psyco()
psyco.bind( Lexer.get_token )
psyco.bind( Node )
def run0():
verbose = 0
if not sys.argv[1:]:
s = sys.stdin.read()
if sys.argv[1:]:
s = sys.argv[1]
#if sys.argv[2:]:
#verbose = int(sys.argv[2])
if 0:
import profile
profile.run('TransUnit(s)','prof.out')
import pstats
p=pstats.Stats('prof.out')
p.strip_dirs().sort_stats(-1).print_stats()
else:
node = TransUnit(verbose = 1 )
node.parse(s)
node.act(1,1,1)
def run1():
cstr = "char *(*)() ,"
node = AbstractDeclarator()
node.parse( Lexer(cstr,True), Symbols() )
print node.deepstr()
if __name__=="__main__":
pass
+530
View File
@@ -0,0 +1,530 @@
#!/usr/bin/env python
""" genpyx.py - parse c declarations
(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
Released under GNU LGPL license.
version 0.xx
This is a module of mixin classes for ir.py .
Towards the end of ir.py our global class definitions
are remapped to point to the class definitions in ir.py .
So, for example, when we refer to Node we get ir.Node .
"""
import sys
from datetime import datetime
# XX use this Context class instead of all those kw dicts !! XX
class Context(object):
" just a record (struct) "
def __init__( self, **kw ):
for key, value in kw.items():
setattr( self, key, value )
def __getattr__( self, name ):
return None # ?
def __getitem__( self, name ):
return getattr(self, name)
class OStream(object):
def __init__( self, filename=None ):
self.filename = filename
self.tokens = []
self._indent = 0
def put( self, token="" ):
assert type(token) is str
self.tokens.append( token )
def startln( self, token="" ):
assert type(token) is str
self.tokens.append( ' '*self._indent + token )
def putln( self, ln="" ):
assert type(ln) is str
self.tokens.append( ' '*self._indent + ln + '\n')
def endln( self, token="" ):
assert type(token) is str
self.tokens.append( token + '\n')
def indent( self ):
self._indent += 1
def dedent( self ):
self._indent -= 1
assert self._indent >= 0, self._indent
def join( self ):
return ''.join( self.tokens )
def close( self ):
s = ''.join( self.tokens )
f = open( self.filename, 'w' )
f.write(s)
#
###############################################################################
#
class Node(object):
"""
tree structure
"""
_unique_id = 0
def get_unique_id(cls):
Node._unique_id += 1
return Node._unique_id
get_unique_id = classmethod(get_unique_id)
# XX toks: use a tree of tokens: a list that can be push'ed and pop'ed XX
def pyxstr(self,toks=None,indent=0,**kw):
"""
Build a list of tokens; return the joined tokens string
"""
if toks is None:
toks = []
for x in self:
if isinstance(x,Node):
x.pyxstr(toks, indent, **kw)
else:
toks.insert(0,str(x)+' ')
s = ''.join(toks)
return s
#
#################################################
class Named(object):
"has a .name property"
pass
class BasicType(object):
"float double void char int"
pass
class Qualifier(object):
"register signed unsigned short long const volatile inline"
def pyxstr(self,toks=None,indent=0,**kw):
if toks is None:
toks = []
x = self[0]
if x not in ( 'const','volatile','inline','register'): # ignore these
toks.insert(0,str(x)+' ')
s = ''.join(toks)
return s
class StorageClass(object):
"extern static auto"
def pyxstr(self,toks=None,indent=0,**kw):
return ""
class Ellipses(object):
"..."
pass
class GCCBuiltin(BasicType):
"things with __builtin prefix"
pass
class Identifier(object):
"""
"""
def pyxstr(self,toks=None,indent=0,**kw):
if toks is None:
toks=[]
if self.name:
toks.append( self.name )
return " ".join(toks)
class TypeAlias(object):
"""
typedefed things, eg. size_t
"""
def pyxstr(self,toks=None,indent=0,cprefix="",**kw):
if toks is None:
toks = []
for x in self:
if isinstance(x,Node):
x.pyxstr(toks, indent, cprefix=cprefix, **kw)
else:
s = str(x)+' '
if cprefix:
s = cprefix+s
toks.insert(0,s)
s = ''.join(toks)
return s
class Function(object):
"""
"""
def pyxstr(self,toks,indent=0,**kw):
#print '%s.pyxstr(%s)'%(self,toks)
_toks=[]
assert len(self)
i=0
while isinstance(self[i],Declarator):
if not self[i].is_void():
_toks.append( self[i].pyxstr(indent=indent, **kw) )
i=i+1
toks.append( '(%s)'% ', '.join(_toks) )
while i<len(self):
self[i].pyxstr(toks, indent=indent, **kw)
i=i+1
return " ".join(toks)
class Pointer(object):
"""
"""
def pyxstr(self,toks,indent=0,**kw):
assert len(self)
node=self[0]
toks.insert(0,'*')
if isinstance(node,Function):
toks.insert(0,'(')
toks.append(')')
elif isinstance(node,Array):
toks.insert(0,'(')
toks.append(')')
return Node.pyxstr(self,toks,indent, **kw)
class Array(object):
"""
"""
def pyxstr(self,toks,indent=0,**kw):
if self.size is None:
toks.append('[]')
else:
try:
int(self.size)
toks.append('[%s]'%self.size)
except:
toks.append('[]')
return Node( *self[:-1] ).pyxstr( toks,indent, **kw )
class Tag(object):
" the tag of a Struct, Union or Enum "
pass
class Taged(object):
"Struct, Union or Enum "
pass
class Compound(Taged):
"Struct or Union"
def pyxstr(self,_toks=None,indent=0,cprefix="",shadow_name=True,**kw):
if _toks is None:
_toks=[]
names = kw.get('names',{})
kw['names'] = names
tag_lookup = kw.get('tag_lookup')
if self.tag:
tag=self.tag.name
else:
tag = ''
if isinstance(self,Struct):
descr = 'struct'
elif isinstance(self,Union):
descr = 'union'
_node = names.get(self.tag.name,None)
if ( _node is not None and _node.has_members() ) or \
( _node is not None and not self.has_members() ):
descr = '' # i am not defining myself here
#print "Compound.pyxstr", tag
#print self.deepstr()
if descr:
if cprefix and shadow_name:
tag = '%s%s "%s"'%(cprefix,tag,tag)
elif cprefix:
tag = cprefix+tag
toks = [ descr+' '+tag ] # struct foo
if self.has_members():
toks.append(':\n')
for decl in self[1:]: # XX self.members
toks.append( decl.pyxstr(indent=indent+1, cprefix=cprefix, shadow_name=shadow_name, **kw)+"\n" ) # shadow_name = False ?
#elif not tag_lookup.get( self.tag.name, self ).has_members():
# define empty struct here, it's the best we're gonna get
#pass
else:
if cprefix: # and shadow_name:
tag = cprefix+tag
toks = [ ' '+tag+' ' ] # foo
while toks:
_toks.insert( 0, toks.pop() )
return "".join( _toks )
class Struct(Compound):
"""
"""
pass
class Union(Compound):
"""
"""
pass
class Enum(Taged):
"""
"""
def pyxstr(self,_toks=None,indent=0,cprefix="",shadow_name=True,**kw):
if _toks is None:
_toks=[]
names = kw.get('names',{})
kw['names'] = names
if self.tag:
tag=self.tag.name
else:
tag = ''
_node = names.get(self.tag.name,None)
if ( _node is not None and _node.has_members() ) or \
( _node is not None and not self.has_members() ):
descr = '' # i am not defining myself here
else:
descr = 'enum'
if descr:
#if not names.has_key(self.tag.name):
toks = [ descr+' '+tag ] # enum foo
toks.append(':\n')
idents = [ ident for ident in self.members if ident.name not in names ]
for ident in idents:
if cprefix and shadow_name:
ident = ident.clone()
ident.name = '%s%s "%s"' % ( cprefix, ident.name, ident.name )
#else: assert 0
toks.append( ' '+' '*indent + ident.pyxstr(**kw)+"\n" )
names[ ident.name ] = ident
if not idents:
# empty enum def'n !
#assert 0 # should be handled by parents...
toks.append( ' '+' '*indent + "pass\n" )
else:
toks = [ ' '+tag+' ' ] # foo
while toks:
_toks.insert( 0, toks.pop() )
return "".join( _toks )
class Declarator(object):
def is_pyxnative( self ):
# pyrex handles char* too
# but i don't know if we should make this the default
# sometimes we want to send a NULL, so ... XX
self = self.cbasetype() # WARNING: cbasetype may be cached
if self.is_void():
return False
if self.is_primative():
return True
if self.enum:
return True
#pointer = None
#if self.pointer:
#pointer = self.pointer
#elif self.array:
#pointer = self.array
#if pointer and pointer.spec:
#spec = pointer.spec
#if BasicType("char") in spec and not Qualifier("unsigned") in spec:
# char*, const char*
##print self.deepstr()
#return True
return False
def _pyxstr( self, toks, indent, cprefix, use_cdef, shadow_name, **kw ):
" this is the common part of pyxstr that gets called from both Declarator and Typedef "
names = kw.get('names',{}) # what names have been defined ?
kw['names']=names
for node in self.nodes(): # depth-first
if isinstance(node,Taged):
#print "Declarator.pyxstr", node.cstr()
if not node.tag.name:
node.tag.name = "_anon_%s" % Node.get_unique_id()
_node = names.get(node.tag.name,None)
#tag_lookup = kw.get('tag_lookup')
#other = tag_lookup.get(node.tag.name, node)
#if ((_node is None and (not isinstance(other,Compound) or not other.has_members()))
# or node.has_members()):
if _node is None or node.has_members():
# either i am not defined at all, or this is my _real_ definition
# emit def'n of this node
#if isinstance(self,Typedef):
#toks.append( ' '*indent + 'ctypedef ' + node.pyxstr(indent=indent, cprefix=cprefix, shadow_name=shadow_name, **kw).strip() )
#else:
toks.append( ' '*indent + 'cdef ' + node.pyxstr(indent=indent, cprefix=cprefix, shadow_name=shadow_name, **kw).strip() )
names[ node.tag.name ] = node
elif isinstance(node,GCCBuiltin) and node[0] not in names:
#toks.append( ' '*indent + 'ctypedef long ' + node.pyxstr(indent=indent, **kw).strip() + ' # XX ??' ) # XX ??
toks.append( ' '*indent + 'struct __unknown_builtin ' )
toks.append( ' '*indent + 'ctypedef __unknown_builtin ' + node.pyxstr(indent=indent, **kw).strip() )
names[ node[0] ] = node
for idx, child in enumerate(node):
if type(child)==Array and not child.has_size():
# mutate this mystery array into a pointer XX method: Array.to_pointer()
node[idx] = Pointer()
node[idx].init_from( child ) # warning: shallow init
node[idx].pop() # pop the size element
def pyxstr(self,toks=None,indent=0,cprefix="",use_cdef=True,shadow_name=True,**kw):
" note: i do not check if my name is already in 'names' "
self = self.clone() # <----- NOTE
toks=[]
names = kw.get('names',{}) # what names have been defined ?
kw['names']=names
self._pyxstr( toks, indent, cprefix, use_cdef, shadow_name, **kw )
if self.name and not names.has_key( self.name ):
names[ self.name ] = self
if self.identifier is not None:
comment = ""
if self.name in python_kws:
comment = "#"
if cprefix and use_cdef and shadow_name:
# When we are defining this guy, we refer to it using the pyrex shadow syntax.
self.name = '%s%s "%s" ' % ( cprefix, self.name, self.name )
cdef = 'cdef '
if not use_cdef: cdef = '' # sometimes we don't want the cdef (eg. in a cast)
# this may need shadow_name=False:
toks.append( ' '*indent + comment + cdef + Node.pyxstr(self,indent=indent, cprefix=cprefix, **kw).strip() ) # + "(cprefix=%s)"%cprefix)
#else: i am just a struct def (so i already did that) # huh ?? XX bad comment
return ' \n'.join(toks)
def pyxsym(self, ostream, names=None, tag_lookup=None, cprefix="", modname=None, cobjects=None):
assert self.name is not None, self.deepstr()
ostream.putln( '# ' + self.cstr() )
# This cdef is no good: it does not expose a python object
# and we can't reliably set a global var
#ostream.putln( 'cdef %s %s' % ( self.pyx_adaptor_decl(cobjects), self.name ) ) # _CObject
#ostream.putln( '%s = %s()' % (self.name, self.pyx_adaptor_name(cobjects)) )
#ostream.putln( '%s.p = <void*>&%s' % (self.name, cprefix+self.name) )
## expose a python object:
#ostream.putln( '%s.%s = %s' % (modname,self.name, self.name) )
ostream.putln( '%s = %s( addr = <long>&%s )' % (self.name, self.pyx_adaptor_name(cobjects), cprefix+self.name) )
return ostream
class Typedef(Declarator):
def pyxstr(self,toks=None,indent=0,cprefix="",use_cdef=True,shadow_name=True,**kw): # shadow_name=True
" warning: i do not check if my name is already in 'names' "
assert shadow_name == True
self = self.clone() # <----- NOTE
toks=[]
names = kw.get('names',{}) # what names have been defined ?
kw['names']=names
#if self.tagged and not self.tagged.tag.name:
## "typedef struct {...} foo;" => "typedef struct foo {...} foo;"
## (to be emitted in the node loop below, and suppressed in the final toks.append)
#self.tagged.tag = Tag( self.name ) # this is how pyrex does it: tag.name == self.name
# XX that doesn't work (the resulting c fails to compile) XX
self._pyxstr( toks, indent, cprefix, use_cdef, shadow_name, **kw )
#print self.deepstr()
if self.name and not names.has_key( self.name ):
names[ self.name ] = self
if not (self.tagged and self.name == self.tagged.tag.name):
comment = ""
if self.name in python_kws:
comment = "#"
#if cprefix:
# self.name = '%s%s "%s" ' % ( cprefix, self.name, self.name ) # XX pyrex can't do this
if cprefix: # shadow_name=True
# My c-name gets this prefix. See also TypeAlias.pyxstr(): it also prepends the cprefix.
self.name = '%s%s "%s" ' % ( cprefix, self.name, self.name )
toks.append( ' '*indent + comment + 'ctypedef ' + Node.pyxstr(self,indent=indent, cprefix=cprefix, **kw).strip() )
return ' \n'.join(toks)
class AbstractDeclarator(Declarator):
""" used in Function; may lack an identifier """
def pyxstr(self,toks=None,indent=0,**kw):
if self.name in python_kws:
# Would be better to do this in __init__, but our subclass doesn't call our __init__.
self.name = '_' + self.name
#return ' '*indent + Node.pyxstr(self,toks,indent, **kw).strip()
return Node.pyxstr(self,toks,indent, **kw).strip()
class FieldLength(object):
"""
"""
def pyxstr(self,toks,indent,**kw):
pass
class StructDeclarator(Declarator): # also used in Union
"""
"""
def pyxstr(self,toks=None,indent=0,**kw):
comment = ""
if self.name in python_kws:
comment = "#"
return ' '*indent + comment + Node.pyxstr(self,toks,indent, **kw).strip()
class DeclarationSpecifiers(object):
"""
"""
pass
class TypeSpecifiers(DeclarationSpecifiers):
"""
"""
pass
class Initializer(object):
"""
"""
pass
class Declaration(object):
"""
"""
pass
class ParameterDeclaration(Declaration):
"""
"""
pass
class StructDeclaration(Declaration):
"""
"""
pass
class TransUnit(object):
"""
Top level node.
"""
def pyx_decls(self, filenames, modname, macros = {}, names = {}, func_cb=None, cprefix="", **kw):
# PART 1: emit extern declarations
ostream = OStream()
now = datetime.today()
ostream.putln( now.strftime('# Code generated by pyxelator on %x at %X') + '\n' )
ostream.putln("# PART 1: extern declarations")
for filename in filenames:
ostream.putln( 'cdef extern from "%s":\n pass\n' % filename )
ostream.putln( 'cdef extern from *:' )
file = None # current file
for node in self:
ostream.putln('')
ostream.putln(' # ' + node.cstr() )
assert node.marked
comment = False
if node.name and node.name in names:
comment = True # redeclaration
#ostream.putln( node.deepstr( comment=True ) )
s = node.pyxstr(indent=1, names=names, tag_lookup = self.tag_lookup, cprefix=cprefix, **kw)
if s.split():
if comment:
s = "#"+s.replace( '\n', '\n#' ) + " # redeclaration "
if node.file != file:
file = node.file
#ostream.putln( 'cdef extern from "%s":' % file )
ostream.putln( ' # "%s"' % file )
ostream.putln( s )
ostream.putln('\n')
#s = '\n'.join(toks)
return ostream.join()
# XX warn when we find a python keyword XX
python_kws = """
break continue del def except exec finally pass print raise
return try global assert lambda yield
for while if elif else and in is not or import from """.split()
python_kws = dict( zip( python_kws, (None,)*len(python_kws) ) )
File diff suppressed because it is too large Load Diff
+248
View File
@@ -0,0 +1,248 @@
#!/usr/bin/env python
""" cdecl.py - parse c declarations
(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
Released under GNU LGPL license.
version 0.xx
"""
import sys
import string
import types
import copy
#from cparse import BasicType, Qualifier, StorageClass, Typedef, Ellipses, GCCBuiltin
#from cparse import *
import cparse as host
class LexError(Exception):
pass
class Lexer(object):
def __init__(self,s="",verbose=0,**kw):
self.verbose = verbose
self.lookup = {} # a map for keywords and typedefs
for t in \
"float double void char int".split():
self.lookup[t] = host.BasicType( t )
for t in \
"register signed unsigned short long const volatile inline".split(): # inline here ???
self.lookup[t] = host.Qualifier( t )
for t in "extern static auto".split():
self.lookup[t] = host.StorageClass( t )
self.lookup['typedef'] = host.Typedef()
#self.lookup['__inline__'] = host.GCCBuiltin('__inline__')
#self.lookup['__extension__'] = host.Qualifier('__extension__')
self.lookup['...'] = host.Ellipses()
if s:
self.lex(s)
for key in kw.keys():
self.__dict__[key] = kw[key]
def lex(self,s):
self.stack = None
self.lines = s.splitlines()
self.set_state("","",0,0)
self.so_file = ""
self._newline()
self.get_token() # start
def mktypedef(self,tok,node):
if self.verbose:
print "%s.mktypedef(%s,%s)"%(self,tok,node)
self.lookup[ tok ] = node
def rmtypedef(self,tok):
" used in round trip testing "
# print "# rmtypedef(%s)"%tok
assert isinstance( self.lookup[ tok ], host.Node ) # existance
del self.lookup[ tok ]
def _get_kind(self,tok):
#print '_get_kind(%s)'%tok,self.lookup
try:
return self.lookup[tok]
#return self.lookup[tok].clone()
except KeyError:
if tok.startswith("__builtin"):
node = host.GCCBuiltin(tok)
self.lookup[tok] = node
return node
#elif tok in ( "__extension__", ):
#node = GCCBuiltin(tok)
#self.lookup[tok] = node
#return node
return None
def _newline(self):
while self.lno < len(self.lines):
line = self.lines[self.lno]
if not line or line[0] != "#":
break
l = line.split('"')
assert len(l)>=2
self.so_file = l[1]
#self.so_lno = int( l[0].split()[1] )
#sys.stderr.write("# %s %s: %s\n"%(so_lno,so_file,l))
self.lno+=1
def get_brace_token( self ):
self.push_state()
ident_chars0 = string.letters+"_"
ident_chars1 = string.letters+string.digits+"_"
tok, kind = "", ""
while self.lno < len(self.lines):
s = self.lines[self.lno]
i=self.col
while i < len(s):
if s[i] not in '{}':
i=i+1
continue
else:
tok = s[i]
kind = tok
self.col = i+1
break
# keep moving
#sys.stderr.write( "lexer ignoring '%s'\n"%s[i] )
i=i+1
if i==len(s):
# nothing found
assert tok == ""
self.col=0
self.lno+=1
self._newline()
else:
assert tok
break
self.set_state(tok,kind,self.lno,self.col)
def get_token(self):
self.push_state()
ident_chars0 = string.letters+"_"
ident_chars1 = string.letters+string.digits+"_"
tok, kind = "", ""
while self.lno < len(self.lines):
s = self.lines[self.lno]
i=self.col
while i < len(s):
if s[i].isspace():
i=i+1
continue
#if s[i] in ident_chars0:
if s[i].isalpha() or s[i]=='_':
# identifier
j=i+1
while j<len(s):
if s[j] in ident_chars1:
j=j+1
else:
break
tok = s[i:j]
self.col = j
kind = self._get_kind(tok)
break
if s[i].isdigit() or \
(i+1<len(s) and s[i] in '+-.' and s[i+1].isdigit()):
# number literal
is_float = s[i]=='.'
is_hex = s[i:i+2]=='0x'
if is_hex:
i=i+2
assert s[i].isdigit() or s[i] in "abcdefABCDEF", self.err_string()
j=i+1
while j<len(s):
#print "lex ",repr(s[i]),is_float
if s[j].isdigit() or (is_hex and s[j] in "abcdefABCDEF"):
j=j+1
elif s[j]=='.' and not is_float:
assert not is_hex
j=j+1
is_float=1
else:
break
tok = s[i:j]
self.col = j
if is_float:
kind = float(tok)
elif is_hex:
kind = int(tok,16)
else:
kind = int(tok)
break
if s[i:i+3]=='...':
# ellipses
#sys.stderr.write( "ELLIPSES "+str(self.get_state()) )
tok = s[i:i+3]
kind = self._get_kind(tok)
self.col = i+3
break
if s[i] in '*/{}()[]:;,=+-~.<>|&':
tok = s[i]
kind = tok
self.col = i+1
break
if s[i] == "'":
j = i+2
while j<len(s) and s[j]!="'":
j+=1
if j==len(s):
raise LexError( self.err_string() + "unterminated char constant" )
tok = s[i:j+1]
self.col = j+1
kind = s[i:j+1]
break
# keep moving
#sys.stderr.write( "lexer ignoring '%s'\n"%s[i] )
sys.stderr.write( "lexer ignoring '%s' lno=%d\n"%(s[i],self.lno+1) )
i=i+1
# end while i < len(s)
if i==len(s):
# nothing found, go to next line
assert tok == ""
self.col=0
self.lno+=1
self._newline()
else:
# we got one
assert tok
break
# end while self.lno < len(self.lines):
self.set_state(tok,kind,self.lno,self.col)
def err_string(self):
"Return helpful error string :)"
return self.lines[self.lno]+"\n"+" "*self.col+"^\n"
def push_state(self):
self.stack = self.get_state() # a short stack :)
#self.stack.push( self.get_state() )
def unget_token(self):
assert self.stack is not None
self.set_state(*self.stack)
self.stack = None
def set_state(self,tok,kind,lno,col):
if self.verbose:
print "tok,kind,lno,col = ",(tok,kind,lno,col)
self.tok = tok
self.kind = kind
self.lno = lno # line
self.col = col # column
def get_state(self):
return self.tok,self.kind,self.lno,self.col
def get_file(self):
return self.so_file
###################################################################
#
###################################################################
#
+301
View File
@@ -0,0 +1,301 @@
#!/usr/bin/env python
""" cdecl.py - parse c declarations
(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
Released under GNU LGPL license.
version 0.xx
"""
import string
class Node(list):
" A node in a parse tree "
def __init__(self,*items,**kw):
list.__init__( self, items )
self.lock1 = 0 # these two should be properties (simplifies serializing)
self.lock2 = 0
self.verbose = 0
for key in kw.keys():
self.__dict__[key] = kw[key]
def __str__(self):
attrs = []
for item in self:
if isinstance(item,Node):
attrs.append( str(item) )
else:
attrs.append( repr(item) )
attrs = ','.join(attrs)
return "%s(%s)"%(self.__class__.__name__,attrs)
def safe_repr( self, tank ):
tank[ str(self) ] = None
attrs = []
for item in self:
if isinstance(item,Node):
attrs.append( item.safe_repr(tank) ) # can we use repr here ?
else:
attrs.append( repr(item) )
# this is the dangerous bit:
for key, val in self.__dict__.items():
if isinstance(val,Node):
if str(val) not in tank:
attrs.append( '%s=%s'%(key,val.safe_repr(tank)) )
else:
attrs.append( '%s=%s'%(key,repr(val)) )
attrs = ','.join(attrs)
return "%s(%s)"%(self.__class__.__name__,attrs)
def __repr__(self):
#attrs = ','.join( [repr(item) for item in self] + \
# [ '%s=%s'%(key,repr(val)) for key,val in self.__dict__.items() ] )
#return "%s%s"%(self.__class__.__name__,tuple(attrs))
return self.safe_repr({})
def __eq__(self,other):
if not isinstance(other,Node):
return 0
if len(self)!=len(other):
return 0
for i in range(len(self)):
if not self[i]==other[i]:
return 0
return 1
def __ne__(self,other):
return not self==other
def filter(self,cls):
return [x for x in self if isinstance(x,cls)]
#return filter( lambda x:isinstance(x,cls), self )
def deepfilter(self,cls):
" bottom-up "
return [x for x in self.nodes() if isinstance(x,cls)]
def find(self,cls):
for x in self:
if isinstance(x,cls):
return x
return None
def deepfind(self,cls):
" bottom-up isinstance search "
for x in self:
if isinstance(x,Node):
if isinstance(x,cls):
return x
node = x.deepfind(cls)
if node is not None:
return node
if isinstance(self,cls):
return self
return None
def leaves(self):
for i in self:
if isinstance( i, Node ):
for j in i.leaves():
yield j
else:
yield i
def nodes(self):
" bottom-up iteration "
for i in self:
if isinstance( i, Node ):
for j in i.nodes():
yield j
yield self
def deeplen(self):
i=0
if not self.lock2:
self.lock2=1
for item in self:
i+=1
if isinstance(item,Node):
i+=item.deeplen()
self.lock2=0
else:
i+=1
return i
def deepstr(self,level=0,comment=False,nl='\n',indent=' '):
if self.deeplen() < 4:
nl = ""; indent = ""
#else:
#nl="\n"; indent = " "
s = []
if not self.lock1:
self.lock1=1
for item in self:
if isinstance(item,Node):
s.append( indent*(level+1)+item.deepstr(level+1,False,nl,indent) )
else:
s.append( indent*(level+1)+repr(item) )
self.lock1=0
else:
for item in self:
if isinstance(item,Node):
s.append( indent*(level+1)+"<recursion...>" )
else:
s.append( indent*(level+1)+"%s"%repr(item) )
s = "%s(%s)"%(self.__class__.__name__,nl+string.join(s,","+nl))
if comment:
s = '#' + s.replace('\n','\n#')
return s
def clone(self):
items = []
for item in self:
if isinstance(item,Node):
item = item.clone()
items.append(item)
# we skip any attributes...
return self.__class__(*items)
def fastclone(self):
# XX is it faster ???
#print "clone"
nodes = [self]
idxs = [0]
itemss = [ [] ]
while nodes:
assert len(nodes)==len(idxs)==len(itemss)
node = nodes[-1]
items = itemss[-1]
assert idxs[-1] == len(items)
while idxs[-1]==len(node):
# pop
_node = node.__class__( *items )
_node.__dict__.update( node.__dict__ )
nodes.pop(-1)
idxs.pop(-1)
itemss.pop(-1)
if not nodes:
#for node0 in self.nodes():
#for node1 in _node.nodes():
#assert node0 is not node1
#assert _node == self
return _node # Done !!
node = nodes[-1]
items = itemss[-1]
items.append(_node) # set
idxs[-1] += 1
assert idxs[-1] == len(items)
#assert idxs[-1] < len(node), str( (node,nodes,idxs,itemss) )
_node = node[ idxs[-1] ]
# while idxs[-1]<len(node):
if isinstance(_node,Node):
# push
nodes.append( _node )
idxs.append( 0 )
itemss.append( [] )
else:
# next
items.append(_node)
idxs[-1] += 1
assert idxs[-1] == len(items)
def expose(self,cls):
' expose children of any <cls> instance '
# children first
for x in self:
if isinstance(x,Node):
x.expose(cls)
# now the tricky bit
i=0
while i < len(self):
if isinstance(self[i],cls):
node=self.pop(i)
for x in node:
assert not isinstance(x,cls)
# pass on some attributes
if hasattr(node,'lines') and not hasattr(x,'lines'):
x.lines=node.lines
if hasattr(node,'file') and not hasattr(x,'file'):
x.file=node.file
self.insert(i,x) # expose
i=i+1
assert i<=len(self)
else:
i=i+1
def get_parent( self, item ): # XX 25% CPU time here XX
assert self != item
if item in self:
return self
for child in self:
if isinstance(child, Node):
parent = child.get_parent(item)
if parent is not None:
return parent
return None
def expose_node( self, item ):
assert self != item
parent = self.get_parent(item)
idx = parent.index( item )
parent[idx:idx+1] = item[:]
def delete(self,cls):
' delete any <cls> subtree '
for x in self:
if isinstance(x,Node):
x.delete(cls)
# now the tricky bit
i=0
while i < len(self):
if isinstance(self[i],cls):
self.pop(i)
else:
i=i+1
def deeprm(self,item):
' remove any items matching <item> '
for x in self:
if isinstance(x,Node):
x.deeprm(item)
# now the tricky bit
i=0
while i < len(self):
if self[i] == item:
self.pop(i)
else:
i=i+1
def idem(self,cls):
" <cls> is made idempotent "
# children first
for x in self:
if isinstance(x,Node):
x.idem(cls)
if isinstance(self,cls):
# now the tricky bit
i=0
while i < len(self):
if isinstance(self[i],cls):
node = self.pop(i)
for x in node:
assert not isinstance(x,cls)
self.insert(i,x) # idempotent
i=i+1
assert i<=len(self)
else:
i=i+1
if __name__=="__main__":
node = Node( 'a', Node(1,2), Node(Node(Node(),1)) )
print node
print node.clone()
+106
View File
@@ -0,0 +1,106 @@
#!/usr/bin/env python
""" cdecl.py - parse c declarations
(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
Released under GNU LGPL license.
version 0.xx
"""
import sys
class Symbols(object):
def __init__(self,parent=None,verbose=False):
self.verbose = verbose
self.parent=parent # are we a nested namespace?
self.lookup = {} # identifiers
self.tags = {} # struct, union, enum tags
def __str__(self):
return "Symbols(%s,%s)"%(self.lookup,self.tags)
def __getitem__(self,key):
try:
item = self.lookup[key]
except KeyError:
item = None
#if self.parent is not None:
#item = self.parent[item]
## self[key] = item # cache
#if self.verbose: print "%s.get('%s')='%s'"%(self,key,item)
return item
def __setitem__(self,key,val):
#if self.verbose: print "%s.set('%s','%s')"%(self,key,val)
assert val is not None
self.lookup[key] = val
def set_tag(self,key,val):
#if self.verbose: print "%s.set_tag(%s,%s)"%(self,key,val)
assert len(key)
self.tags[key] = val
def deep_get_tag(self,key):
try:
item = self.tags[key]
except KeyError:
item = None
if self.parent is not None:
item = self.parent.deep_get_tag(key)
#if self.verbose: print "%s.get_tag(%s)=%s"%(self,key,item)
return item
def get_tag(self,key):
try:
item = self.tags[key]
except KeyError:
item = None
#if self.verbose: print "%s.get_tag(%s)=%s"%(self,key,item)
return item
###################################################################
#
###################################################################
#
class ParseError(Exception):
def __init__(self,*e):
self.e = e
def __str__(self):
return "".join(map(str,self.e))
class Parser(object):
def parse_error(self,lexer,reason="?",*blah):
sys.stderr.write( "%s.parse_error()\n"%self.deepstr() )
sys.stderr.write( "at line %s: %s\n"%(lexer.lno+1,reason) )
sys.stderr.write( lexer.err_string() )
raise ParseError(reason,*blah)
def expected_error(self,lexer,*l):
self.parse_error( lexer, "expected %s, got '%s'"\
%(" or ".join(map(repr,l)),lexer.tok))
def consume(self,lexer,tok):
if lexer.tok != tok:
self.expected_error(lexer, tok)
lexer.get_token()
def parse_enter(self,lexer):
#return
self.start_lno=lexer.lno
self.file=lexer.so_file
def parse_leave(self,lexer):
#return
self.lines = lexer.lines[self.start_lno:max(lexer.lno,self.start_lno+1)]
###################################################################
#
###################################################################
#
+192
View File
@@ -0,0 +1,192 @@
#!/usr/bin/env python
"""
(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
Released under GNU LGPL license.
version 0.xx
"""
import sys
import os
import cparse
import ir
def callcmd(cmd):
try:
from subprocess import call
try:
retcode = call(cmd, shell=True)
assert retcode == 0, "command failed: %s"%cmd
except OSError, e:
assert False, "command failed: %s"%e
except ImportError:
status = os.system( cmd )
assert status == 0, "command failed: %s"%cmd
class WorkUnit(object):
def __init__(self, files, modname, filename,
std=False, strip=False, mark_cb=None,
extradefs="", use_header=None, CC="gcc", CPP="gcc -E",
CPPFLAGS=""):
self.files = tuple(files)
self.modname = modname
self.filename = filename
self.CPPFLAGS = CPPFLAGS
self.CPP = CPP
if CC == 'g++':
self.CPPFLAGS += " -D__cplusplus"
self.std = std
self.strip = strip
self.mark_cb = mark_cb
self.node = None
self.extradefs = extradefs
self.CC = CC
self.use_header = use_header
def mkheader( self ):
if self.use_header:
return self.use_header
tmpname = str(abs(hash( (self.files,self.CPPFLAGS) )))
name = '.tmp/%s' % tmpname
ifile = open( name+'.h', "w" )
ifile.write( """
#define __attribute__(...)
#define __const const
#define __restrict
#define __extension__
#define __asm__(...)
#define __asm(...)
#define __inline__
#define __inline
""" )
for filename in self.files:
if self.std:
line = '#include <%s>\n'%filename
else:
line = '#include "%s"\n'%filename
ifile.write( line )
print line,
ifile.close()
cmd = '%s %s %s > %s'%(self.CPP,name+'.h',self.CPPFLAGS,name+'.E')
sys.stderr.write( "# %s\n" % cmd )
callcmd( cmd )
assert open(name+'.E').read().count('\n') > 10, "failed to run preprocessor"
cmd = '%s -dM %s %s > %s'%(self.CPP,name+'.h',self.CPPFLAGS,name+'.dM')
sys.stderr.write( "# %s\n" % cmd )
callcmd( cmd )
assert open(name+'.dM').read().count('\n') > 10, "failed to run preprocessor with -dM"
return name
def parse(self, verbose=False):
sys.stderr.write( "# parse %s\n" % str(self.files) )
name = self.mkheader()
# read macros
f = open(name+'.dM')
macros = {}
for line in f.readlines():
if line:
macro = line.split()[1]
if macro.count('('):
macro = macro[:macro.index('(')]
macros[macro] = None
#keys = macros.keys()
#keys.sort()
#for key in keys:
#print key
self.macros = macros
# parse preprocessed code
f = open(name+'.E')
s = f.read() + self.extradefs
self.node = cparse.TransUnit(verbose = verbose)
sys.stderr.write( "# parsing %s lines\n" % s.count('\n') )
self.node.parse( s )
if self.strip:
self.node.strip(self.files)
def transform(self, verbose=False, test_parse=False, test_types=False):
sys.stderr.write( "# processing...\n" )
self.node = ir.TransUnit( self.node )
self.node.transform(verbose, test_parse, test_types)
#self.node[0].psource()
if self.mark_cb is not None:
self.node.mark(self.mark_cb,verbose=False)
def output( self, func_cb = None ):
sys.stderr.write( "# pyxstr...\n" )
decls = self.node.pyx_decls(self.files, self.modname, macros = self.macros, func_cb = func_cb, names={}, cprefix="" )
name = self.filename
assert name.endswith(".pyx")
pxi = name[:-3]+'pxi'
file = open( pxi, "w" )
file.write(decls)
sys.stderr.write( "# wrote %s, %d lines\n" % (pxi,decls.count('\n')) )
def pprint(self):
for decl in self.node:
#decl.psource()
#cstr = decl.cstr()
#cstr = cstr.replace( '\n', '\n# ' )
print
#print '#', cstr
print decl.deepstr()
def file_exists(path):
try:
os.stat(path)
return True
except OSError:
return False
if sys.platform.count('darwin'):
shared_ext = '.dylib'
else:
shared_ext = '.so'
def get_syms(libs, libdirs):
# XX write interface to objdump -t XX
libnames = []
for lib in libs:
for ext in shared_ext,'.a':
libname = 'lib'+lib+ext
for libdir in libdirs:
path = libdir+'/'+libname
if file_exists(path):
libnames.append(path)
break
#else:
#print "cannot find %s lib as %s in %s" % ( lib, libname, libdir )
print 'libnames:', libnames
syms = {}
accept = [ ' %s '%c for c in 'TVWBCDGRS' ]
#f = open('syms.out','w')
for libname in libnames:
try:
from subprocess import Popen, PIPE
p = Popen(['nm', libname], bufsize=1, stdout=PIPE)
fout = p.stdout
except ImportError:
fin, fout = os.popen2( 'nm %s' % libname )
for line in fout.readlines():
for acc in accept:
if line.count(acc):
left, right = line.split(acc)
sym = right.strip()
if sys.platform.count('darwin'):
if sym[0] == '_':
sym = sym[1:] # remove underscore prefix
if sym.endswith('.eh'):
sym = sym[:-len('.eh')]
syms[sym] = None
#f.write( '%s: %s %s\n' % (sym,line[:-1],libname) )
break
return syms
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python
"""
(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
Released under GNU LGPL license.
version 0.xx
"""
import sys
import os
from work_unit import WorkUnit, get_syms
import ir
def mk_tao(CPPFLAGS = "", CPP = "gcc -E", modname = '_yasm', oname = None, YASM_DIR = ".", **options):
if oname is None:
oname = modname+'.pyx'
CPPFLAGS += " -I"+YASM_DIR
CPPFLAGS += " -DYASM_PYXELATOR"
CPPFLAGS += " -DYASM_LIB_INTERNAL"
CPPFLAGS += " -DYASM_BC_INTERNAL"
CPPFLAGS += " -DYASM_EXPR_INTERNAL"
files = [ 'libyasm.h', 'libyasm/assocdat.h', 'libyasm/bitvect.h' ]
syms = get_syms( ['yasm'], [YASM_DIR] )
def cb(trans_unit, node, *args):
name, file = node.name, node.file
return True
return name in syms
extradefs = ""
unit = WorkUnit(files,modname,oname,False,mark_cb=cb,extradefs=extradefs,
CPPFLAGS=CPPFLAGS, CPP=CPP, **options)
unit.parse( False )
unit.transform(verbose=False, test_parse=False, test_types=False)
unit.output()
def main():
options = {}
for i,arg in enumerate(sys.argv[1:]):
if arg.count('='):
key,val = arg.split('=', 1)
options[key]=val
mk_tao(**options)
if __name__=="__main__":
main()
+88
View File
@@ -0,0 +1,88 @@
#! /usr/bin/env python
# Build Python extension with configuration file input
#
# Copyright (C) 2006 Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
from os.path import basename, join, exists
def ReadSetup(filename):
"""ReadSetup goes through filename and parses out the values stored
in the file. Values need to be stored in a
\"key=value format\""""
return dict(line.split('=', 1) for line in open(filename))
def ParseCPPFlags(flags):
"""parse the CPPFlags macro"""
incl_dir = [x[2:] for x in flags.split() if x.startswith("-I")]
cppflags = [x for x in flags.split() if not x.startswith("-I")]
cppflags.append("-DYASM_LIB_INTERNAL")
cppflags.append("-DYASM_BC_INTERNAL")
cppflags.append("-DYASM_EXPR_INTERNAL")
return (incl_dir, cppflags)
def ParseSources(src, srcdir):
"""parse the Sources macro"""
# do the dance of detecting if the source file is in the current
# directory, and if it's not, prepend srcdir
sources = []
for tok in src.split():
if tok.endswith(".c"):
fn = tok
else:
continue
if not exists(fn):
fn = join(srcdir, fn)
sources.append(fn)
return sources
def RunSetup(incldir, cppflags, sources):
setup(
name='yasm',
version='0.0',
description='Python bindings for Yasm',
author='Michael Urman, Peter Johnson',
url='http://www.tortall.net/projects/yasm',
ext_modules=[
Extension('yasm',
sources=sources,
extra_compile_args=cppflags,
include_dirs=incldir,
),
],
cmdclass = dict(build_ext=build_ext),
)
if __name__ == "__main__":
opts = ReadSetup("python-setup.txt")
incldir, cppflags = ParseCPPFlags(opts["includes"])
sources = ParseSources(opts["sources"], opts["srcdir"].strip())
sources.append('yasm_python.c')
if opts["gcc"].strip() == "yes":
cppflags.append('-w')
RunSetup(incldir, cppflags, sources)
+285
View File
@@ -0,0 +1,285 @@
# Python bindings for Yasm: Pyrex input file for symrec.h
#
# Copyright (C) 2006 Michael Urman, Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
cdef class Symbol:
cdef yasm_symrec *sym
def __cinit__(self, symrec):
self.sym = NULL
if PyCObject_Check(symrec):
self.sym = <yasm_symrec *>__get_voidp(symrec, Symbol)
else:
raise NotImplementedError
# no deref or destroy necessary
property name:
def __get__(self): return yasm_symrec_get_name(self.sym)
property status:
def __get__(self):
cdef yasm_sym_status status
s = set()
status = yasm_symrec_get_status(self.sym)
if <int>status & <int>YASM_SYM_USED: s.add('used')
if <int>status & <int>YASM_SYM_DEFINED: s.add('defined')
if <int>status & <int>YASM_SYM_VALUED: s.add('valued')
return s
property in_table:
def __get__(self):
return bool(<int>yasm_symrec_get_status(self.sym) &
<int>YASM_SYM_NOTINTABLE)
property visibility:
def __get__(self):
cdef yasm_sym_vis vis
s = set()
vis = yasm_symrec_get_visibility(self.sym)
if <int>vis & <int>YASM_SYM_GLOBAL: s.add('global')
if <int>vis & <int>YASM_SYM_COMMON: s.add('common')
if <int>vis & <int>YASM_SYM_EXTERN: s.add('extern')
if <int>vis & <int>YASM_SYM_DLOCAL: s.add('dlocal')
return s
property equ:
def __get__(self):
cdef yasm_expr *e
e = yasm_symrec_get_equ(self.sym)
if not e:
raise AttributeError("not an EQU")
return __make_expression(yasm_expr_copy(e))
property label:
def __get__(self):
cdef yasm_symrec_get_label_bytecodep bc
if yasm_symrec_get_label(self.sym, &bc):
return None #Bytecode(bc)
else:
raise AttributeError("not a label or not defined")
property is_special:
def __get__(self): return bool(yasm_symrec_is_special(self.sym))
property is_curpos:
def __get__(self): return bool(yasm_symrec_is_curpos(self.sym))
def get_data(self): pass # TODO
#return <object>(yasm_symrec_get_data(self.sym, PyYasmAssocData))
def set_data(self, data): pass # TODO
#yasm_symrec_set_data(self.sym, PyYasmAssocData, data)
#
# Use associated data mechanism to keep Symbol reference paired with symrec.
#
cdef void __python_symrec_cb_destroy(void *data):
Py_DECREF(<object>data)
cdef void __python_symrec_cb_print(void *data, FILE *f, int indent_level):
pass
__python_symrec_cb = __assoc_data_callback(
PyCObject_FromVoidPtr(&__python_symrec_cb_destroy, NULL),
PyCObject_FromVoidPtr(&__python_symrec_cb_print, NULL))
cdef object __make_symbol(yasm_symrec *symrec):
cdef void *data
__error_check()
data = yasm_symrec_get_data(symrec,
(<__assoc_data_callback>__python_symrec_cb).cb)
if data != NULL:
return <object>data
symbol = Symbol(__pass_voidp(symrec, Symbol))
yasm_symrec_add_data(symrec,
(<__assoc_data_callback>__python_symrec_cb).cb,
<void *>symbol)
Py_INCREF(symbol) # We're keeping a reference on the C side!
return symbol
cdef class Bytecode
cdef class SymbolTable
cdef class SymbolTableKeyIterator:
cdef yasm_symtab_iter *iter
def __cinit__(self, symtab):
if not isinstance(symtab, SymbolTable):
raise TypeError
self.iter = yasm_symtab_first((<SymbolTable>symtab).symtab)
def __iter__(self):
return self
def __next__(self):
if self.iter == NULL:
raise StopIteration
rv = yasm_symrec_get_name(yasm_symtab_iter_value(self.iter))
self.iter = yasm_symtab_next(self.iter)
return rv
cdef class SymbolTableValueIterator:
cdef yasm_symtab_iter *iter
def __cinit__(self, symtab):
if not isinstance(symtab, SymbolTable):
raise TypeError
self.iter = yasm_symtab_first((<SymbolTable>symtab).symtab)
def __iter__(self):
return self
def __next__(self):
if self.iter == NULL:
raise StopIteration
rv = __make_symbol(yasm_symtab_iter_value(self.iter))
self.iter = yasm_symtab_next(self.iter)
return rv
cdef class SymbolTableItemIterator:
cdef yasm_symtab_iter *iter
def __cinit__(self, symtab):
if not isinstance(symtab, SymbolTable):
raise TypeError
self.iter = yasm_symtab_first((<SymbolTable>symtab).symtab)
def __iter__(self):
return self
def __next__(self):
cdef yasm_symrec *sym
if self.iter == NULL:
raise StopIteration
sym = yasm_symtab_iter_value(self.iter)
rv = (yasm_symrec_get_name(sym), __make_symbol(sym))
self.iter = yasm_symtab_next(self.iter)
return rv
cdef int __parse_vis(vis) except -1:
if not vis or vis == 'local': return YASM_SYM_LOCAL
if vis == 'global': return YASM_SYM_GLOBAL
if vis == 'common': return YASM_SYM_COMMON
if vis == 'extern': return YASM_SYM_EXTERN
if vis == 'dlocal': return YASM_SYM_DLOCAL
msg = "bad visibility value %r" % vis
PyErr_SetString(ValueError, msg)
return -1
cdef class SymbolTable:
cdef yasm_symtab *symtab
def __cinit__(self):
self.symtab = yasm_symtab_create()
def __dealloc__(self):
if self.symtab != NULL: yasm_symtab_destroy(self.symtab)
def use(self, name, line):
return __make_symbol(yasm_symtab_use(self.symtab, name, line))
def define_equ(self, name, expr, line):
if not isinstance(expr, Expression):
raise TypeError
return __make_symbol(yasm_symtab_define_equ(self.symtab, name,
yasm_expr_copy((<Expression>expr).expr), line))
def define_label(self, name, precbc, in_table, line):
if not isinstance(precbc, Bytecode):
raise TypeError
return __make_symbol(yasm_symtab_define_label(self.symtab, name,
(<Bytecode>precbc).bc, in_table, line))
def define_special(self, name, vis):
return __make_symbol(
yasm_symtab_define_special(self.symtab, name,
<yasm_sym_vis>__parse_vis(vis)))
def declare(self, name, vis, line):
return __make_symbol(
yasm_symtab_declare(self.symtab, name,
<yasm_sym_vis>__parse_vis(vis), line))
#
# Methods to make SymbolTable behave like a dictionary of Symbols.
#
def __getitem__(self, key):
cdef yasm_symrec *symrec
symrec = yasm_symtab_get(self.symtab, key)
if symrec == NULL:
raise KeyError
return __make_symbol(symrec)
def __contains__(self, key):
cdef yasm_symrec *symrec
symrec = yasm_symtab_get(self.symtab, key)
return symrec != NULL
def keys(self):
cdef yasm_symtab_iter *iter
l = []
iter = yasm_symtab_first(self.symtab)
while iter != NULL:
l.append(yasm_symrec_get_name(yasm_symtab_iter_value(iter)))
iter = yasm_symtab_next(iter)
return l
def values(self):
cdef yasm_symtab_iter *iter
l = []
iter = yasm_symtab_first(self.symtab)
while iter != NULL:
l.append(__make_symbol(yasm_symtab_iter_value(iter)))
iter = yasm_symtab_next(iter)
return l
def items(self):
cdef yasm_symtab_iter *iter
cdef yasm_symrec *sym
l = []
iter = yasm_symtab_first(self.symtab)
while iter != NULL:
sym = yasm_symtab_iter_value(iter)
l.append((yasm_symrec_get_name(sym), __make_symbol(sym)))
iter = yasm_symtab_next(iter)
return l
def has_key(self, key):
cdef yasm_symrec *symrec
symrec = yasm_symtab_get(self.symtab, key)
return symrec != NULL
def get(self, key, x):
cdef yasm_symrec *symrec
symrec = yasm_symtab_get(self.symtab, key)
if symrec == NULL:
return x
return __make_symbol(symrec)
def iterkeys(self): return SymbolTableKeyIterator(self)
def itervalues(self): return SymbolTableValueIterator(self)
def iteritems(self): return SymbolTableItemIterator(self)
def __iter__(self): return SymbolTableKeyIterator(self)
@@ -0,0 +1,13 @@
EXTRA_DIST += tools/python-yasm/tests/python_test.sh
EXTRA_DIST += tools/python-yasm/tests/__init__.py
EXTRA_DIST += tools/python-yasm/tests/test_bytecode.py
EXTRA_DIST += tools/python-yasm/tests/test_expr.py
EXTRA_DIST += tools/python-yasm/tests/test_intnum.py
EXTRA_DIST += tools/python-yasm/tests/test_symrec.py
if HAVE_PYTHON_BINDINGS
TESTS_ENVIRONMENT += PYTHON=${PYTHON}
TESTS += tools/python-yasm/tests/python_test.sh
endif
@@ -0,0 +1,69 @@
# Test wrapper from Quod Libet
# http://www.sacredchao.net/quodlibet/
import unittest, sys
suites = []
add = registerCase = suites.append
from unittest import TestCase
class Mock(object):
# A generic mocking object.
def __init__(self, **kwargs): self.__dict__.update(kwargs)
import test_intnum
import test_symrec
import test_bytecode
import test_expr
class Result(unittest.TestResult):
separator1 = '=' * 70
separator2 = '-' * 70
def addSuccess(self, test):
unittest.TestResult.addSuccess(self, test)
sys.stdout.write('.')
def addError(self, test, err):
unittest.TestResult.addError(self, test, err)
sys.stdout.write('E')
def addFailure(self, test, err):
unittest.TestResult.addFailure(self, test, err)
sys.stdout.write('F')
def printErrors(self):
succ = self.testsRun - (len(self.errors) + len(self.failures))
v = "%3d" % succ
count = 50 - self.testsRun
sys.stdout.write((" " * count) + v + "\n")
self.printErrorList('ERROR', self.errors)
self.printErrorList('FAIL', self.failures)
def printErrorList(self, flavour, errors):
for test, err in errors:
sys.stdout.write(self.separator1 + "\n")
sys.stdout.write("%s: %s\n" % (flavour, str(test)))
sys.stdout.write(self.separator2 + "\n")
sys.stdout.write("%s\n" % err)
class Runner:
def run(self, test):
suite = unittest.makeSuite(test)
pref = '%s (%d): ' % (test.__name__, len(suite._tests))
print pref + " " * (25 - len(pref)),
result = Result()
suite(result)
result.printErrors()
return bool(result.failures + result.errors)
def unit(run = []):
runner = Runner()
failures = False
for test in suites:
if not run or test.__name__ in run:
failures |= runner.run(test)
return failures
if __name__ == "__main__":
raise SystemExit(unit(sys.argv[1:]))
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
# Based on _sanity.sh from Quod Libet
# http://www.sacredchao.net/quodlibet/
set -e
test -n "${srcdir}" || srcdir=.
test -n "${PYTHON}" || PYTHON=python
if test "$1" = "--help" -o "$1" = "-h"; then
echo "Usage: $0 --sanity | [TestName] ..."
exit 0
elif [ "$1" = "--sanity" ]; then
echo "Running static sanity checks."
grep "except None:" ${srcdir}/tools/python-yasm/tests/*.py
else
${PYTHON} -c "import sys; import glob; sys.path.insert(0, '${srcdir}/tools/python-yasm'); sys.path.insert(0, glob.glob('build/lib.*')[0]); import tests; raise SystemExit(tests.unit('$*'.split()))"
fi
@@ -0,0 +1,3 @@
from tests import TestCase, add
from yasm import Bytecode, Expression
@@ -0,0 +1,18 @@
from tests import TestCase, add
from yasm import Expression
import operator
class TExpression(TestCase):
def test_create(self):
e1 = Expression(operator.add, 1, 2)
e2 = Expression('+', 1, 2)
self.assertEquals(e1.get_intnum(), e1.get_intnum())
def test_extract(self):
e1 = Expression('/', 15, 5)
self.assertEquals(e1.get_intnum(), 3)
self.assertRaises(ValueError, e1.extract_segoff)
self.assertRaises(ValueError, e1.extract_wrt)
add(TExpression)
@@ -0,0 +1,77 @@
from tests import TestCase, add
from yasm import IntNum
class TIntNum(TestCase):
legal_values = [
0, 1, -1, 2, -2, 17, -17,
2**31-1, -2**31, 2**31, 2**32-1, -2**32,
2**63-1, -2**63-1, 2**63, 2**64, -2**64,
2**127-1, -2**127
]
overflow_values = [
2**127, -2**127-1
]
def test_to_from(self):
for i in self.legal_values:
self.assertEquals(i, int(IntNum(i)))
self.assertEquals(i, long(IntNum(i)))
def test_overflow(self):
for i in self.overflow_values:
self.assertRaises(OverflowError, IntNum, i)
str_values = [
"0", "00000", "1234", "87654321", "010101010", "FADCBEEF"
]
base_values = [2, 8, 10, 12, 16, None, "nasm", "foo"]
def test_from_str(self):
pass
def test_from_str_base(self):
pass
def test_exceptions(self):
self.assertRaises(ZeroDivisionError, IntNum(1).__div__, 0)
IntNum(1) / 1 # make sure the above error is cleared
try: IntNum(1) / 0
except ZeroDivisionError, err:
self.assertEquals('divide by zero', str(err))
def test_xor(self):
a = IntNum(-234)
b = IntNum(432)
c = a ^ b
self.assertEquals(a, -234)
self.assertEquals(b, 432)
self.assertEquals(c, -234 ^ 432)
def test_ixor(self):
a = IntNum(-234)
b = IntNum(432)
a ^= b; b ^= a; a ^= b
self.assertEquals(a, 432)
self.assertEquals(b, -234)
def test_cmp(self):
a = IntNum(-1)
b = IntNum(0)
c = IntNum(1)
self.assert_(a < b < c)
self.assert_(a <= b <= c)
self.assert_(c >= b >= a)
self.assert_(c > b > a)
self.assert_(a != b != c)
def test_abs(self):
a = IntNum(-1)
b = IntNum(0)
c = IntNum(1)
self.assertEquals(abs(a), abs(c))
self.assertEquals(abs(a) - abs(c), abs(b))
add(TIntNum)
@@ -0,0 +1,80 @@
from tests import TestCase, add
from yasm import SymbolTable, Expression, YasmError
class TSymbolTable(TestCase):
def setUp(self):
self.symtab = SymbolTable()
def test_keys(self):
self.assertEquals(len(self.symtab.keys()), 0)
self.symtab.declare("foo", None, 0)
keys = self.symtab.keys()
self.assertEquals(len(keys), 1)
self.assertEquals(keys[0], "foo")
def test_contains(self):
self.assert_("foo" not in self.symtab)
self.symtab.declare("foo", None, 0)
self.assert_("foo" in self.symtab)
def test_exception(self):
expr = Expression('+', 1, 2)
self.symtab.define_equ("foo", expr, 0)
self.assertRaises(YasmError, self.symtab.define_equ, "foo", expr, 0)
self.symtab.define_equ("bar", expr, 0) # cleared
self.assertRaises(YasmError, self.symtab.define_special, "bar",
'global')
def test_iters(self):
tab = self.symtab
tab.declare("foo", None, 0)
tab.declare("bar", None, 0)
tab.declare("baz", None, 0)
# while ordering is not known, it must be consistent
self.assertEquals(list(tab.keys()), list(tab.iterkeys()))
self.assertEquals(list(tab.values()), list(tab.itervalues()))
self.assertEquals(list(tab.items()), list(tab.iteritems()))
self.assertEquals(list(tab.iteritems()), zip(tab.keys(), tab.values()))
add(TSymbolTable)
class TSymbolAttr(TestCase):
def setUp(self):
self.symtab = SymbolTable()
self.declsym = self.symtab.declare("foo", None, 0)
def test_visibility(self):
sym = self.symtab.declare("local1", None, 0)
self.assertEquals(sym.visibility, set())
sym = self.symtab.declare("local2", '', 0)
self.assertEquals(sym.visibility, set())
sym = self.symtab.declare("local3", 'local', 0)
self.assertEquals(sym.visibility, set())
sym = self.symtab.declare("global", 'global', 0)
self.assertEquals(sym.visibility, set(['global']))
sym = self.symtab.declare("common", 'common', 0)
self.assertEquals(sym.visibility, set(['common']))
sym = self.symtab.declare("extern", 'extern', 0)
self.assertEquals(sym.visibility, set(['extern']))
sym = self.symtab.declare("dlocal", 'dlocal', 0)
self.assertEquals(sym.visibility, set(['dlocal']))
self.assertRaises(ValueError,
lambda: self.symtab.declare("extern2", 'foo', 0))
def test_name(self):
self.assertEquals(self.declsym.name, "foo")
def test_equ(self):
self.assertRaises(AttributeError, lambda: self.declsym.equ)
def test_label(self):
self.assertRaises(AttributeError, lambda: self.declsym.label)
def test_is_special(self):
self.assertEquals(self.declsym.is_special, False)
def test_is_curpos(self):
self.assertEquals(self.declsym.is_curpos, False)
add(TSymbolAttr)
+56
View File
@@ -0,0 +1,56 @@
# Python bindings for Yasm: Pyrex input file for value.h
#
# Copyright (C) 2006 Michael Urman, Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
cdef class Value:
cdef yasm_value value
def __cinit__(self, value=None, size=None):
cdef unsigned int sz
if size is None:
sz = 0
else:
sz = size;
yasm_value_initialize(&self.value, NULL, sz)
if value is None:
pass
elif isinstance(value, Expression):
yasm_value_initialize(&self.value,
yasm_expr_copy((<Expression>value).expr), sz)
elif isinstance(value, Symbol):
yasm_value_init_sym(&self.value, (<Symbol>value).sym, sz)
else:
raise TypeError("Invalid value type '%s'" % type(value))
def __dealloc__(self):
yasm_value_delete(&self.value)
def finalize(self, precbc=None):
if precbc is None:
return yasm_value_finalize(&self.value, NULL)
elif isinstance(precbc, Bytecode):
return yasm_value_finalize(&self.value, (<Bytecode>precbc).bc)
else:
raise TypeError("Invalid precbc type '%s'" % type(precbc))
+137
View File
@@ -0,0 +1,137 @@
# Python bindings for Yasm: Main Pyrex input file
#
# Copyright (C) 2006 Michael Urman, Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
"""Interface to the Yasm library.
The Yasm library (aka libyasm) provides the core functionality of the Yasm
assembler. Classes in this library provide for manipulation of machine
instructions and object file constructs such as symbol tables and sections.
Expression objects encapsulate complex expressions containing registers,
symbols, and operations such as SEG.
Bytecode objects encapsulate data or code objects such as data, reserve,
align, or instructions.
Section objects encapsulate an object file section, including the section
name, any Bytecode objects contained within that section, and other
information.
"""
cdef extern from "Python.h":
cdef object PyCObject_FromVoidPtr(void *cobj, void (*destr)(void *))
cdef object PyCObject_FromVoidPtrAndDesc(void *cobj, void *desc,
void (*destr)(void *, void *))
cdef int PyType_Check(object)
cdef int PyCObject_Check(object)
cdef void *PyCObject_AsVoidPtr(object)
cdef void *PyCObject_GetDesc(object)
cdef object _PyLong_FromByteArray(unsigned char *bytes, unsigned int n,
int little_endian, int is_signed)
cdef int _PyLong_AsByteArray(object v, unsigned char *bytes, unsigned int n,
int little_endian, int is_signed) except -1
cdef void Py_INCREF(object o)
cdef void Py_DECREF(object o)
cdef void PyErr_SetString(object type, char *message)
cdef object PyErr_Format(object type, char *format, ...)
cdef extern from "stdlib.h":
cdef void *malloc(int n)
cdef void free(void *p)
include "_yasm.pxi"
cdef object __pass_voidp(void *obj, object forclass):
return PyCObject_FromVoidPtrAndDesc(obj, <void *>forclass, NULL)
cdef void *__get_voidp(object obj, object forclass) except NULL:
cdef void* desc
if not PyCObject_Check(obj):
msg = "obj %r is not a CObject" % obj
PyErr_SetString(TypeError, msg)
return NULL
desc = PyCObject_GetDesc(obj)
if desc != <void *>forclass:
if desc == NULL:
msg = "CObject type is not set (expecting %s)" % forclass
elif PyType_Check(<object>desc):
msg = "CObject is for %s not %s" % (<object>desc, forclass)
else:
msg = "CObject is incorrect (expecting %s)" % forclass
PyErr_SetString(TypeError, msg)
return NULL
return PyCObject_AsVoidPtr(obj)
#
# Link to associated data mechanism to keep Python references paired with
# yasm objects.
#
cdef class __assoc_data_callback:
cdef yasm_assoc_data_callback *cb
def __cinit__(self, destroy, print_):
self.cb = <yasm_assoc_data_callback *>malloc(sizeof(yasm_assoc_data_callback))
self.cb.destroy = <void (*) (void *)>PyCObject_AsVoidPtr(destroy)
#self.cb.print_ = <void (*) (void *, FILE *, int)>PyCObject_AsVoidPtr(print_)
def __dealloc__(self):
free(self.cb)
cdef class Register:
cdef unsigned long reg
def __cinit__(self, reg):
self.reg = reg
include "errwarn.pxi"
include "intnum.pxi"
include "floatnum.pxi"
include "expr.pxi"
include "symrec.pxi"
include "value.pxi"
include "bytecode.pxi"
cdef __initialize():
BitVector_Boot()
yasm_intnum_initialize()
yasm_floatnum_initialize()
yasm_errwarn_initialize()
def __cleanup():
yasm_floatnum_cleanup()
yasm_intnum_cleanup()
yasm_errwarn_cleanup()
BitVector_Shutdown()
__initialize()
import atexit
atexit.register(__cleanup)