-PHP_ARG_ENABLE(psi, whether to enable PHP System Interface support,
-[ --enable-psi Enable PHP System Interface support])
-
-PHP_ARG_WITH(psi-libjit, where to find libjit,
-[ --with-psi-libjit=DIR PSI: path to libjit], [ ], [ ])
-
-PHP_ARG_WITH(psi-libffi, where to find libffi,
-[ --with-psi-libffi=DIR PSI: path to libffi], [ ], [ ])
-
PHP_PSI_SRCDIR=PHP_EXT_SRCDIR(psi)
PHP_PSI_BUILDDIR=PHP_EXT_BUILDDIR(psi)
sinclude([ext/psi/m4/]incfile)
])
+PHP_ARG_ENABLE(psi, whether to enable PHP System Interface support,
+[ --enable-psi Enable PHP System Interface support])
+
+PHP_ARG_ENABLE(psi-posix, whether to pre-define POSIX decls,
+[ --ebable-psi-posix PSI: pre-define POSIX decls], [ ], [ ])
+
+PHP_ARG_WITH(psi-libjit, where to find libjit,
+[ --with-psi-libjit=DIR PSI: path to libjit], [ ], [ ])
+
+PHP_ARG_WITH(psi-libffi, where to find libffi,
+[ --with-psi-libffi=DIR PSI: path to libffi], [ ], [ ])
+
if test "$PHP_PSI" != no; then
PHP_CONFIGURE_PART(Configuring PSI)
PSI_CONFIG_INIT
PSI_CHECK_STD_TYPES
PSI_CHECK_STDINT
- PSI_CHECK_STDDEF
PSI_CHECK_SYS_TYPES
+ PSI_CHECK_STDDEF
PSI_CHECK_ERRNO
PSI_CHECK_FCNTL
PSI_CHECK_GLOB
PSI_CHECK_ERRNO() {
- AC_CHECK_HEADERS(errno.h)
+ PSI_CONFIG_POSIX(errno, errno.h)
PSI_EXTVAR(int errno)
PSI_CHECK_FCNTL() {
- AC_CHECK_HEADERS(fcntl.h)
+ PSI_CONFIG_POSIX(fcntl, fcntl.h)
PSI_CONST(F_DUPFD, int)
PSI_CONST(F_DUPFD_CLOEXEC, int)
PSI_CHECK_GLOB() {
- AC_CHECK_HEADERS(glob.h)
+ PSI_CONFIG_POSIX(glob, glob.h)
+
PSI_STRUCT(glob_t, [
size_t gl_pathc,
int gl_matchc,
PSI_CHECK_LOCALE() {
- AC_CHECK_HEADERS(locale.h xlocale.h)
+ PSI_CONFIG_POSIX(locale, locale.h xlocale.h)
PSI_STRUCT(struct lconv, [
char *currency_symbol,
PSI_CHECK_NDBM() {
- AC_CHECK_HEADERS(ndbm.h)
+ PSI_CONFIG_POSIX(ndbm, ndbm.h)
PHP_CHECK_FUNC_LIB(dbm_open, gdbm_compat)
PSI_CHECK_NETDB() {
- AC_CHECK_HEADERS(netdb.h)
+ PSI_CONFIG_POSIX(netdb, netdb.h)
PSI_STRUCT(struct hostent, [
char *h_name,
PSI_CHECK_NETINET_IN() {
- AC_CHECK_HEADERS(netinet/in.h)
+ PSI_CONFIG_POSIX(netinet/in, netinet/in.h)
PSI_TYPE(in_port_t, uint)
PSI_TYPE(in_addr_t, uint)
PSI_CHECK_NETINET_TCP() {
- AC_CHECK_HEADERS(netinet/tcp.h)
+ PSI_CONFIG_POSIX(netinet/tcp, netinet/tcp.h)
PSI_CONST(TCP_NODELAY, int)
}
PSI_CHECK_POLL() {
- AC_CHECK_HEADERS(poll.h)
+ PSI_CONFIG_POSIX(poll, poll.h)
PSI_STRUCT(struct pollfd, [
int fd,
done
])
+dnl PSI_CONFIG_POSIX(section, headers)
+AC_DEFUN(PSI_CONFIG_POSIX, [
+ case "$PHP_PSI_POSIX" in
+ yes|all) ;;
+ *) expr "$PHP_PSI_POSIX" : '\b$1\b' >/dev/null || return 0 ;;
+ esac
+ ifelse($2,,,AC_CHECK_HEADERS($2))
+])
+
dnl PSI_INCLUDES()
dnl Expands to a complete list of include statements including
dnl AC_INCLUDES_DEFAULT().
PSI_CHECK_STDIO() {
- AC_CHECK_HEADER(stdio.h)
+ PSI_CONFIG_POSIX(stdio, stdio.h)
PSI_STRUCT(FILE)
PSI_STRUCT(fpos_t)
PSI_CHECK_SYS_SELECT() {
- AC_CHECK_HEADERS(sys/select.h)
+ PSI_CONFIG_POSIX(sys/select, sys/select.h)
PSI_STRUCT(fd_set, [])
PSI_CHECK_SYS_SOCKET() {
- AC_CHECK_HEADERS(sys/socket.h)
+ PSI_CONFIG_POSIX(sys/socket, sys/socket.h)
PSI_TYPE(socklen_t, int)
PSI_TYPE(sa_family_t, uint)
PSI_CHECK_SYS_STAT() {
- AC_CHECK_HEADERS([sys/stat.h])
+ PSI_CONFIG_POSIX(sys/stat, sys/stat.h)
PSI_STRUCT(struct stat, [
dev_t st_dev,
PSI_CHECK_SYS_TIME() {
- AC_CHECK_HEADERS(sys/time.h)
+ PSI_CONFIG_POSIX(sys/time, sys/time.h)
PSI_CONST(ITIMER_REAL, int)
PSI_CONST(ITIMER_VIRTUAL, int)
PSI_CHECK_SYS_TIMES() {
- AC_CHECK_HEADERS(sys/times.h)
+ PSI_CONFIG_POSIX(sys/times, sys/times.h)
PSI_STRUCT(struct tms, [
clock_t tms_utime,
PSI_CHECK_SYS_UIO() {
- AC_CHECK_HEADERS(sys/uio.h)
+ PSI_CONFIG_POSIX(sys/uio, sys/uio.h)
PSI_STRUCT(struct iovec, [
void *iov_base,
PSI_CHECK_SYS_UTSNAME() {
- AC_CHECK_HEADERS(sys/utsname.h)
+ PSI_CONFIG_POSIX(sys/utsname, sys/utsname.h)
PSI_STRUCT(struct utsname, [
char sysname@<:@0@:>@,
PSI_CHECK_SYSLOG() {
- AC_CHECK_HEADERS(syslog.h)
+ PSI_CONFIG_POSIX(syslog, syslog.h)
PSI_CONST(LOG_PID, int)
PSI_CONST(LOG_CONS, int)
PSI_CHECK_TIME() {
- AC_CHECK_HEADERS(time.h)
+ PSI_CONFIG_POSIX(time, time.h)
PSI_CONST(CLOCKS_PER_SEC, int)
PSI_CONST(CLOCK_MONOTONIC, int)
PSI_CHECK_WCHAR() {
- AC_CHECK_HEADERS(wchar.h)
+ PSI_CONFIG_POSIX(wchar, wchar.h)
PSI_TYPE(wint_t, int)
PSI_STRUCT(mbstate_t)
PSI_CHECK_WCTYPE() {
- AC_CHECK_HEADERS(wctype.h)
+ PSI_CONFIG_POSIX(wctype, wctype.h)
PSI_TYPE(wctype_t, int)
PSI_TYPE(wctrans_t, int)
#include "libjit.h"
#include "libffi.h"
+static inline void dump_decl_arg(int fd, decl_arg *darg);
+
static inline void dump_decl_type(int fd, decl_type *t) {
const char *pre;
+ size_t j;
switch (t->type) {
+ case PSI_T_POINTER:
+ dprintf(fd, "%s *", t->name);
+ return;
+
+ case PSI_T_FUNCTION:
+ dump_decl_arg(fd, t->func->func);
+ dprintf(fd, "(");
+ if (t->func->args) {
+ for (j = 0; j < t->func->args->count; ++j) {
+ if (j) {
+ dprintf(fd, ", ");
+ }
+ dump_decl_arg(fd, t->func->args->args[j]);
+ }
+ if (t->func->args->varargs) {
+ dprintf(fd, ", ...");
+ }
+ }
+ dprintf(fd, ")");
+ return;
+
case PSI_T_STRUCT:
pre = "struct ";
break;
+ case PSI_T_ENUM:
+ pre = "enum ";
+ break;
+ case PSI_T_UNION:
+ pre = "union ";
+ break;
default:
pre = "";
+ break;
}
dprintf(fd, "%s%s", pre, t->name);
}
static inline void dump_typedef(int fd, decl_arg *tdef) {
dprintf(fd, "typedef ");
dump_decl_arg(fd, tdef);
+ dprintf(fd, ";");
/*
dump_decl_type(fd, tdef->type);
dprintf(fd, " %s%s;", tdef->type->type == PSI_T_POINTER ? "*":"",
for (i = 0; i < structs->count; ++i) {
decl_struct *strct = structs->list[i];
+
dump_struct(fd, strct);
dprintf(fd, "\n");
}
return 0;
}
+static inline int locate_decl_type_union(decl_unions *unions, decl_type *type) {
+ size_t i;
+
+ if (type->unn) {
+ return 1;
+ }
+ if (unions) for (i = 0; i < unions->count; ++i) {
+ if (!strcmp(unions->list[i]->name, type->name)) {
+ type->unn = unions->list[i];
+ return 1;
+ }
+ }
+ return 0;
+}
+
static inline int locate_decl_type_enum(decl_enums *enums, decl_type *type) {
size_t i;
return 0;
}
+static inline int validate_decl_struct(PSI_Data *data, decl_struct *s);
+static inline int validate_decl_union(PSI_Data *data, decl_union *u);
+static inline int validate_decl_enum(PSI_Data *data, decl_enum *e);
+
static inline int validate_decl_type(PSI_Data *data, decl_type *type) {
switch (type->type) {
case PSI_T_CHAR:
return 0;
}
break;
+ case PSI_T_UNION:
+ if (!locate_decl_type_union(data->unions, type)) {
+ return 0;
+ }
+ break;
case PSI_T_ENUM:
if (!locate_decl_type_enum(data->enums, type)) {
return 0;
static inline int validate_decl_arg(PSI_Data *data, decl_arg *arg) {
if (!validate_decl_type(data, arg->type)) {
data->error(arg->type->token, PSI_WARNING,
- "Cannot use '%s'(%d) as type for decl var '%s'",
- arg->type->name, arg->type->type, arg->var->name);
+ "Cannot use '%s' as type for '%s'",
+ arg->type->name, arg->var->name);
return 0;
}
return 1;
*_b = *_a;
*_a = _c;
}
-static inline void psi_sort_struct_args(decl_struct *s) {
- zend_insert_sort(s->args->args, s->args->count, sizeof(*s->args->args),
+static inline void psi_sort_struct_args(void **args, size_t count) {
+ zend_insert_sort(args, count, sizeof(*args),
psi_sort_struct_arg_cmp, psi_sort_struct_arg_swp);
}
-static inline int validate_decl_struct(PSI_Data *data, decl_struct *s) {
- size_t i;
+static inline int validate_decl_struct_darg(PSI_Data *data, decl_arg *darg) {
+ decl_type *real = real_decl_type(darg->type);
- for (i = 0; i < s->args->count; ++i) {
- if (!validate_decl_arg(data, s->args->args[i])) {
+ /* pre-validate any structs/unions/enums */
+ switch (real->type) {
+ case PSI_T_STRUCT:
+ if (!validate_decl_struct(data, real->strct)) {
+ return 0;
+ }
+ break;
+ case PSI_T_UNION:
+ if (!validate_decl_union(data, real->unn)) {
return 0;
}
+ break;
+ case PSI_T_ENUM:
+ if (!validate_decl_enum(data, real->enm)) {
+ return 0;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static inline size_t sizeof_decl_arg(decl_arg *darg) {
+ size_t size;
+ decl_type *real = real_decl_type(darg->type);
+
+ if (darg->var->array_size) {
+ if (darg->var->pointer_level > 2) {
+ size = psi_t_size(PSI_T_POINTER) * darg->var->array_size;
+ } else {
+ size = psi_t_size(real->type) * darg->var->array_size;
+ }
+ } else if (darg->var->pointer_level) {
+ size = psi_t_size(PSI_T_POINTER);
+ } else {
+ switch (real->type) {
+ case PSI_T_UNION:
+ size = real->unn->size;
+ break;
+ case PSI_T_STRUCT:
+ size = real->strct->size;
+ break;
+ case PSI_T_ENUM:
+ default:
+ size = psi_t_size(real->type);
+ break;
+ }
+ }
+
+ return size;
+}
+
+static inline size_t align_decl_arg(decl_arg *darg, size_t *pos, size_t *len) {
+ size_t align;
+
+ if (darg->var->pointer_level && (!darg->var->array_size || darg->var->pointer_level > 2)) {
+ align = psi_t_alignment(PSI_T_POINTER);
+ } else {
+ decl_type *real = real_decl_type(darg->type);
+
+ switch (real->type) {
+ case PSI_T_STRUCT:
+ align = real->strct->align;
+ break;
+ case PSI_T_UNION:
+ align = real->unn->align;
+ break;
+ default:
+ align = psi_t_alignment(real->type);
+ break;
+ }
+ }
+
+ *len = sizeof_decl_arg(darg);
+ *pos = psi_align(align, *pos);
+
+ return align;
+}
+
+static inline int validate_decl_struct(PSI_Data *data, decl_struct *s) {
+ size_t i, pos, len, size, align;
+
+ if (!s->size && !s->args->count) {
+ data->error(s->token, PSI_WARNING,
+ "Cannot compute size of empty struct %s",
+ s->name);
+ return 0;
}
for (i = 0; i < s->args->count; ++i) {
darg->var->arg = darg;
if (darg->layout) {
- size_t size;
+ pos = darg->layout->pos;
- if (darg->var->array_size) {
- size = psi_t_size(real_decl_type(darg->type)->type) * darg->var->array_size;
- } else if (darg->var->pointer_level) {
- size = psi_t_size(PSI_T_POINTER);
- } else {
- decl_type *real = real_decl_type(darg->type);
+ align = align_decl_arg(darg, &pos, &len);
- if (real->type == PSI_T_STRUCT) {
- size = real->strct->size;
- } else {
- size = psi_t_size(real->type);
- }
- }
- if (darg->layout->len != size) {
+ if (darg->layout->len != len) {
data->error(darg->token, PSI_WARNING,
- "Computed length %zu of %s.%s does not match"
- " pre-defined length %zu of type '%s'",
- darg->layout->len, s->name, darg->var->name, size,
+ "Computed size %zu of %s.%s does not match"
+ " pre-defined size %zu of type '%s'",
+ darg->layout->len, s->name, darg->var->name, len,
darg->type->name);
return 0;
}
+ if (darg->layout->pos != pos) {
+ data->error(darg->token, PSI_WARNING,
+ "Computed offset %zu of %s.%s does not match"
+ " pre-defined offset %zu",
+ darg->layout->len, s->name, darg->var->name, len);
+ return 0;
+ }
+ } else if (!validate_decl_struct_darg(data, darg)) {
+ return 0;
} else {
- token_t t;
- size_t size, align;
-
- if (darg->var->pointer_level && (!darg->var->array_size || darg->var->pointer_level == 1)) {
- t = PSI_T_POINTER;
+ if (i) {
+ pos = s->args->args[i-1]->layout->pos +
+ s->args->args[i-1]->layout->len;
} else {
- t = real_decl_type(darg->type)->type;
+ pos = 0;
}
- switch (t) {
- case PSI_T_STRUCT:
- if (!validate_decl_struct(data, real_decl_type(darg->type)->strct)) {
- return 0;
- }
- size = real_decl_type(darg->type)->strct->size;
- break;
- default:
- size = psi_t_size(t) * (darg->var->array_size ?: 1);
- break;
- }
+ align = align_decl_arg(darg, &pos, &len);
+ darg->layout = init_decl_struct_layout(pos, len);
+ }
- if (i) {
- decl_arg *last = s->args->args[i-1];
+ if (align > s->align) {
+ s->align = align;
+ }
+ }
- align = psi_t_align(t, last->layout->pos + last->layout->len);
- } else {
- align = 0;
+ psi_sort_struct_args((void **) s->args->args, s->args->count);
+
+ if (s->args->count) {
+ decl_arg *darg = s->args->args[s->args->count-1];
+
+ size = darg->layout->pos + darg->layout->len;
+ if (s->size < size) {
+ s->size = psi_align(size, s->align);
+ }
+ }
+
+ return 1;
+}
+
+static inline int validate_decl_union(PSI_Data *data, decl_union *u) {
+ size_t i, pos, len, size, align;
+
+ if (!u->size && !u->args->count) {
+ data->error(u->token, PSI_WARNING,
+ "Cannot compute size of empty union %s",
+ u->name);
+ return 0;
+ }
+
+ for (i = 0; i < u->args->count; ++i) {
+ decl_arg *darg = u->args->args[i];
+
+ if (!validate_decl_arg(data, darg)) {
+ return 0;
+ }
+
+ ZEND_ASSERT(!darg->var->arg || darg->var->arg == darg);
+ darg->var->arg = darg;
+
+ if (darg->layout) {
+ pos = darg->layout->pos;
+
+ align = align_decl_arg(darg, &pos, &len);
+
+ if (darg->layout->pos != 0) {
+ data->error(darg->token, PSI_WARNING,
+ "Offset of %s.%s must be 0",
+ u->name, darg->var->name);
+ return 0;
+ }
+ if (darg->layout->len != len) {
+ data->error(darg->token, PSI_WARNING,
+ "Computed size %zu of %s.%s does not match"
+ " pre-defined size %zu of type '%s'",
+ darg->layout->len, u->name, darg->var->name, size,
+ darg->type->name);
+ return 0;
}
+ } else if (!validate_decl_struct_darg(data, darg)) {
+ return 0;
+ } else {
+ pos = 0;
+
+ align = align_decl_arg(darg, &pos, &len);
+ darg->layout = init_decl_struct_layout(pos, len);
- darg->layout = init_decl_struct_layout(align, size);
}
- if (s->size < darg->layout->pos + darg->layout->len) {
- s->size = darg->layout->pos + darg->layout->len;
- /* FIXME: align struct */
+ if (len > size) {
+ size = len;
+ }
+ if (align > u->align) {
+ u->align = align;
}
}
- psi_sort_struct_args(s);
+ psi_sort_struct_args((void **) u->args->args, u->args->count);
+
+ if (u->size < size) {
+ u->size = psi_align(size, u->align);
+ }
return 1;
}
if (!decl->call.sym) {
data->error(func->token, PSI_WARNING,
"Failed to locate symbol '%s': %s",
- func->var->name, dlerror());
+ func->var->name, dlerror() ?: "not found");
}
}
return 1;
}
}
+ if (source->unions) for (i = 0; i < source->unions->count; ++i) {
+ decl_union *dunion = source->unions->list[i];
+
+ if (validate_decl_union(source, dunion)) {
+ if (dest) {
+ dest->unions = add_decl_union(dest->unions, dunion);
+ }
+ } else {
+ ++errors;
+ }
+ }
+
if (source->enums) for (i = 0; i < source->enums->count; ++i) {
decl_enum *denum = source->enums->list[i];
return ALIGNOF_DOUBLE;
case PSI_T_POINTER:
case PSI_T_FUNCTION:
- case PSI_T_STRUCT:
return ALIGNOF_VOID_P;
case PSI_T_ENUM:
return ALIGNOF_INT;
return 0;
}
-size_t psi_t_align(token_t t, size_t s)
-{
- size_t a = psi_t_alignment(t);
- return ((s - 1) | (a - 1)) + 1;
-}
-
-size_t psi_offset_padding(size_t diff, size_t alignment)
-{
- if (diff && diff <= ((diff - 1) | (alignment -1)) + 1) {
- diff = 0;
- }
-
- return diff;
-}
-
int psi_internal_type(impl_type *type)
{
switch (type->type) {
size_t psi_t_alignment(token_t t);
size_t psi_t_size(token_t t);
-size_t psi_t_align(token_t t, size_t s);
-size_t psi_offset_padding(size_t diff, size_t alignment);
+static inline size_t psi_align(size_t s, size_t a) {
+ return ((s - 1) | (a - 1)) + 1;
+}
+
+static inline size_t psi_offset_padding(size_t diff, size_t alignment) {
+ if (diff && diff <= psi_align(diff, alignment)) {
+ diff = 0;
+ }
+
+ return diff;
+}
+
int psi_internal_type(impl_type *type);
zend_internal_arg_info *psi_internal_arginfo(impl *impl);
size_t psi_num_min_args(impl *impl);
case PSI_T_BOOL:
return &ffi_type_uchar;
case PSI_T_INT:
+ case PSI_T_ENUM:
return &ffi_type_sint;
case PSI_T_LONG:
return &ffi_type_slong;
token_t type;
struct decl_type *real;
struct decl_struct *strct;
+ struct decl_union *unn;
struct decl_enum *enm;
struct decl *func;
} decl_type;
}
static inline void free_decl_arg(decl_arg *arg) {
+ if (arg->token && arg->token != arg->var->token) {
+ free(arg->token);
+ }
free_decl_type(arg->type);
free_decl_var(arg->var);
if (arg->layout) {
char *name;
decl_args *args;
size_t size;
+ size_t align;
struct {
void *type;
void (*dtor)(void *type);
free(ss);
}
+typedef struct decl_union {
+ PSI_Token *token;
+ char *name;
+ decl_args *args;
+ size_t size;
+ size_t align;
+} decl_union;
+
+static inline decl_union *init_decl_union(const char *name, decl_args *args) {
+ decl_union *u = calloc(1, sizeof(*u));
+ u->name = strdup(name);
+ u->args = args;
+ return u;
+}
+
+static inline void free_decl_union(decl_union *u) {
+ if (u->token) {
+ free(u->token);
+ }
+ if (u->args) {
+ free_decl_args(u->args);
+ }
+ free(u->name);
+ free(u);
+}
+
+typedef struct decl_unions {
+ decl_union **list;
+ size_t count;
+} decl_unions;
+
+static inline decl_unions *add_decl_union(decl_unions *uu, decl_union *u) {
+ if (!uu) {
+ uu = calloc(1, sizeof(*uu));
+ }
+ uu->list = realloc(uu->list, ++uu->count * sizeof(*uu->list));
+ uu->list[uu->count-1] = u;
+ return uu;
+}
+
+static inline void free_decl_unions(decl_unions *uu) {
+ size_t i;
+
+ for (i = 0; i < uu->count; ++i) {
+ free_decl_union(uu->list[i]);
+ }
+ free(uu->list);
+ free(uu);
+}
+
typedef struct impl_type {
char *name;
token_t type;
constants *consts; \
decl_typedefs *defs; \
decl_structs *structs; \
+ decl_unions *unions; \
decl_enums *enums; \
decls *decls; \
impls *impls; \
if (data->structs) {
free_decl_structs(data->structs);
}
+ if (data->unions) {
+ free_decl_unions(data->unions);
+ }
if (data->enums) {
free_decl_enums(data->enums);
}
#define PSI_T_RETURN 10
#define PSI_T_LIB 11
#define PSI_T_STRING 12
-#define PSI_T_STRUCT 13
-#define PSI_T_UNION 14
-#define PSI_T_EOF 15
-#define PSI_T_EOS 16
-#define PSI_T_QUOTED_STRING 17
-#define PSI_T_ENUM 18
-#define PSI_T_LBRACE 19
-#define PSI_T_RBRACE 20
-#define PSI_T_COMMA 21
-#define PSI_T_EQUALS 22
+#define PSI_T_EOF 13
+#define PSI_T_EOS 14
+#define PSI_T_QUOTED_STRING 15
+#define PSI_T_ENUM 16
+#define PSI_T_LBRACE 17
+#define PSI_T_RBRACE 18
+#define PSI_T_COMMA 19
+#define PSI_T_EQUALS 20
+#define PSI_T_UNION 21
+#define PSI_T_STRUCT 22
#define PSI_T_COLON 23
#define PSI_T_LPAREN 24
#define PSI_T_NUMBER 25
%left PLUS MINUS.
%left SLASH ASTERISK.
%fallback NAME TEMP FREE SET LET RETURN LIB STRING.
-%fallback STRUCT UNION.
file ::= blocks.
block ::= decl_struct(strct). {
P->structs = add_decl_struct(P->structs, strct);
}
+block ::= decl_union(u). {
+ P->unions = add_decl_union(P->unions, u);
+}
block ::= decl_enum(e). {
P->enums = add_decl_enum(P->enums, e);
}
optional_name(n) ::= NAME(N). {
n = N;
}
+
enum_name(n) ::= ENUM(E) optional_name(N). {
if (N) {
n = N;
i->token = N;
}
+union_name(n) ::= UNION(U) optional_name(N). {
+ if (N) {
+ n = N;
+ free(U);
+ } else {
+ char digest[17];
+
+ PSI_TokenHash(U, digest);
+ n = PSI_TokenTranslit(PSI_TokenAppend(U, 1, digest), " ", "@");
+ }
+}
+
struct_name(n) ::= STRUCT(S) optional_name(N). {
if (N) {
n = N;
%type decl_struct {decl_struct*}
%destructor decl_struct {free_decl_struct($$);}
-decl_struct(strct) ::= struct_name(N) struct_size(size_) decl_struct_args(args). {
+decl_struct(strct) ::= STRUCT NAME(N) struct_size(size_) decl_struct_args(args). {
strct = init_decl_struct(N->text, args);
strct->size = size_;
strct->token = N;
free(SIZ);
}
+%type decl_union {decl_union*}
+%destructor decl_union {free_decl_union($$);}
+decl_union(u) ::= UNION NAME(N) struct_size(size_) decl_struct_args(args). {
+ u = init_decl_union(N->text, args);
+ u->size = size_;
+ u->token = N;
+}
+
%token_class const_type_token BOOL INT FLOAT STRING.
%type const_type {const_type*}
%destructor const_type {free_const_type($$);}
if ($$->type->enm) {
free_decl_enum($$->type->enm);
}
+ if ($$->type->unn) {
+ free_decl_union($$->type->unn);
+ }
if ($$->type->func) {
free_decl($$->type->func);
}
def->type->strct->token = N;
def->type->strct->size = size_;
}
+decl_typedef_body_ex(def) ::= union_name(N) struct_size(size_) decl_struct_args_block(args) decl_var(var). {
+ def = init_decl_arg(init_decl_type(PSI_T_UNION, N->text), var);
+ def->type->token = PSI_TokenCopy(N);
+ def->type->unn = init_decl_union(N->text, args);
+ def->type->unn->token = N;
+ def->type->unn->size = size_;
+}
decl_typedef_body_ex(def) ::= decl_enum(e) NAME(ALIAS). {
def = init_decl_arg(init_decl_type(PSI_T_ENUM, e->name), init_decl_var(ALIAS->text, 0, 0));
def->var->token = ALIAS;
if ($$->type->enm) {
free_decl_enum($$->type->enm);
}
+ if ($$->type->unn) {
+ free_decl_union($$->type->unn);
+ }
if ($$->type->func) {
free_decl($$->type->func);
}
init_decl_var(N->text, 0, 0)
);
func->type->token = T;
- free(N);
+ func->var->token = N;
+ func->token = N;
}
%type decl_abi {decl_abi*}
args = add_decl_arg(args_, arg);
}
%type struct_arg {decl_arg*}
-%destructor struct_arg {free_decl_arg($$);}
+%destructor struct_arg {
+ free_decl_arg($$);
+ if ($$->type->strct) {
+ free_decl_struct($$->type->strct);
+ }
+ if ($$->type->enm) {
+ free_decl_enum($$->type->enm);
+ }
+ if ($$->type->func) {
+ free_decl($$->type->func);
+ }
+}
struct_arg(arg_) ::= decl_typedef_body_ex(def) EOS. {
arg_ = def;
+ if (def->type->strct) {
+ P->structs = add_decl_struct(P->structs, def->type->strct);
+ }
+ if (def->type->enm) {
+ P->enums = add_decl_enum(P->enums, def->type->enm);
+ }
}
struct_arg(arg) ::= decl_arg(arg_) struct_layout(layout_) EOS. {
arg_->layout = layout_;
type_->token = T;
free(S);
}
+decl_type(type_) ::= UNION(U) NAME(T). {
+ type_ = init_decl_type(U->type, T->text);
+ type_->token = T;
+ free(U);
+}
decl_type(type_) ::= ENUM(E) NAME(T). {
type_ = init_decl_type(E->type, T->text);
type_->token = T;
--SKIPIF--
<?php
extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\div") or die("skip - need psi\\div()");
?>
--FILE--
===TEST===
--SKIPIF--
<?php
extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\ldiv") or die("skip - need psi\\ldiv()");
?>
--FILE--
===TEST===
lldiv
--INI--
psi.directory={PWD}:{PWD}/../../psi.d
+display_startup_errors=0
--SKIPIF--
<?php
extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\lldiv") or die("skip - need psi\\lldiv()");
?>
--FILE--
===TEST===
var_dump(file_exists($fn));
var_dump(psi_validate($fn));
+@unlink(__DIR__."/dump.psi");
+
?>
===DONE===
--EXPECT--
bool(true)
bool(true)
===DONE===
---CLEAN--
-<?php
-@unlink(__DIR__."/dump.psi");
-?>
\ No newline at end of file