1ccfcf0760
* NEW: The form editor has a new menu entry for transforming a control into another control. For example, a Label into a TextLabel, or a HBox into a VBox, and so on. The possible transformations are defined in the *.component file. * BUG: Compiler errors that are not related to the compiled code are now correctly displayed. * BUG: Locked forms are correctly loaded, and the form tab title now correctly shows the associated read-only state. * BUG: The automatic completion can deal with multiple local variable declarations on the same line now. [INTERPRETER] * BUG: Array.Insert() does not crash anymore if the inserted array is NULL. It raises an error now. [COMPILER] * BUG: The owner and group of all files generated by the compiler ('.startup', '.info', '.list', object files) are now set to the owner and group of the '.project' file. This way, any project can be safely compiled as root, without locking it for other users. git-svn-id: svn://localhost/gambas/trunk@1369 867c0c6c-44f3-4631-809d-bfa615b0a4ec
1311 lines
24 KiB
C
1311 lines
24 KiB
C
/***************************************************************************
|
||
|
||
output.c
|
||
|
||
The object file creator
|
||
|
||
(c) 2000-2007 Benoit Minisini <gambas@users.sourceforge.net>
|
||
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 1, or (at your option)
|
||
any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
||
***************************************************************************/
|
||
|
||
#define __GBC_OUTPUT_C
|
||
|
||
#include "gb_common.h"
|
||
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <fcntl.h>
|
||
#include <unistd.h>
|
||
#include <ctype.h>
|
||
|
||
#include "config.h"
|
||
|
||
#include "gb_error.h"
|
||
#include "gb_alloc.h"
|
||
#include "gb_str.h"
|
||
#include "gb_file.h"
|
||
#include "gb_common_swap.h"
|
||
#include "gb_magic.h"
|
||
#include "gbc_chown.h"
|
||
#include "gbc_compile.h"
|
||
|
||
#include "gbc_output.h"
|
||
|
||
|
||
/*#define DEBUG*/
|
||
/*#define DEBUG_MORE*/
|
||
|
||
static CLASS *Class;
|
||
|
||
static int StringAddr;
|
||
static TABLE *StringTable;
|
||
static int NSection;
|
||
static int PosStartSection;
|
||
static int SizeSection;
|
||
|
||
static bool _swap;
|
||
|
||
static FILE *_file;
|
||
|
||
static int _pos;
|
||
static char _buffer[OUTPUT_BUFFER_SIZE + 8];
|
||
static const char * const _mbuffer = &_buffer[OUTPUT_BUFFER_SIZE];
|
||
static char *_pbuffer;
|
||
|
||
static OUTPUT_CHANGE *_change = NULL;
|
||
|
||
|
||
static void output_init(void)
|
||
{
|
||
TABLE_create(&StringTable, sizeof(OUTPUT_SYMBOL), TF_NORMAL);
|
||
StringAddr = 0;
|
||
NSection = 0;
|
||
_pos = 0;
|
||
_pbuffer = _buffer;
|
||
|
||
ARRAY_create(&_change);
|
||
}
|
||
|
||
|
||
static void output_exit(void)
|
||
{
|
||
TABLE_delete(&StringTable);
|
||
ARRAY_delete(&_change);
|
||
}
|
||
|
||
|
||
static int get_string(const char *string, int len)
|
||
{
|
||
OUTPUT_SYMBOL *sym;
|
||
|
||
if (len < 0)
|
||
len = strlen(string);
|
||
|
||
if (!TABLE_add_symbol(StringTable, string, len, (SYMBOL **)(void *)&sym, NULL))
|
||
{
|
||
sym->value = StringAddr;
|
||
StringAddr += len + 1;
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
printf("'%.*s' -> %ld\n", len, string, sym->value);
|
||
#endif
|
||
|
||
return sym->value;
|
||
}
|
||
|
||
#define get_pos() (_pos)
|
||
|
||
static void flush_buffer(void)
|
||
{
|
||
size_t len = _pbuffer - _buffer;
|
||
|
||
if (len <= 0)
|
||
return;
|
||
|
||
if (fwrite(_buffer, sizeof(char), len, _file) != len)
|
||
THROW("Write error");
|
||
|
||
_pbuffer = _buffer;
|
||
}
|
||
|
||
|
||
static void write_byte(unsigned char val)
|
||
{
|
||
#ifdef DEBUG_MORE
|
||
printf("%ld : b %u 0x%X\n", get_pos(), val, val);
|
||
#endif
|
||
|
||
if (_pbuffer >= _mbuffer)
|
||
flush_buffer();
|
||
|
||
*_pbuffer++ = val;
|
||
_pos++;
|
||
|
||
/*if (fwrite(&val, sizeof(char), 1, _file) != 1)
|
||
THROW("Write error");*/
|
||
}
|
||
|
||
|
||
static void write_short(ushort val)
|
||
{
|
||
#ifdef DEBUG_MORE
|
||
printf("%ld : i %u 0x%X\n", get_pos(), val, val);
|
||
#endif
|
||
|
||
if (_swap)
|
||
SWAP_short((short *)&val);
|
||
|
||
if (_pbuffer >= _mbuffer)
|
||
flush_buffer();
|
||
|
||
*((ushort *)_pbuffer) = val;
|
||
_pbuffer += sizeof(val);
|
||
_pos += sizeof(val);
|
||
}
|
||
|
||
|
||
static void write_int(uint val)
|
||
{
|
||
#ifdef DEBUG_MORE
|
||
printf("%ld : l %lu 0x%lX\n", get_pos(), val, val);
|
||
#endif
|
||
|
||
if (_swap)
|
||
SWAP_int((int *)&val);
|
||
|
||
if (_pbuffer >= _mbuffer)
|
||
flush_buffer();
|
||
|
||
*((uint *)_pbuffer) = val;
|
||
_pbuffer += sizeof(val);
|
||
_pos += sizeof(val);
|
||
}
|
||
|
||
|
||
static void write_int64(uint64_t val)
|
||
{
|
||
#ifdef DEBUG_MORE
|
||
printf("%ld : l %llu 0x%llX\n", get_pos(), val, val);
|
||
#endif
|
||
|
||
if (_swap)
|
||
SWAP_int64((int64_t *)&val);
|
||
|
||
if (_pbuffer >= _mbuffer)
|
||
flush_buffer();
|
||
|
||
*((uint64_t *)_pbuffer) = val;
|
||
_pbuffer += sizeof(val);
|
||
_pos += sizeof(val);
|
||
}
|
||
|
||
static void write_string(const char *str, int len)
|
||
{
|
||
#ifdef DEBUG_MORE
|
||
printf("%ld : s \"%.*s\"\n", get_pos(), len, str);
|
||
#endif
|
||
|
||
if (&_pbuffer[len] > _mbuffer)
|
||
flush_buffer();
|
||
|
||
if (&_pbuffer[len] <= _mbuffer)
|
||
{
|
||
memcpy(_pbuffer, str, len);
|
||
_pbuffer += len;
|
||
*_pbuffer++ = 0;
|
||
_pos += len + 1;
|
||
return;
|
||
}
|
||
|
||
if (fwrite(str, sizeof(char), len, _file) != len)
|
||
THROW("Write error");
|
||
|
||
_pos += len;
|
||
write_byte(0);
|
||
}
|
||
|
||
|
||
static void write_buffer(void *str, int len)
|
||
{
|
||
#ifdef DEBUG_MORE
|
||
printf("%ld : buffer %ld octets\n", get_pos(), len);
|
||
#endif
|
||
|
||
if (len == 0)
|
||
return;
|
||
|
||
if (&_pbuffer[len] > _mbuffer)
|
||
flush_buffer();
|
||
|
||
if (&_pbuffer[len] <= _mbuffer)
|
||
{
|
||
memcpy(_pbuffer, str, len);
|
||
_pbuffer += len;
|
||
_pos += len;
|
||
return;
|
||
}
|
||
|
||
flush_buffer();
|
||
|
||
if (fwrite(str, sizeof(char), len, _file) != len)
|
||
THROW("Write error");
|
||
|
||
_pos += len;
|
||
}
|
||
|
||
|
||
static void write_pad(void)
|
||
{
|
||
while (get_pos() & 0x3)
|
||
write_byte(0);
|
||
}
|
||
|
||
|
||
static void write_type(TYPE type)
|
||
{
|
||
write_byte(type.t.flag);
|
||
write_byte(type.t.id);
|
||
write_short(type.t.value);
|
||
}
|
||
|
||
|
||
static void add_change(off_t pos, uint val)
|
||
{
|
||
int prev = get_pos();
|
||
char *ppos;
|
||
OUTPUT_CHANGE *change;
|
||
|
||
ppos = &_buffer[pos - (prev - (_pbuffer - _buffer))];
|
||
if (ppos >= _buffer && ppos < (_pbuffer - sizeof(uint)))
|
||
{
|
||
*((uint *)ppos) = val;
|
||
return;
|
||
}
|
||
|
||
change = ARRAY_add(&_change);
|
||
change->pos = pos;
|
||
change->val = val;
|
||
}
|
||
|
||
static void begin_section(const char *name, int size)
|
||
{
|
||
NSection++;
|
||
#ifdef DEBUG
|
||
printf("Section #%d : %s\n", NSection, name);
|
||
#endif
|
||
|
||
if (size)
|
||
{
|
||
PosStartSection = get_pos();
|
||
write_int(0);
|
||
}
|
||
else
|
||
PosStartSection = 0;
|
||
|
||
SizeSection = size;
|
||
}
|
||
|
||
|
||
static void end_section(void)
|
||
{
|
||
int len;
|
||
|
||
if (PosStartSection)
|
||
{
|
||
write_pad();
|
||
len = get_pos() - PosStartSection - sizeof(int);
|
||
add_change(PosStartSection, len);
|
||
|
||
#ifdef DEBUG
|
||
printf("==> %ld %s\n", len / SizeSection, (SizeSection == 1) ? "bytes" : "elements");
|
||
if (len % SizeSection)
|
||
printf("*** remain %ld bytes\n", len % SizeSection);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
|
||
static void output_header(void)
|
||
{
|
||
begin_section("Header", 0);
|
||
|
||
/* magic */
|
||
write_int(OUTPUT_MAGIC);
|
||
/* version */
|
||
write_int(GAMBAS_PCODE_VERSION);
|
||
/* endianness */
|
||
write_int(OUTPUT_ENDIAN);
|
||
/* flag */
|
||
if (JOB->debug)
|
||
write_int(1);
|
||
else
|
||
write_int(0);
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_class(void)
|
||
{
|
||
short flag;
|
||
begin_section("Class", 1);
|
||
|
||
/* classe parente */
|
||
write_short(Class->parent);
|
||
/* flags */
|
||
flag = 0;
|
||
if (Class->exported) flag |= 1;
|
||
if (Class->autocreate) flag |= 2;
|
||
if (Class->optional) flag |= 4;
|
||
if (Class->nocreate) flag |= 8;
|
||
write_short(flag);
|
||
/* size_static */
|
||
write_int(Class->size_stat);
|
||
/* size_dynamic */
|
||
write_int(Class->size_dyn);
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_desc(void)
|
||
{
|
||
int i, n, nn = 0;
|
||
CLASS_SYMBOL *csym;
|
||
TYPE type;
|
||
short out_type;
|
||
|
||
n = TABLE_count(Class->table);
|
||
|
||
begin_section("Description", 6 * sizeof(int));
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
csym = (CLASS_SYMBOL *)TABLE_get_symbol(Class->table, i);
|
||
csym = (CLASS_SYMBOL *)TABLE_get_symbol(Class->table, csym->symbol.sort);
|
||
|
||
type = csym->global.type;
|
||
|
||
if (TYPE_is_public(type))
|
||
{
|
||
nn++;
|
||
/* name */
|
||
write_int(get_string(csym->symbol.name, csym->symbol.len));
|
||
/* datatype */
|
||
write_type(csym->global.type);
|
||
|
||
switch (TYPE_get_kind(type))
|
||
{
|
||
case TK_VARIABLE:
|
||
|
||
/* offset */
|
||
write_int(csym->global.value);
|
||
/* read */
|
||
write_int(0);
|
||
/* write */
|
||
write_int(0);
|
||
|
||
if (TYPE_is_static(type))
|
||
out_type = CD_STATIC_VARIABLE_ID;
|
||
else
|
||
out_type = CD_VARIABLE_ID;
|
||
|
||
break;
|
||
|
||
case TK_PROPERTY:
|
||
|
||
/* read */
|
||
write_int(Class->prop[csym->global.value].read);
|
||
/* write */
|
||
write_int(Class->prop[csym->global.value].write);
|
||
/* flag */
|
||
write_int(0);
|
||
|
||
if (TYPE_is_static(type))
|
||
out_type = CD_STATIC_PROPERTY_ID;
|
||
else
|
||
out_type = CD_PROPERTY_ID;
|
||
|
||
break;
|
||
|
||
case TK_CONST:
|
||
|
||
/* param */
|
||
write_int(csym->global.value);
|
||
/* read */
|
||
write_int(0);
|
||
/* write */
|
||
write_int(0);
|
||
|
||
out_type = CD_CONSTANT_ID;
|
||
|
||
break;
|
||
|
||
case TK_FUNCTION:
|
||
|
||
/* exec */
|
||
write_int(csym->global.value);
|
||
/* signature */
|
||
write_int(0);
|
||
/* nparam */
|
||
write_int(0);
|
||
|
||
if (TYPE_is_static(type))
|
||
out_type = CD_STATIC_METHOD_ID;
|
||
else
|
||
out_type = CD_METHOD_ID;
|
||
|
||
break;
|
||
|
||
case TK_EVENT:
|
||
|
||
/* exec */
|
||
write_int(csym->global.value);
|
||
/* signature */
|
||
write_int(0);
|
||
/* nparam */
|
||
write_int(0);
|
||
|
||
out_type = CD_EVENT_ID;
|
||
|
||
break;
|
||
|
||
case TK_EXTERN:
|
||
|
||
/* exec */
|
||
write_int(csym->global.value);
|
||
/* signature */
|
||
write_int(0);
|
||
/* nparam */
|
||
write_int(0);
|
||
|
||
out_type = CD_EXTERN_ID;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
ERROR_panic("output_desc: unknown symbol type");
|
||
continue;
|
||
}
|
||
|
||
/* type de symbole */
|
||
write_int(out_type);
|
||
}
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
|
||
static void output_constant(void)
|
||
{
|
||
int i, n;
|
||
CONSTANT *constant;
|
||
SYMBOL *sym;
|
||
//TABLE *table;
|
||
|
||
n = ARRAY_count(Class->constant);
|
||
|
||
begin_section("Constants", 3 * sizeof(int));
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
constant = &Class->constant[i];
|
||
|
||
/* type */
|
||
write_type(constant->type);
|
||
/* value */
|
||
switch (TYPE_get_id(constant->type))
|
||
{
|
||
case T_BOOLEAN: case T_BYTE: case T_SHORT: case T_INTEGER:
|
||
|
||
write_int(constant->value);
|
||
write_int(0);
|
||
break;
|
||
|
||
case T_LONG:
|
||
|
||
write_int64(constant->lvalue);
|
||
break;
|
||
|
||
case T_SINGLE: case T_FLOAT:
|
||
|
||
sym = TABLE_get_symbol(Class->table, constant->value);
|
||
write_int(get_string(sym->name, sym->len));
|
||
write_int(sym->len);
|
||
break;
|
||
|
||
case T_STRING: case T_CSTRING:
|
||
|
||
sym = TABLE_get_symbol(Class->string, constant->value);
|
||
write_int(get_string(sym->name, sym->len));
|
||
write_int(sym->len);
|
||
break;
|
||
}
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_class_ref(void)
|
||
{
|
||
int i, n;
|
||
SYMBOL *sym;
|
||
CLASS_REF *ref;
|
||
|
||
n = ARRAY_count(Class->class);
|
||
|
||
begin_section("External classes", sizeof(int));
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
ref = &Class->class[i];
|
||
sym = TABLE_get_symbol(Class->table, ref->index);
|
||
if (ref->used)
|
||
{
|
||
write_int(get_string(sym->name, sym->len));
|
||
}
|
||
else
|
||
{
|
||
if (JOB->verbose)
|
||
printf("Ignoring class %.*s\n", sym->len, sym->name);
|
||
write_int(-get_string(sym->name, sym->len));
|
||
}
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_unknown_ref(void)
|
||
{
|
||
int i, n;
|
||
SYMBOL *sym;
|
||
|
||
n = ARRAY_count(Class->unknown);
|
||
|
||
begin_section("External symbols", sizeof(int));
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
sym = TABLE_get_symbol(Class->table, Class->unknown[i]);
|
||
write_int(get_string(sym->name, sym->len));
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_static(void)
|
||
{
|
||
int i, n;
|
||
VARIABLE *var;
|
||
|
||
n = ARRAY_count(Class->stat);
|
||
|
||
begin_section("Static variables", 2 * sizeof(int));
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
var = &Class->stat[i];
|
||
|
||
/* type */
|
||
write_type(var->type);
|
||
/* addr */
|
||
write_int(var->pos);
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_dynamic(void)
|
||
{
|
||
int i, n;
|
||
VARIABLE *var;
|
||
|
||
n = ARRAY_count(Class->dyn);
|
||
|
||
begin_section("Dynamic variables", 2 * sizeof(int));
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
var = &Class->dyn[i];
|
||
|
||
/* type */
|
||
write_type(var->type);
|
||
/* addr */
|
||
write_int(var->pos);
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_event(void)
|
||
{
|
||
int i, n;
|
||
EVENT *event;
|
||
SYMBOL *sym;
|
||
|
||
n = ARRAY_count(Class->event);
|
||
|
||
begin_section("Events", 4 * sizeof(int));
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
event = &Class->event[i];
|
||
|
||
/* type */
|
||
write_type(event->type);
|
||
/* n_param */
|
||
write_short(event->nparam);
|
||
/* reserved */
|
||
write_short(0);
|
||
/* desc_param */
|
||
write_int(0);
|
||
/* name */
|
||
sym = TABLE_get_symbol(Class->table, event->name);
|
||
write_int(get_string(sym->name, sym->len));
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_extern(void)
|
||
{
|
||
int i, n;
|
||
EXTFUNC *ext;
|
||
SYMBOL *sym;
|
||
|
||
n = ARRAY_count(Class->ext_func);
|
||
|
||
begin_section("Extern functions", 5 * sizeof(int));
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
ext = &Class->ext_func[i];
|
||
|
||
/* type */
|
||
write_type(ext->type);
|
||
/* n_param */
|
||
write_short(ext->nparam);
|
||
/* reserved */
|
||
write_short(0);
|
||
/* desc_param */
|
||
write_int(0);
|
||
/* name */
|
||
/*sym = TABLE_get_symbol(Class->table, ext->name);
|
||
write_int(get_string(sym->name, sym->len));*/
|
||
/* alias name */
|
||
if (ext->alias == NO_SYMBOL)
|
||
sym = TABLE_get_symbol(Class->table, ext->name);
|
||
else
|
||
sym = TABLE_get_symbol(Class->string, ext->alias);
|
||
write_int(get_string(sym->name, sym->len));
|
||
/* library name */
|
||
sym = TABLE_get_symbol(Class->string, ext->library);
|
||
write_int(get_string(sym->name, sym->len));
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_method(void)
|
||
{
|
||
int i, n;
|
||
FUNCTION *func;
|
||
/*SYMBOL *sym;*/
|
||
|
||
n = ARRAY_count(Class->function);
|
||
|
||
begin_section("Methods", 8 * sizeof(int));
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
func = &Class->function[i];
|
||
|
||
write_type(func->type);
|
||
write_byte(func->nparam);
|
||
write_byte(func->npmin);
|
||
write_byte(func->vararg);
|
||
write_byte(0);
|
||
write_short(func->nlocal);
|
||
write_short(func->nctrl);
|
||
write_short(func->stack);
|
||
|
||
/* gestion d'erreur */
|
||
if (func->catch && func->finally)
|
||
write_short(Min(func->finally, func->catch));
|
||
else if (func->catch)
|
||
write_short(func->catch);
|
||
else
|
||
write_short(func->finally);
|
||
|
||
/* addr_code */
|
||
write_int(func->ncode);
|
||
/* desc_param */
|
||
write_int(0);
|
||
/* desc_local */
|
||
write_int(0);
|
||
/* debug_info */
|
||
write_int(0);
|
||
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_param_local(void)
|
||
{
|
||
int i, j;
|
||
FUNCTION *func;
|
||
EVENT *event;
|
||
EXTFUNC *ext;
|
||
PARAM *param;
|
||
|
||
begin_section("Parameters", sizeof(int));
|
||
|
||
for (i = 0; i < ARRAY_count(Class->function); i++)
|
||
{
|
||
func = &Class->function[i];
|
||
|
||
if (func->name != NO_SYMBOL)
|
||
{
|
||
/* Les param<61>res sont remis dans les variables locales !
|
||
for (j = 0; j < func->nparam; j++)
|
||
{
|
||
param = &func->param[j];
|
||
write_int(param->type);
|
||
}
|
||
*/
|
||
|
||
for (j = 0; j < func->nlocal + func->nparam; j++)
|
||
{
|
||
param = &func->local[j];
|
||
|
||
/* type */
|
||
write_type(param->type);
|
||
}
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < ARRAY_count(Class->event); i++)
|
||
{
|
||
event = &Class->event[i];
|
||
|
||
for (j = 0; j < event->nparam; j++)
|
||
{
|
||
param = &event->param[j];
|
||
|
||
/* type */
|
||
write_type(param->type);
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < ARRAY_count(Class->ext_func); i++)
|
||
{
|
||
ext = &Class->ext_func[i];
|
||
|
||
for (j = 0; j < ext->nparam; j++)
|
||
{
|
||
param = &ext->param[j];
|
||
|
||
/* type */
|
||
write_type(param->type);
|
||
}
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_array(void)
|
||
{
|
||
int i, j, p;
|
||
CLASS_ARRAY *array;
|
||
|
||
begin_section("Arrays", sizeof(int));
|
||
|
||
p = ARRAY_count(Class->array) * sizeof(int);
|
||
|
||
for (i = 0; i < ARRAY_count(Class->array); i++)
|
||
{
|
||
array = &Class->array[i];
|
||
write_int(p);
|
||
p += sizeof(int) + array->ndim * sizeof(int);
|
||
}
|
||
|
||
for (i = 0; i < ARRAY_count(Class->array); i++)
|
||
{
|
||
array = &Class->array[i];
|
||
|
||
write_type(array->type);
|
||
|
||
for (j = 0; j < array->ndim; j++)
|
||
{
|
||
p = array->dim[j];
|
||
if (j == (array->ndim - 1))
|
||
p = (-p);
|
||
|
||
write_int(p);
|
||
}
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_code()
|
||
{
|
||
int i, j;
|
||
int n;
|
||
FUNCTION *func;
|
||
|
||
for (i = 0; i < ARRAY_count(Class->function); i++)
|
||
{
|
||
func = &Class->function[i];
|
||
|
||
n = func->ncode;
|
||
|
||
begin_section("Code", sizeof(short));
|
||
if (_swap)
|
||
{
|
||
for (j = 0; j < n; j++)
|
||
write_short(func->code[j]);
|
||
}
|
||
else
|
||
write_buffer(func->code, n * sizeof(short));
|
||
end_section();
|
||
}
|
||
}
|
||
|
||
|
||
static void output_debug_global()
|
||
{
|
||
int i, nn = 0;
|
||
CLASS_SYMBOL *csym;
|
||
TYPE type;
|
||
|
||
begin_section("Global symbol table", 4 * sizeof(int));
|
||
|
||
for (i = 0; i < TABLE_count(Class->table); i++)
|
||
{
|
||
csym = (CLASS_SYMBOL *)TABLE_get_symbol(Class->table, i);
|
||
csym = (CLASS_SYMBOL *)TABLE_get_symbol(Class->table, csym->symbol.sort);
|
||
|
||
type = csym->global.type;
|
||
switch (TYPE_get_kind(type))
|
||
{
|
||
case TK_VARIABLE:
|
||
case TK_FUNCTION:
|
||
case TK_PROPERTY:
|
||
case TK_EXTERN:
|
||
case TK_CONST:
|
||
|
||
nn++;
|
||
/* sort */
|
||
write_short((short)nn);
|
||
/* len */
|
||
write_short(csym->symbol.len);
|
||
/* name */
|
||
write_int(get_string(csym->symbol.name, csym->symbol.len));
|
||
/* type */
|
||
write_type(csym->global.type);
|
||
/* value */
|
||
write_int(csym->global.value);
|
||
|
||
break;
|
||
|
||
default:
|
||
/* ignore */
|
||
break;
|
||
}
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_debug_method()
|
||
{
|
||
int i, j, n;
|
||
SYMBOL *sym;
|
||
OUTPUT_SYMBOL *osym;
|
||
CLASS_SYMBOL *csym;
|
||
PARAM *param;
|
||
FUNCTION *func;
|
||
TABLE *table;
|
||
|
||
begin_section("Debug method info", 5 * sizeof(int));
|
||
|
||
for (i = 0; i < ARRAY_count(Class->function); i++)
|
||
{
|
||
func = &Class->function[i];
|
||
|
||
if (func->pos_line != NULL)
|
||
{
|
||
/* line */
|
||
write_short(func->line);
|
||
write_short(ARRAY_count(func->pos_line));
|
||
/* pos_line */
|
||
write_int(0);
|
||
/* nom */
|
||
sym = TABLE_get_symbol(Class->table, func->name);
|
||
write_int(get_string(sym->name, sym->len));
|
||
/* local symbols */
|
||
write_int(0);
|
||
/* n_local */
|
||
write_short(0);
|
||
/* reserved */
|
||
write_short(0);
|
||
}
|
||
else
|
||
{
|
||
write_short(0);
|
||
write_short(0);
|
||
write_int(0);
|
||
write_int(0);
|
||
write_int(0);
|
||
write_short(0);
|
||
write_short(0);
|
||
}
|
||
}
|
||
|
||
end_section();
|
||
|
||
for (i = 0; i < ARRAY_count(Class->function); i++)
|
||
{
|
||
func = &Class->function[i];
|
||
|
||
n = func->pos_line ? ARRAY_count(func->pos_line) : 0;
|
||
|
||
begin_section("Debug method lines", sizeof(short));
|
||
|
||
if (_swap)
|
||
{
|
||
for (j = 0; j < n; j++)
|
||
write_short(func->pos_line[j]);
|
||
}
|
||
else
|
||
write_buffer(func->pos_line, n * sizeof(short));
|
||
|
||
end_section();
|
||
}
|
||
|
||
for (i = 0; i < ARRAY_count(Class->function); i++)
|
||
{
|
||
func = &Class->function[i];
|
||
|
||
begin_section("Debug method local symbols", sizeof(int) * 3);
|
||
|
||
if (func->name != NO_SYMBOL)
|
||
{
|
||
sym = (SYMBOL *)TABLE_get_symbol(Class->table, func->name);
|
||
/*printf("%.*s()\n", sym->len, sym->name);*/
|
||
|
||
TABLE_create(&table, sizeof(OUTPUT_SYMBOL), TF_IGNORE_CASE);
|
||
|
||
for (j = 0; j < func->nlocal + func->nparam; j++)
|
||
{
|
||
param = &func->local[j];
|
||
csym = (CLASS_SYMBOL *)TABLE_get_symbol(Class->table, param->index);
|
||
|
||
TABLE_add_symbol(table, csym->symbol.name, csym->symbol.len, (SYMBOL **)(void *)&osym, NULL);
|
||
osym->value = param->value;/*TYPE_long(param->type);*/
|
||
}
|
||
|
||
for (j = 0; j < TABLE_count(table); j++)
|
||
{
|
||
param = &func->local[j];
|
||
osym = (OUTPUT_SYMBOL *)TABLE_get_symbol(table, j);
|
||
|
||
/* sort */
|
||
write_short(osym->sym.sort);
|
||
/* len */
|
||
write_short(osym->sym.len);
|
||
/* name */
|
||
write_int(get_string(osym->sym.name, osym->sym.len));
|
||
/* value */
|
||
write_int(osym->value);
|
||
|
||
/*printf("%.*s %ld\n", osym->sym.len, osym->sym.name, osym->value);*/
|
||
}
|
||
|
||
TABLE_delete(&table);
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
}
|
||
|
||
|
||
static void output_debug_filename(void)
|
||
{
|
||
char path[MAX_PATH + 1];
|
||
int n;
|
||
|
||
begin_section("Debug file name", 1);
|
||
|
||
if (JOB->name[0] == '/')
|
||
{
|
||
|
||
strcpy(path, JOB->name);
|
||
}
|
||
else
|
||
{
|
||
getcwd(path, MAX_PATH);
|
||
n = strlen(path);
|
||
|
||
if (path[n - 1] != '/')
|
||
strcpy(&path[n], "/");
|
||
|
||
strcat(&path[n], JOB->name);
|
||
}
|
||
|
||
n = strlen(path);
|
||
write_buffer(path, n);
|
||
/*write_pad();*/
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
static void output_string(void)
|
||
{
|
||
int i;
|
||
SYMBOL *sym;
|
||
|
||
begin_section("Strings", 1);
|
||
|
||
for (i = 0; i < TABLE_count(StringTable); i++)
|
||
{
|
||
sym = TABLE_get_symbol(StringTable, i);
|
||
write_string(sym->name, sym->len);
|
||
}
|
||
|
||
end_section();
|
||
}
|
||
|
||
|
||
PUBLIC const char *OUTPUT_get_file(const char *file)
|
||
{
|
||
const char *output;
|
||
char *p;
|
||
const char *dir;
|
||
char *name;
|
||
|
||
dir = STR_copy(FILE_get_dir(file));
|
||
name = STR_copy(FILE_get_name(file));
|
||
|
||
for (p = name; *p; p++)
|
||
{
|
||
if (*p == '.')
|
||
{
|
||
*p = 0;
|
||
break;
|
||
}
|
||
|
||
*p = toupper(*p);
|
||
}
|
||
|
||
output = FILE_cat(dir, ".gambas", NULL);
|
||
if (mkdir(output, 0777) == 0)
|
||
FILE_set_owner(output, COMP_project);
|
||
|
||
output = STR_copy(FILE_cat(dir, ".gambas", name, NULL));
|
||
|
||
STR_free(dir);
|
||
STR_free(name);
|
||
|
||
return output;
|
||
}
|
||
|
||
|
||
PUBLIC const char *OUTPUT_get_trans_file(const char *file)
|
||
{
|
||
const char *output;
|
||
const char *dir;
|
||
const char *name;
|
||
|
||
dir = STR_copy(FILE_get_dir(file));
|
||
name = STR_copy(FILE_get_name(file));
|
||
|
||
output = FILE_cat(dir, ".lang", NULL);
|
||
if (mkdir(output, 0777) == 0)
|
||
FILE_set_owner(output, COMP_project);
|
||
|
||
output = FILE_cat(dir, ".lang", name, NULL);
|
||
output = STR_copy(FILE_set_ext(output, "pot"));
|
||
|
||
STR_free(dir);
|
||
STR_free(name);
|
||
|
||
return output;
|
||
}
|
||
|
||
|
||
static void output_translation(void)
|
||
{
|
||
FILE *file;
|
||
int i, j, n;
|
||
CONSTANT *constant;
|
||
SYMBOL *sym;
|
||
unsigned char c;
|
||
|
||
/*printf("Generating %s\n", JOB->tname);*/
|
||
|
||
file = fopen(JOB->tname, "w");
|
||
if (!file)
|
||
THROW("Cannot create file '&1'", JOB->tname);
|
||
|
||
fprintf(file, "# %s\n# Generated by Gambas compiler\n\n", JOB->name);
|
||
|
||
fprintf(file,
|
||
"# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n"
|
||
"#\n"
|
||
"#, fuzzy\n"
|
||
"msgid \"\"\n"
|
||
"msgstr \"\"\n"
|
||
"\"Project-Id-Version: PACKAGE VERSION\\n\""
|
||
"\"POT-Creation-Date: 2002-11-01 04:27+0100\\n\"\n"
|
||
"\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n"
|
||
"\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n"
|
||
"\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n"
|
||
"\"MIME-Version: 1.0\\n\"\n"
|
||
"\"Content-Type: text/plain; charset=UTF-8\\n\"\n"
|
||
"\"Content-Transfer-Encoding: 8bit\\n\"\n\n");
|
||
|
||
n = ARRAY_count(Class->constant);
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
constant = &Class->constant[i];
|
||
if (TYPE_get_id(constant->type) != T_CSTRING)
|
||
continue;
|
||
|
||
sym = TABLE_get_symbol(Class->string, constant->value);
|
||
if (sym->len == 0)
|
||
continue;
|
||
|
||
for (j = 0; j < sym->len; j++)
|
||
{
|
||
c = sym->name[j];
|
||
if (c > ' ')
|
||
break;
|
||
}
|
||
|
||
if (j >= sym->len)
|
||
continue;
|
||
|
||
fprintf(file, "#: %s:%d\n", FILE_get_name(JOB->name), constant->line);
|
||
|
||
fprintf(file, "msgid \"");
|
||
|
||
for (j = 0; j < sym->len; j++)
|
||
{
|
||
c = sym->name[j];
|
||
if (c == '\n')
|
||
fprintf(file, "\\n");
|
||
else if (c == '\t')
|
||
fprintf(file, "\\t");
|
||
else if (c == '\r')
|
||
fprintf(file, "\\r");
|
||
else if (c == '\\')
|
||
fprintf(file, "\\\\");
|
||
else if (c == '"')
|
||
fprintf(file, "\\\"");
|
||
else
|
||
fputc(c, file);
|
||
}
|
||
|
||
fprintf(file, "\"\n");
|
||
fprintf(file, "msgstr \"\"\n\n");
|
||
|
||
sym->len = 0; /* Horrible hack for not writing the same string twice */
|
||
}
|
||
|
||
fclose(file);
|
||
FILE_set_owner(JOB->tname, COMP_project);
|
||
}
|
||
|
||
|
||
static void output_finalize(void)
|
||
{
|
||
int i;
|
||
|
||
flush_buffer();
|
||
|
||
for (i = 0; i < ARRAY_count(_change); i++)
|
||
{
|
||
fseek(_file, _change[i].pos, SEEK_SET);
|
||
if (fwrite(&_change[i].val, sizeof(int), 1, _file) != 1)
|
||
THROW("Write error");
|
||
}
|
||
}
|
||
|
||
|
||
PUBLIC void OUTPUT_do(bool swap)
|
||
{
|
||
const char *name;
|
||
|
||
_swap = swap;
|
||
|
||
output_init();
|
||
|
||
/* La premi<6D>e cha<68>e est toujours le nom de la classe */
|
||
get_string(JOB->class->name, strlen(JOB->class->name));
|
||
|
||
name = JOB->output;
|
||
|
||
#ifdef DEBUG
|
||
printf("Output to %s\n", name);
|
||
#endif
|
||
|
||
_file = fopen(name, "w");
|
||
if (!_file)
|
||
THROW("Cannot create file '&1'", name);
|
||
|
||
Class = JOB->class;
|
||
|
||
#ifdef DEBUG
|
||
printf("pos = %lu\n", get_pos());
|
||
#endif
|
||
|
||
output_header();
|
||
output_class();
|
||
output_desc();
|
||
output_constant();
|
||
output_class_ref();
|
||
output_unknown_ref();
|
||
output_static();
|
||
output_dynamic();
|
||
output_event();
|
||
output_extern();
|
||
output_method();
|
||
output_param_local();
|
||
output_array();
|
||
output_code();
|
||
|
||
if (JOB->debug)
|
||
{
|
||
output_debug_global();
|
||
output_debug_method();
|
||
output_debug_filename();
|
||
}
|
||
|
||
output_string();
|
||
|
||
output_finalize();
|
||
|
||
fclose(_file);
|
||
FILE_set_owner(JOB->output, COMP_project);
|
||
|
||
output_exit();
|
||
|
||
/* Internationalisation */
|
||
|
||
if (JOB->trans)
|
||
output_translation();
|
||
}
|