#include "report.h"
#include "token.h"
+static enum token_kind parsed_calling_convention = TOK_EOF;
+
static struct vector vec_dllexports = { 0 };
static int parsed_dllexport = 0;
static int current_function_return_size = DATA_NONE;
static int current_function_return_is_unsigned = 0;
static int current_function_returns_aggregate = 0;
+static int current_function_param_stack_bytes = 0;
+
+static enum token_kind current_function_calling_convention = TOK_EOF;
static struct local_symbol *pending_struct_return_lhs = 0;
static const char *pending_struct_return_global_name = 0;
static int declarator_pointer_depth = 0;
static int declarator_has_array = 0;
+static enum token_kind declarator_calling_convention = TOK_EOF;
+
static int global_initializer_accept_symbol_addresses = 0;
static void masm_flush_data_line (void);
char *tag_name;
char *owner_tag_name;
+ enum token_kind calling_convention;
int owner_size;
};
static const char *last_found_member_tag_name = 0;
static int last_found_member_is_unsigned = 0;
+static enum token_kind last_found_member_calling_convention = TOK_EOF;
+static enum token_kind postfix_member_calling_convention = TOK_EOF;
+
static int postfix_member_offset = 0;
static int postfix_member_size = 0;
member_infos[member_info_count].is_array = is_array;
member_infos[member_info_count].is_floating = is_floating ? 1 : 0;
member_infos[member_info_count].is_unsigned = parsed_type_is_unsigned ? 1 : 0;
+ member_infos[member_info_count].calling_convention = (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention;
member_infos[member_info_count].tag_name = parsed_type_tag_name[0] ? xstrdup (parsed_type_tag_name) : 0;
member_infos[member_info_count].owner_size = 0;
member_infos[member_info_count].owner_tag_name = 0;
last_found_member_tag_name = 0;
last_found_member_is_unsigned = 0;
+ last_found_member_calling_convention = TOK_EOF;
if (!name) {
return 0;
last_found_member_tag_name = member_infos[best].tag_name;
last_found_member_is_unsigned = member_infos[best].is_unsigned ? 1 : 0;
+ last_found_member_calling_convention = member_infos[best].calling_convention;
if (offset) {
*offset = member_infos[best].offset;
last_found_member_tag_name = 0;
last_found_member_is_unsigned = 0;
+ last_found_member_calling_convention = TOK_EOF;
if (!name) {
return 0;
last_found_member_tag_name = member_infos[best].tag_name;
last_found_member_is_unsigned = member_infos[best].is_unsigned ? 1 : 0;
+ last_found_member_calling_convention = member_infos[best].calling_convention;
if (offset) {
*offset = member_infos[best].offset;
char *tag_name;
long array_count;
+
+ enum token_kind calling_convention;
};
typedef_names[i].is_array = 0;
typedef_names[i].array_count = 1;
typedef_names[i].array_element_size = DATA_NONE;
+
+ typedef_names[i].calling_convention = TOK_EOF;
}
}
-static void save_typedef_name (const char *name, int size, int is_unsigned, int is_void, int is_aggregate, int is_array, long array_count, int array_element_size, const int *field_sizes, int field_count) {
+static void save_typedef_name (const char *name, int size, int is_unsigned, int is_void, int is_aggregate, int is_array, long array_count, int array_element_size, enum token_kind calling_convention, const int *field_sizes, int field_count) {
struct typedef_entry *entry;
int i;
entry = &typedef_names[typedef_name_count++];
entry->name = xstrdup (name);
entry->tag_name = 0;
+ entry->calling_convention = TOK_EOF;
}
entry->is_array = is_array ? 1 : 0;
entry->array_count = array_count > 0 ? array_count : 1;
entry->array_element_size = array_element_size > 0 ? array_element_size : DATA_INT;
+ entry->calling_convention = calling_convention;
for (i = 0; i < field_count && i < MAX_AGG_FIELDS; i++) {
entry->field_sizes[entry->field_count++] = field_sizes[i];
entry->is_array = 0;
entry->array_count = 1;
entry->array_element_size = DATA_NONE;
+ entry->calling_convention = TOK_EOF;
entry->field_count = 0;
if (entry->tag_name) {
parsed_type_is_array_typedef = 0;
parsed_type_array_count = 1;
parsed_type_array_element_size = DATA_NONE;
+ parsed_calling_convention = TOK_EOF;
append_parsed_field (DATA_INT & 0x1f);
return;
parsed_type_is_array_typedef = entry->is_array;
parsed_type_array_count = entry->array_count > 0 ? entry->array_count : 1;
parsed_type_array_element_size = entry->array_element_size > 0 ? entry->array_element_size : DATA_INT;
+ parsed_calling_convention = entry->calling_convention;
parsed_type_has_tag = 0;
parsed_type_tag_name[0] = '\0';
int is_implicit;
int extern_emitted;
+ enum token_kind calling_convention;
char *tag_name;
};
global_symbols[i].is_floating = 0;
global_symbols[i].returns_void = 0;
+ global_symbols[i].calling_convention = TOK_EOF;
+
{
int pi;
}
+static void set_global_symbol_calling_convention (const char *name, enum token_kind calling_convention) {
+
+ int i = find_global_symbol (name);
+
+ if (i >= 0) {
+ global_symbols[i].calling_convention = calling_convention;
+ }
+
+}
+
+static enum token_kind get_global_symbol_calling_convention (const char *name) {
+
+ int i = find_global_symbol (name);
+
+ if (i >= 0) {
+ return global_symbols[i].calling_convention;
+ }
+
+ return TOK_EOF;
+
+}
+
static int get_global_symbol_returns_void (const char *name) {
int i = find_global_symbol (name);
global_symbols[global_symbol_count].pointed_is_floating = 0;
global_symbols[global_symbol_count].pointed_is_unsigned = 0;
global_symbols[global_symbol_count].returns_void = 0;
+ global_symbols[global_symbol_count].calling_convention = TOK_EOF;
{
if (i >= 0) {
+ global_symbols[i].calling_convention = TOK_EOF;
global_symbols[i].size = DATA_INT & 0x1f;
global_symbols[i].is_unsigned = 0;
global_symbols[i].is_floating = 0;
parsed_type_is_void = 0;
parsed_type_only_qualifiers = 0;
parsed_type_size = DATA_NONE;
+ parsed_calling_convention = TOK_EOF;
clear_parsed_fields ();
tok.kind == TOK_SHORT || tok.kind == TOK_LONG || tok.kind == TOK_CHAR ||
tok.kind == TOK_INT || tok.kind == TOK_VOID || tok.kind == TOK_FLOAT ||
tok.kind == TOK_DOUBLE || tok.kind == TOK_INLINE || tok.kind == TOK_RESTRICT ||
- tok.kind == TOK_DLLEXPORT || token_is_ms_int_type_name ()) {
+ tok.kind == TOK_DLLEXPORT || tok.kind == TOK_STDCALL || token_is_ms_int_type_name ()) {
saw = 1;
saw_real_type = 1;
}
- if (tok.kind == TOK_DLLEXPORT) {
+ if (tok.kind == TOK_STDCALL) {
+
+ if (parsed_calling_convention == TOK_STDCALL) {
+ report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate '__stdcall'");
+ } else {
+ parsed_calling_convention = TOK_STDCALL;
+ }
+
+ } else if (tok.kind == TOK_DLLEXPORT) {
if (parsed_dllexport) {
report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate '__dllexport'");
} else if (is_type_start (tok.kind)) {
+ enum token_kind saved_calling_convention = declarator_calling_convention;
long saved_array_count = declarator_array_count;
int saved_type_size = parsed_type_size;
parsed_type_has_tag = saved_has_tag;
parsed_type_is_inline = saved_is_inline;
+ declarator_calling_convention = saved_calling_convention;
declarator_is_pointer = saved_is_pointer;
declarator_pointer_depth = saved_pointer_depth;
declarator_has_array = saved_has_array;
static void parse_declarator_inner (char **out_name) {
+ while (tok.kind == TOK_STDCALL) {
+
+ declarator_calling_convention = tok.kind;
+ get_token ();
+
+ }
+
while (tok.kind == TOK_STAR) {
declarator_is_pointer = 1;
get_token ();
- while (tok.kind == TOK_CONST || tok.kind == TOK_VOLATILE || tok.kind == TOK_RESTRICT) {
+ while (tok.kind == TOK_CONST || tok.kind == TOK_VOLATILE || tok.kind == TOK_RESTRICT || tok.kind == TOK_STDCALL) {
+
+ if (tok.kind == TOK_STDCALL) {
+ declarator_calling_convention = tok.kind;
+ }
+
get_token ();
+
}
}
const char *saved_captured_declarator_name_start = captured_declarator_name_start;
const char *saved_captured_declarator_name_caret = captured_declarator_name_caret;
+ enum token_kind saved_declarator_calling_convention = declarator_calling_convention;
unsigned long saved_captured_declarator_name_line = captured_declarator_name_line;
if (top_level) {
clear_pending_params ();
}
+ declarator_calling_convention = TOK_EOF;
capture_declarator_name_location = 1;
captured_declarator_name_location = 0;
captured_declarator_name_caret = saved_captured_declarator_name_caret;
captured_declarator_name_line = saved_captured_declarator_name_line;
+ } else {
+ declarator_calling_convention = saved_declarator_calling_convention;
}
}
}
fprintf (state->ofp, " leave\n");
- fprintf (state->ofp, " ret\n");
+
+ if (current_function_calling_convention == TOK_STDCALL && current_function_param_stack_bytes > 0) {
+ fprintf (state->ofp, " ret %d\n", current_function_param_stack_bytes);
+ } else {
+ fprintf (state->ofp, " ret\n");
+ }
} else {
}
fprintf (state->ofp, " leave\n");
- fprintf (state->ofp, " ret\n");
+
+ if (current_function_calling_convention == TOK_STDCALL && current_function_param_stack_bytes > 0) {
+
+ if (state->syntax & ASM_SYNTAX_INTEL) {
+ fprintf (state->ofp, " ret %d\n", current_function_param_stack_bytes);
+ } else {
+ fprintf (state->ofp, " ret $%d\n", current_function_param_stack_bytes);
+ }
+
+ } else {
+ fprintf (state->ofp, " ret\n");
+ }
}
(!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)),
(!declarator_is_pointer && declarator_has_array),
declarator_array_count, parsed_type_size,
- object_fields, object_field_count);
+ (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention,
+ object_fields, object_field_count);
} else if (name && parsed_storage_class == STORAGE_EXTERN) {
postfix_member_size = 0;
postfix_member_is_floating = 0;
postfix_member_is_unsigned = 0;
+
+ postfix_member_calling_convention = TOK_EOF;
{
postfix_member_size = size;
postfix_member_is_floating = is_floating;
postfix_member_is_unsigned = is_unsigned;
+ postfix_member_calling_convention = last_found_member_calling_convention;
if (pointer_depth > 0 || is_array) {
current_object_size = elem_size;
static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result_reg) {
+ enum token_kind saved_calling_convention = postfix_member_calling_convention;
+
int argc = 0;
int total_arg_bytes = 0;
int arg_bytes;
}
fprintf (state->ofp, " call ecx\n");
- fprintf (state->ofp, " add esp, %d\n", total_arg_bytes + (DATA_PTR & 0x1f));
+
+ if (saved_calling_convention == TOK_STDCALL) {
+ fprintf (state->ofp, " add esp, %d\n", (DATA_PTR & 0x1f));
+ } else {
+ fprintf (state->ofp, " add esp, %d\n", total_arg_bytes + (DATA_PTR & 0x1f));
+ }
if (strcmp (result_reg, "eax") != 0) {
fprintf (state->ofp, " mov %s, eax\n", result_reg);
fprintf (state->ofp, " movl %d(%%esp), %%ecx\n", total_arg_bytes);
fprintf (state->ofp, " call *%%ecx\n");
- fprintf (state->ofp, " addl $%d, %%esp\n", total_arg_bytes + (DATA_PTR & 0x1f));
+
+ if (saved_calling_convention == TOK_STDCALL) {
+ fprintf (state->ofp, " addl $%d, %%esp\n", (DATA_PTR & 0x1f));
+ } else {
+ fprintf (state->ofp, " addl $%d, %%esp\n", total_arg_bytes + (DATA_PTR & 0x1f));
+ }
if (strcmp (result_reg, "eax") != 0) {
fprintf (state->ofp, " movl %%eax, %%%s\n", result_reg);
fprintf (state->ofp, " call %s\n", asm_name);
}
- if (total_arg_bytes > 0) {
+ if (total_arg_bytes > 0 && get_global_symbol_calling_convention (name) != TOK_STDCALL) {
fprintf (state->ofp, " add esp, %d\n", total_arg_bytes);
}
fprintf (state->ofp, " call %s\n", asm_name);
}
- if (total_arg_bytes > 0) {
+ if (total_arg_bytes > 0 && get_global_symbol_calling_convention (name) != TOK_STDCALL) {
fprintf (state->ofp, " addl $%d, %%esp\n", total_arg_bytes);
}
if (tok.kind == TOK_LPAREN) {
+ enum token_kind member_calling_convention = last_found_member_calling_convention;
+
FILE **arg_tmp_ofps = 0;
FILE **new_arg_tmp_ofps;
FILE *arg_tmp_ofp;
}
fprintf (state->ofp, " call ecx\n");
- fprintf (state->ofp, " add esp, %d\n", total_arg_bytes + (DATA_PTR & 0x1f));
+
+ if (member_calling_convention == TOK_STDCALL) {
+ fprintf (state->ofp, " add esp, %d\n", (DATA_PTR & 0x1f));
+ } else {
+ fprintf (state->ofp, " add esp, %d\n", total_arg_bytes + (DATA_PTR & 0x1f));
+ }
} else {
fprintf (state->ofp, " movl %d(%%esp), %%ecx\n", total_arg_bytes);
fprintf (state->ofp, " call *%%ecx\n");
- fprintf (state->ofp, " addl $%d, %%esp\n", total_arg_bytes + (DATA_PTR & 0x1f));
+
+ if (member_calling_convention == TOK_STDCALL) {
+ fprintf (state->ofp, " addl $%d, %%esp\n", (DATA_PTR & 0x1f));
+ } else {
+ fprintf (state->ofp, " addl $%d, %%esp\n", total_arg_bytes + (DATA_PTR & 0x1f));
+ }
}
return 0;
}
- if ((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|')) {
- p += 2;
- } else {
- return 0;
- }
-
- while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
- p++;
- }
-
- if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
- return 0;
- }
-
- while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
- p++;
- }
-
- while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
- p++;
- }
-
- if (*p == '(') {
- return 0;
- }
-
for (;;) {
- if (*p == '.') {
- p++;
- } else if (p[0] == '-' && p[1] == '>') {
+ if ((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|')) {
p += 2;
} else {
- break;
+ return 0;
}
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
p++;
}
+
+ if (*p == '(') {
+ return 0;
+ }
+
+ for (;;) {
+
+ if (*p == '.') {
+ p++;
+ } else if (p[0] == '-' && p[1] == '>') {
+ p += 2;
+ } else {
+ break;
+ }
+
+ while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+ p++;
+ }
+
+ if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+ return 0;
+ }
+
+ while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+ p++;
+ }
+
+ while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+ p++;
+ }
+
+ }
+
+ if ((p[0] == '=' && p[1] == '=') || (p[0] == '!' && p[1] == '=') ||
+ (p[0] == '<' && p[1] == '=') || (p[0] == '>' && p[1] == '=')) {
+ p += 2;
+ } else if (*p == '<' || *p == '>') {
+ p++;
+ } else {
+ return 0;
+ }
+
+ while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+ p++;
+ }
+
+ if (!source_condition_skip_rhs_const_or_enum_now (&p)) {
+ return 0;
+ }
+
+ while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+ p++;
+ }
+
+ if (source_condition_tail_end_now (p)) {
+ return 1;
+ }
+
+ if (!((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|'))) {
+ return 0;
+ }
}
-
- if ((p[0] == '=' && p[1] == '=') || (p[0] == '!' && p[1] == '=') ||
- (p[0] == '<' && p[1] == '=') || (p[0] == '>' && p[1] == '=')) {
- p += 2;
- } else if (*p == '<' || *p == '>') {
- p++;
- } else {
- return 0;
- }
-
- while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
- p++;
- }
-
- if (!source_condition_skip_rhs_const_or_enum_now (&p)) {
- return 0;
- }
-
- return 1;
}
set_global_symbol_unsigned (name, 0);
set_global_symbol_floating (name, return_is_floating);
set_global_symbol_returns_void (name, return_is_void);
+ set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
set_global_symbol_param_count (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0, saved_declarator_function_is_variadic);
if (is_inline) {
current_function_return_is_unsigned = return_is_unsigned;
current_function_return_size = return_size;
current_function_returns_aggregate = (!return_is_void && !return_is_floating && return_size > (DATA_LLONG & 0x1f));
+ current_function_calling_convention = (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention;
+ current_function_param_stack_bytes = saved_declarator_function_param_count * (DATA_PTR & 0x1f);
current_function_has_return_statement = 0;
parse_old_style_param_decls ();
(!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)),
(!declarator_is_pointer && declarator_has_array),
declarator_array_count, parsed_type_size,
- object_fields, object_field_count);
+ (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention,
+ object_fields, object_field_count);
}