blob: 698ef6451ec7db3e528fd3d83d019b482a400311 [file] [log] [blame]
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#define _CFFI_INTERNAL
#include "../cffi/parse_c_type.h"
enum token_e {
TOK_STAR='*',
TOK_OPEN_PAREN='(',
TOK_CLOSE_PAREN=')',
TOK_OPEN_BRACKET='[',
TOK_CLOSE_BRACKET=']',
TOK_COMMA=',',
TOK_START=256,
TOK_END,
TOK_ERROR,
TOK_IDENTIFIER,
TOK_INTEGER,
TOK_DOTDOTDOT,
/* keywords */
TOK__BOOL,
TOK_CHAR,
TOK__COMPLEX,
TOK_CONST,
TOK_DOUBLE,
TOK_ENUM,
TOK_FLOAT,
//TOK__IMAGINARY,
TOK_INT,
TOK_LONG,
TOK_SHORT,
TOK_SIGNED,
TOK_STRUCT,
TOK_UNION,
TOK_UNSIGNED,
TOK_VOID,
TOK_VOLATILE,
TOK_CDECL,
TOK_STDCALL,
};
typedef struct {
struct _cffi_parse_info_s *info;
const char *input, *p;
size_t size; // the next token is at 'p' and of length 'size'
enum token_e kind;
_cffi_opcode_t *output;
size_t output_index;
} token_t;
static int is_space(char x)
{
return (x == ' ' || x == '\f' || x == '\n' || x == '\r' ||
x == '\t' || x == '\v');
}
static int is_ident_first(char x)
{
return (('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z') || x == '_' ||
x == '$'); /* '$' in names is supported here, for the struct
names invented by cparser */
}
static int is_digit(char x)
{
return ('0' <= x && x <= '9');
}
static int is_hex_digit(char x)
{
return (('0' <= x && x <= '9') ||
('A' <= x && x <= 'F') ||
('a' <= x && x <= 'f'));
}
static int is_ident_next(char x)
{
return (is_ident_first(x) || is_digit(x));
}
static char get_following_char(token_t *tok)
{
const char *p = tok->p + tok->size;
if (tok->kind == TOK_ERROR)
return 0;
while (is_space(*p))
p++;
return *p;
}
static int number_of_commas(token_t *tok)
{
const char *p = tok->p;
int result = 0;
int nesting = 0;
while (1) {
switch (*p++) {
case ',': result += !nesting; break;
case '(': nesting++; break;
case ')': if ((--nesting) < 0) return result; break;
case 0: return result;
default: break;
}
}
}
static void next_token(token_t *tok)
{
const char *p = tok->p + tok->size;
if (tok->kind == TOK_ERROR)
return;
while (!is_ident_first(*p)) {
if (is_space(*p)) {
p++;
}
else if (is_digit(*p)) {
tok->kind = TOK_INTEGER;
tok->p = p;
tok->size = 1;
if (p[1] == 'x' || p[1] == 'X')
tok->size = 2;
while (is_hex_digit(p[tok->size]))
tok->size++;
return;
}
else if (p[0] == '.' && p[1] == '.' && p[2] == '.') {
tok->kind = TOK_DOTDOTDOT;
tok->p = p;
tok->size = 3;
return;
}
else if (*p) {
tok->kind = *p;
tok->p = p;
tok->size = 1;
return;
}
else {
tok->kind = TOK_END;
tok->p = p;
tok->size = 0;
return;
}
}
tok->kind = TOK_IDENTIFIER;
tok->p = p;
tok->size = 1;
while (is_ident_next(p[tok->size]))
tok->size++;
switch (*p) {
case '_':
if (tok->size == 5 && !memcmp(p, "_Bool", 5)) tok->kind = TOK__BOOL;
if (tok->size == 7 && !memcmp(p,"__cdecl",7)) tok->kind = TOK_CDECL;
if (tok->size == 9 && !memcmp(p,"__stdcall",9))tok->kind = TOK_STDCALL;
if (tok->size == 8 && !memcmp(p,"_Complex",8)) tok->kind = TOK__COMPLEX;
break;
case 'c':
if (tok->size == 4 && !memcmp(p, "char", 4)) tok->kind = TOK_CHAR;
if (tok->size == 5 && !memcmp(p, "const", 5)) tok->kind = TOK_CONST;
break;
case 'd':
if (tok->size == 6 && !memcmp(p, "double", 6)) tok->kind = TOK_DOUBLE;
break;
case 'e':
if (tok->size == 4 && !memcmp(p, "enum", 4)) tok->kind = TOK_ENUM;
break;
case 'f':
if (tok->size == 5 && !memcmp(p, "float", 5)) tok->kind = TOK_FLOAT;
break;
case 'i':
if (tok->size == 3 && !memcmp(p, "int", 3)) tok->kind = TOK_INT;
break;
case 'l':
if (tok->size == 4 && !memcmp(p, "long", 4)) tok->kind = TOK_LONG;
break;
case 's':
if (tok->size == 5 && !memcmp(p, "short", 5)) tok->kind = TOK_SHORT;
if (tok->size == 6 && !memcmp(p, "signed", 6)) tok->kind = TOK_SIGNED;
if (tok->size == 6 && !memcmp(p, "struct", 6)) tok->kind = TOK_STRUCT;
break;
case 'u':
if (tok->size == 5 && !memcmp(p, "union", 5)) tok->kind = TOK_UNION;
if (tok->size == 8 && !memcmp(p,"unsigned",8)) tok->kind = TOK_UNSIGNED;
break;
case 'v':
if (tok->size == 4 && !memcmp(p, "void", 4)) tok->kind = TOK_VOID;
if (tok->size == 8 && !memcmp(p,"volatile",8)) tok->kind = TOK_VOLATILE;
break;
}
}
static int parse_error(token_t *tok, const char *msg)
{
if (tok->kind != TOK_ERROR) {
tok->kind = TOK_ERROR;
tok->info->error_location = tok->p - tok->input;
tok->info->error_message = msg;
}
return -1;
}
static int write_ds(token_t *tok, _cffi_opcode_t ds)
{
size_t index = tok->output_index;
if (index >= tok->info->output_size) {
parse_error(tok, "internal type complexity limit reached");
return -1;
}
tok->output[index] = ds;
tok->output_index = index + 1;
return index;
}
#define MAX_SSIZE_T (((size_t)-1) >> 1)
static int parse_complete(token_t *tok);
static const char *get_common_type(const char *search, size_t search_len);
static int parse_common_type_replacement(token_t *tok, const char *replacement);
static int parse_sequel(token_t *tok, int outer)
{
/* Emit opcodes for the "sequel", which is the optional part of a
type declaration that follows the type name, i.e. everything
with '*', '[ ]', '( )'. Returns the entry point index pointing
the innermost opcode (the one that corresponds to the complete
type). The 'outer' argument is the index of the opcode outside
this "sequel".
*/
int check_for_grouping, abi=0;
_cffi_opcode_t result, *p_current;
header:
switch (tok->kind) {
case TOK_STAR:
outer = write_ds(tok, _CFFI_OP(_CFFI_OP_POINTER, outer));
next_token(tok);
goto header;
case TOK_CONST:
/* ignored for now */
next_token(tok);
goto header;
case TOK_VOLATILE:
/* ignored for now */
next_token(tok);
goto header;
case TOK_CDECL:
case TOK_STDCALL:
/* must be in a function; checked below */
abi = tok->kind;
next_token(tok);
goto header;
default:
break;
}
check_for_grouping = 1;
if (tok->kind == TOK_IDENTIFIER) {
next_token(tok); /* skip a potential variable name */
check_for_grouping = 0;
}
result = 0;
p_current = &result;
while (tok->kind == TOK_OPEN_PAREN) {
next_token(tok);
if (tok->kind == TOK_CDECL || tok->kind == TOK_STDCALL) {
abi = tok->kind;
next_token(tok);
}
if ((check_for_grouping--) == 1 && (tok->kind == TOK_STAR ||
tok->kind == TOK_CONST ||
tok->kind == TOK_VOLATILE ||
tok->kind == TOK_OPEN_BRACKET)) {
/* just parentheses for grouping. Use a OP_NOOP to simplify */
int x;
assert(p_current == &result);
x = tok->output_index;
p_current = tok->output + x;
write_ds(tok, _CFFI_OP(_CFFI_OP_NOOP, 0));
x = parse_sequel(tok, x);
result = _CFFI_OP(_CFFI_GETOP(0), x);
}
else {
/* function type */
int arg_total, base_index, arg_next, flags=0;
if (abi == TOK_STDCALL) {
flags = 2;
/* note that an ellipsis below will overwrite this flags,
which is the goal: variadic functions are always cdecl */
}
abi = 0;
if (tok->kind == TOK_VOID && get_following_char(tok) == ')') {
next_token(tok);
}
/* (over-)estimate 'arg_total'. May return 1 when it is really 0 */
arg_total = number_of_commas(tok) + 1;
*p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index);
p_current = tok->output + tok->output_index;
base_index = write_ds(tok, _CFFI_OP(_CFFI_OP_FUNCTION, 0));
if (base_index < 0)
return -1;
/* reserve (arg_total + 1) slots for the arguments and the
final FUNCTION_END */
for (arg_next = 0; arg_next <= arg_total; arg_next++)
if (write_ds(tok, _CFFI_OP(0, 0)) < 0)
return -1;
arg_next = base_index + 1;
if (tok->kind != TOK_CLOSE_PAREN) {
while (1) {
int arg;
_cffi_opcode_t oarg;
if (tok->kind == TOK_DOTDOTDOT) {
flags = 1; /* ellipsis */
next_token(tok);
break;
}
arg = parse_complete(tok);
switch (_CFFI_GETOP(tok->output[arg])) {
case _CFFI_OP_ARRAY:
case _CFFI_OP_OPEN_ARRAY:
arg = _CFFI_GETARG(tok->output[arg]);
/* fall-through */
case _CFFI_OP_FUNCTION:
oarg = _CFFI_OP(_CFFI_OP_POINTER, arg);
break;
default:
oarg = _CFFI_OP(_CFFI_OP_NOOP, arg);
break;
}
assert(arg_next - base_index <= arg_total);
tok->output[arg_next++] = oarg;
if (tok->kind != TOK_COMMA)
break;
next_token(tok);
}
}
tok->output[arg_next] = _CFFI_OP(_CFFI_OP_FUNCTION_END, flags);
}
if (tok->kind != TOK_CLOSE_PAREN)
return parse_error(tok, "expected ')'");
next_token(tok);
}
if (abi != 0)
return parse_error(tok, "expected '('");
while (tok->kind == TOK_OPEN_BRACKET) {
*p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index);
p_current = tok->output + tok->output_index;
next_token(tok);
if (tok->kind != TOK_CLOSE_BRACKET) {
size_t length;
int gindex;
char *endptr;
switch (tok->kind) {
case TOK_INTEGER:
errno = 0;
if (sizeof(length) > sizeof(unsigned long)) {
#ifdef MS_WIN32
# ifdef _WIN64
length = _strtoui64(tok->p, &endptr, 0);
# else
abort(); /* unreachable */
# endif
#else
length = strtoull(tok->p, &endptr, 0);
#endif
}
else
length = strtoul(tok->p, &endptr, 0);
if (endptr != tok->p + tok->size)
return parse_error(tok, "invalid number");
if (errno == ERANGE || length > MAX_SSIZE_T)
return parse_error(tok, "number too large");
break;
case TOK_IDENTIFIER:
gindex = search_in_globals(tok->info->ctx, tok->p, tok->size);
if (gindex >= 0) {
const struct _cffi_global_s *g;
g = &tok->info->ctx->globals[gindex];
if (_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT_INT ||
_CFFI_GETOP(g->type_op) == _CFFI_OP_ENUM) {
int neg;
struct _cffi_getconst_s gc;
gc.ctx = tok->info->ctx;
gc.gindex = gindex;
neg = ((int(*)(struct _cffi_getconst_s*))g->address)
(&gc);
if (neg == 0 && gc.value > MAX_SSIZE_T)
return parse_error(tok,
"integer constant too large");
if (neg == 0 || gc.value == 0) {
length = (size_t)gc.value;
break;
}
if (neg != 1)
return parse_error(tok, "disagreement about"
" this constant's value");
}
}
/* fall-through to the default case */
default:
return parse_error(tok, "expected a positive integer constant");
}
next_token(tok);
write_ds(tok, _CFFI_OP(_CFFI_OP_ARRAY, 0));
write_ds(tok, (_cffi_opcode_t)length);
}
else
write_ds(tok, _CFFI_OP(_CFFI_OP_OPEN_ARRAY, 0));
if (tok->kind != TOK_CLOSE_BRACKET)
return parse_error(tok, "expected ']'");
next_token(tok);
}
*p_current = _CFFI_OP(_CFFI_GETOP(*p_current), outer);
return _CFFI_GETARG(result);
}
static int search_sorted(const char *const *base,
size_t item_size, int array_len,
const char *search, size_t search_len)
{
int left = 0, right = array_len;
const char *baseptr = (const char *)base;
while (left < right) {
int middle = (left + right) / 2;
const char *src = *(const char *const *)(baseptr + middle * item_size);
int diff = strncmp(src, search, search_len);
if (diff == 0 && src[search_len] == '\0')
return middle;
else if (diff >= 0)
right = middle;
else
left = middle + 1;
}
return -1;
}
#define MAKE_SEARCH_FUNC(FIELD) \
static \
int search_in_##FIELD(const struct _cffi_type_context_s *ctx, \
const char *search, size_t search_len) \
{ \
return search_sorted(&ctx->FIELD->name, sizeof(*ctx->FIELD), \
ctx->num_##FIELD, search, search_len); \
}
MAKE_SEARCH_FUNC(globals)
MAKE_SEARCH_FUNC(struct_unions)
MAKE_SEARCH_FUNC(typenames)
MAKE_SEARCH_FUNC(enums)
#undef MAKE_SEARCH_FUNC
static
int search_standard_typename(const char *p, size_t size)
{
if (size < 6 || p[size-2] != '_' || p[size-1] != 't')
return -1;
switch (p[4]) {
case '1':
if (size == 8 && !memcmp(p, "uint16", 6)) return _CFFI_PRIM_UINT16;
if (size == 8 && !memcmp(p, "char16", 6)) return _CFFI_PRIM_CHAR16;
break;
case '2':
if (size == 7 && !memcmp(p, "int32", 5)) return _CFFI_PRIM_INT32;
break;
case '3':
if (size == 8 && !memcmp(p, "uint32", 6)) return _CFFI_PRIM_UINT32;
if (size == 8 && !memcmp(p, "char32", 6)) return _CFFI_PRIM_CHAR32;
break;
case '4':
if (size == 7 && !memcmp(p, "int64", 5)) return _CFFI_PRIM_INT64;
break;
case '6':
if (size == 8 && !memcmp(p, "uint64", 6)) return _CFFI_PRIM_UINT64;
if (size == 7 && !memcmp(p, "int16", 5)) return _CFFI_PRIM_INT16;
break;
case '8':
if (size == 7 && !memcmp(p, "uint8", 5)) return _CFFI_PRIM_UINT8;
break;
case 'a':
if (size == 8 && !memcmp(p, "intmax", 6)) return _CFFI_PRIM_INTMAX;
break;
case 'e':
if (size == 7 && !memcmp(p, "ssize", 5)) return _CFFI_PRIM_SSIZE;
break;
case 'f':
if (size == 11 && !memcmp(p, "int_fast8", 9)) return _CFFI_PRIM_INT_FAST8;
if (size == 12 && !memcmp(p, "int_fast16", 10)) return _CFFI_PRIM_INT_FAST16;
if (size == 12 && !memcmp(p, "int_fast32", 10)) return _CFFI_PRIM_INT_FAST32;
if (size == 12 && !memcmp(p, "int_fast64", 10)) return _CFFI_PRIM_INT_FAST64;
break;
case 'i':
if (size == 9 && !memcmp(p, "ptrdiff", 7)) return _CFFI_PRIM_PTRDIFF;
break;
case 'l':
if (size == 12 && !memcmp(p, "int_least8", 10)) return _CFFI_PRIM_INT_LEAST8;
if (size == 13 && !memcmp(p, "int_least16", 11)) return _CFFI_PRIM_INT_LEAST16;
if (size == 13 && !memcmp(p, "int_least32", 11)) return _CFFI_PRIM_INT_LEAST32;
if (size == 13 && !memcmp(p, "int_least64", 11)) return _CFFI_PRIM_INT_LEAST64;
break;
case 'm':
if (size == 9 && !memcmp(p, "uintmax", 7)) return _CFFI_PRIM_UINTMAX;
break;
case 'p':
if (size == 9 && !memcmp(p, "uintptr", 7)) return _CFFI_PRIM_UINTPTR;
break;
case 'r':
if (size == 7 && !memcmp(p, "wchar", 5)) return _CFFI_PRIM_WCHAR;
break;
case 't':
if (size == 8 && !memcmp(p, "intptr", 6)) return _CFFI_PRIM_INTPTR;
break;
case '_':
if (size == 6 && !memcmp(p, "size", 4)) return _CFFI_PRIM_SIZE;
if (size == 6 && !memcmp(p, "int8", 4)) return _CFFI_PRIM_INT8;
if (size >= 12) {
switch (p[10]) {
case '1':
if (size == 14 && !memcmp(p, "uint_least16", 12)) return _CFFI_PRIM_UINT_LEAST16;
break;
case '2':
if (size == 13 && !memcmp(p, "uint_fast32", 11)) return _CFFI_PRIM_UINT_FAST32;
break;
case '3':
if (size == 14 && !memcmp(p, "uint_least32", 12)) return _CFFI_PRIM_UINT_LEAST32;
break;
case '4':
if (size == 13 && !memcmp(p, "uint_fast64", 11)) return _CFFI_PRIM_UINT_FAST64;
break;
case '6':
if (size == 14 && !memcmp(p, "uint_least64", 12)) return _CFFI_PRIM_UINT_LEAST64;
if (size == 13 && !memcmp(p, "uint_fast16", 11)) return _CFFI_PRIM_UINT_FAST16;
break;
case '8':
if (size == 13 && !memcmp(p, "uint_least8", 11)) return _CFFI_PRIM_UINT_LEAST8;
break;
case '_':
if (size == 12 && !memcmp(p, "uint_fast8", 10)) return _CFFI_PRIM_UINT_FAST8;
break;
default:
break;
}
}
break;
default:
break;
}
return -1;
}
static int parse_complete(token_t *tok)
{
unsigned int t0;
_cffi_opcode_t t1;
_cffi_opcode_t t1complex;
int modifiers_length, modifiers_sign;
qualifiers:
switch (tok->kind) {
case TOK_CONST:
/* ignored for now */
next_token(tok);
goto qualifiers;
case TOK_VOLATILE:
/* ignored for now */
next_token(tok);
goto qualifiers;
default:
;
}
modifiers_length = 0;
modifiers_sign = 0;
modifiers:
switch (tok->kind) {
case TOK_SHORT:
if (modifiers_length != 0)
return parse_error(tok, "'short' after another 'short' or 'long'");
modifiers_length--;
next_token(tok);
goto modifiers;
case TOK_LONG:
if (modifiers_length < 0)
return parse_error(tok, "'long' after 'short'");
if (modifiers_length >= 2)
return parse_error(tok, "'long long long' is too long");
modifiers_length++;
next_token(tok);
goto modifiers;
case TOK_SIGNED:
if (modifiers_sign)
return parse_error(tok, "multiple 'signed' or 'unsigned'");
modifiers_sign++;
next_token(tok);
goto modifiers;
case TOK_UNSIGNED:
if (modifiers_sign)
return parse_error(tok, "multiple 'signed' or 'unsigned'");
modifiers_sign--;
next_token(tok);
goto modifiers;
default:
break;
}
t1complex = 0;
if (modifiers_length || modifiers_sign) {
switch (tok->kind) {
case TOK_VOID:
case TOK__BOOL:
case TOK_FLOAT:
case TOK_STRUCT:
case TOK_UNION:
case TOK_ENUM:
case TOK__COMPLEX:
return parse_error(tok, "invalid combination of types");
case TOK_DOUBLE:
if (modifiers_sign != 0 || modifiers_length != 1)
return parse_error(tok, "invalid combination of types");
next_token(tok);
t0 = _CFFI_PRIM_LONGDOUBLE;
break;
case TOK_CHAR:
if (modifiers_length != 0)
return parse_error(tok, "invalid combination of types");
modifiers_length = -2;
/* fall-through */
case TOK_INT:
next_token(tok);
/* fall-through */
default:
if (modifiers_sign >= 0)
switch (modifiers_length) {
case -2: t0 = _CFFI_PRIM_SCHAR; break;
case -1: t0 = _CFFI_PRIM_SHORT; break;
case 1: t0 = _CFFI_PRIM_LONG; break;
case 2: t0 = _CFFI_PRIM_LONGLONG; break;
default: t0 = _CFFI_PRIM_INT; break;
}
else
switch (modifiers_length) {
case -2: t0 = _CFFI_PRIM_UCHAR; break;
case -1: t0 = _CFFI_PRIM_USHORT; break;
case 1: t0 = _CFFI_PRIM_ULONG; break;
case 2: t0 = _CFFI_PRIM_ULONGLONG; break;
default: t0 = _CFFI_PRIM_UINT; break;
}
}
t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, t0);
}
else {
switch (tok->kind) {
case TOK_INT:
t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_INT);
break;
case TOK_CHAR:
t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_CHAR);
break;
case TOK_VOID:
t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_VOID);
break;
case TOK__BOOL:
t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_BOOL);
break;
case TOK_FLOAT:
t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOAT);
t1complex = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOATCOMPLEX);
break;
case TOK_DOUBLE:
t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLE);
t1complex = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLECOMPLEX);
break;
case TOK_IDENTIFIER:
{
const char *replacement;
int n = search_in_typenames(tok->info->ctx, tok->p, tok->size);
if (n >= 0) {
t1 = _CFFI_OP(_CFFI_OP_TYPENAME, n);
break;
}
n = search_standard_typename(tok->p, tok->size);
if (n >= 0) {
t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, n);
break;
}
replacement = get_common_type(tok->p, tok->size);
if (replacement != NULL) {
n = parse_common_type_replacement(tok, replacement);
if (n < 0)
return parse_error(tok, "internal error, please report!");
t1 = _CFFI_OP(_CFFI_OP_NOOP, n);
break;
}
return parse_error(tok, "undefined type name");
}
case TOK_STRUCT:
case TOK_UNION:
{
int n, kind = tok->kind;
next_token(tok);
if (tok->kind != TOK_IDENTIFIER)
return parse_error(tok, "struct or union name expected");
n = search_in_struct_unions(tok->info->ctx, tok->p, tok->size);
if (n < 0) {
if (kind == TOK_STRUCT && tok->size == 8 &&
!memcmp(tok->p, "_IO_FILE", 8))
n = _CFFI__IO_FILE_STRUCT;
else
return parse_error(tok, "undefined struct/union name");
}
else if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION)
!= 0) ^ (kind == TOK_UNION))
return parse_error(tok, "wrong kind of tag: struct vs union");
t1 = _CFFI_OP(_CFFI_OP_STRUCT_UNION, n);
break;
}
case TOK_ENUM:
{
int n;
next_token(tok);
if (tok->kind != TOK_IDENTIFIER)
return parse_error(tok, "enum name expected");
n = search_in_enums(tok->info->ctx, tok->p, tok->size);
if (n < 0)
return parse_error(tok, "undefined enum name");
t1 = _CFFI_OP(_CFFI_OP_ENUM, n);
break;
}
default:
return parse_error(tok, "identifier expected");
}
next_token(tok);
}
if (tok->kind == TOK__COMPLEX)
{
if (t1complex == 0)
return parse_error(tok, "_Complex type combination unsupported");
t1 = t1complex;
next_token(tok);
}
return parse_sequel(tok, write_ds(tok, t1));
}
static
int parse_c_type_from(struct _cffi_parse_info_s *info, size_t *output_index,
const char *input)
{
int result;
token_t token;
token.info = info;
token.kind = TOK_START;
token.input = input;
token.p = input;
token.size = 0;
token.output = info->output;
token.output_index = *output_index;
next_token(&token);
result = parse_complete(&token);
*output_index = token.output_index;
if (token.kind != TOK_END)
return parse_error(&token, "unexpected symbol");
return result;
}
static
int parse_c_type(struct _cffi_parse_info_s *info, const char *input)
{
size_t output_index = 0;
return parse_c_type_from(info, &output_index, input);
}
static
int parse_common_type_replacement(token_t *tok, const char *replacement)
{
return parse_c_type_from(tok->info, &tok->output_index, replacement);
}