2007-12-30 17:41:49 +01:00
|
|
|
|
/***************************************************************************
|
|
|
|
|
|
|
|
|
|
class.c
|
|
|
|
|
|
|
|
|
|
Class management
|
|
|
|
|
|
|
|
|
|
(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_CLASS_C
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#include "gb_common.h"
|
|
|
|
|
#include "gb_error.h"
|
|
|
|
|
#include "gb_str.h"
|
|
|
|
|
#include "gb_file.h"
|
|
|
|
|
|
|
|
|
|
#include "gb_table.h"
|
|
|
|
|
#include "gbc_compile.h"
|
|
|
|
|
#include "gb_code.h"
|
|
|
|
|
|
|
|
|
|
static int _array_class[17];
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void CLASS_create(CLASS **result)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
CLASS *class;
|
|
|
|
|
TRANS_FUNC func;
|
|
|
|
|
|
|
|
|
|
ALLOC_ZERO(&class, sizeof(CLASS), "CLASS_create");
|
|
|
|
|
|
|
|
|
|
ARRAY_create(&class->function);
|
|
|
|
|
ARRAY_create(&class->event);
|
|
|
|
|
ARRAY_create(&class->prop);
|
|
|
|
|
ARRAY_create(&class->ext_func);
|
|
|
|
|
ARRAY_create(&class->constant);
|
|
|
|
|
ARRAY_create(&class->class);
|
|
|
|
|
ARRAY_create(&class->unknown);
|
|
|
|
|
ARRAY_create(&class->stat);
|
|
|
|
|
ARRAY_create(&class->dyn);
|
|
|
|
|
ARRAY_create(&class->array);
|
|
|
|
|
ARRAY_create(&class->structure);
|
|
|
|
|
|
|
|
|
|
TABLE_create(&class->table, sizeof(CLASS_SYMBOL), TF_IGNORE_CASE);
|
|
|
|
|
TABLE_create(&class->string, sizeof(SYMBOL), TF_NORMAL);
|
|
|
|
|
|
|
|
|
|
/* Cr<43>tion des fonctions d'initialisation */
|
|
|
|
|
|
2008-02-24 17:29:02 +01:00
|
|
|
|
CLEAR(&func);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
TYPE_clear(&func.type);
|
|
|
|
|
|
|
|
|
|
func.index = CLASS_add_symbol(class, "@init");
|
|
|
|
|
CLASS_add_function(class, &func);
|
|
|
|
|
|
|
|
|
|
func.index = CLASS_add_symbol(class, "@new");
|
|
|
|
|
CLASS_add_function(class, &func);
|
|
|
|
|
|
|
|
|
|
/* Le premier symbole de la table des symboles est vide.
|
|
|
|
|
Ainsi, l'index 0 de la table n'est jamais utilis<EFBFBD>! */
|
|
|
|
|
|
|
|
|
|
/*CLASS_add_symbol_string(class, "");*/
|
|
|
|
|
|
|
|
|
|
class->name = STR_copy(FILE_set_ext(FILE_get_name(JOB->name), NULL));
|
|
|
|
|
class->parent = NO_SYMBOL;
|
|
|
|
|
|
|
|
|
|
memset(_array_class, 0, sizeof(_array_class));
|
|
|
|
|
|
|
|
|
|
*result = class;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void delete_function(FUNCTION *func)
|
|
|
|
|
{
|
|
|
|
|
ARRAY_delete(&func->local);
|
|
|
|
|
if (func->code)
|
|
|
|
|
FREE(&func->code, "delete_function");
|
|
|
|
|
|
|
|
|
|
if (JOB->debug)
|
|
|
|
|
ARRAY_delete(&func->pos_line);
|
|
|
|
|
|
|
|
|
|
if (func->param)
|
|
|
|
|
FREE(&func->param, "delete_function");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void delete_event(EVENT *event)
|
|
|
|
|
{
|
|
|
|
|
if (event->param)
|
|
|
|
|
FREE(&event->param, "delete_event");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void delete_extfunc(EXTFUNC *extfunc)
|
|
|
|
|
{
|
|
|
|
|
if (extfunc->param)
|
|
|
|
|
FREE(&extfunc->param, "delete_extfunc");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void delete_structure(CLASS_STRUCT *structure)
|
|
|
|
|
{
|
|
|
|
|
if (structure->field)
|
|
|
|
|
ARRAY_delete(&structure->field);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void CLASS_delete(CLASS **class)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (*class)
|
|
|
|
|
{
|
|
|
|
|
TABLE_delete(&((*class)->table));
|
|
|
|
|
TABLE_delete(&((*class)->string));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_count((*class)->function); i++)
|
|
|
|
|
delete_function(&((*class)->function[i]));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_count((*class)->event); i++)
|
|
|
|
|
delete_event(&((*class)->event[i]));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_count((*class)->ext_func); i++)
|
|
|
|
|
delete_extfunc(&((*class)->ext_func[i]));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_count((*class)->structure); i++)
|
|
|
|
|
delete_structure(&((*class)->structure[i]));
|
|
|
|
|
|
|
|
|
|
ARRAY_delete(&((*class)->function));
|
|
|
|
|
ARRAY_delete(&((*class)->event));
|
|
|
|
|
ARRAY_delete(&((*class)->prop));
|
|
|
|
|
ARRAY_delete(&((*class)->ext_func));
|
|
|
|
|
ARRAY_delete(&((*class)->constant));
|
|
|
|
|
ARRAY_delete(&((*class)->class));
|
|
|
|
|
ARRAY_delete(&((*class)->unknown));
|
|
|
|
|
ARRAY_delete(&((*class)->stat));
|
|
|
|
|
ARRAY_delete(&((*class)->dyn));
|
|
|
|
|
ARRAY_delete(&((*class)->array));
|
|
|
|
|
ARRAY_delete(&((*class)->structure));
|
|
|
|
|
|
|
|
|
|
if ((*class)->name != NULL)
|
|
|
|
|
STR_free((*class)->name);
|
|
|
|
|
|
|
|
|
|
FREE(class, "CLASS_delete");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
CLASS_SYMBOL *CLASS_declare(CLASS *class, int index, boolean global)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
CLASS_SYMBOL *sym = CLASS_get_symbol(class, index);
|
|
|
|
|
|
|
|
|
|
if ((global && !TYPE_is_null(sym->global.type))
|
|
|
|
|
|| (!global && !TYPE_is_null(sym->local.type)))
|
|
|
|
|
{
|
|
|
|
|
char name[MAX_SYMBOL_LEN + 1];
|
2008-01-06 21:06:44 +01:00
|
|
|
|
snprintf(name, sizeof(name), "%.*s", sym->symbol.len, sym->symbol.name);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
THROW("'&1' already declared", name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sym;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void CLASS_add_function(CLASS *class, TRANS_FUNC *decl)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
FUNCTION *func;
|
|
|
|
|
int i;
|
|
|
|
|
CLASS_SYMBOL *sym;
|
|
|
|
|
PARAM *param;
|
2008-04-10 14:06:14 +02:00
|
|
|
|
int count;
|
|
|
|
|
|
|
|
|
|
count = ARRAY_count(class->function);
|
|
|
|
|
if (count >= MAX_CLASS_FUNCTION)
|
|
|
|
|
THROW("Too many functions");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
func = ARRAY_add_void(&class->function);
|
|
|
|
|
TYPE_clear(&func->type);
|
|
|
|
|
func->nparam = 0;
|
|
|
|
|
func->name = NO_SYMBOL;
|
|
|
|
|
|
|
|
|
|
ARRAY_create(&func->local);
|
|
|
|
|
//ARRAY_create_inc(&func->code, 512);
|
|
|
|
|
func->code = NULL;
|
|
|
|
|
func->ncode = 0;
|
[DEVELOPMENT ENVIRONMENT]
* BUG: Use TextEdit.RichText insted of TextEdit.Text.
* BUG: END SUB can be the end of a method. The class analyze now takes
that into account.
[HELP]
* BUG: Fixed the generated treeview.
[COMPILER]
* OPT: The NOT operator used just at the beginning of a conditional
expression is optimized. Consequently, an expression like 'IF NOT 2' is
now equivalent to 'IF 2 = 0' and not to 'IF (NOT 2) <> 0' as before. In
other words, the boolean conversion is now done before the NOT, and not
after. The following instructions are concerned: IF, WHILE, UNTIL.
* NEW: BYREF is new keyword that is a more readable synonymous of '@'.
[GB.DB.FORM]
* BUG: Correctly manage data controls inside TabStrip-like containers.
* BUG: Setting the focus on a non-initialized DataControl does not raise
an error anymore.
[GB.GTK]
* BUG: HSplitter.Layout and VSplitter.Layout now work correctly. It is a
list of children widths, hidden children having a zero width.
* BUG: Window arrangement is done before the Open event is raised, as in
gb.qt.
* BUG: Keyboard, focus and mouse events now work correctly on Window and
DrawingArea controls.
[GB.QT]
* BUG: HSplitter.Layout and VSplitter.Layout now work correctly. It is a
list of children widths, hidden children having a zero width.
* BUG: Many warning fixes.
* BUG: Now the Control.Visible property works like in gb.gtk, i.e. it
returns if the control was not explicitely hidden.
git-svn-id: svn://localhost/gambas/trunk@1060 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-02-06 01:25:48 +01:00
|
|
|
|
func->ncode_max = 0;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
if (JOB->debug)
|
|
|
|
|
ARRAY_create(&func->pos_line);
|
|
|
|
|
|
|
|
|
|
if (!decl) return;
|
|
|
|
|
|
|
|
|
|
sym = CLASS_declare(class, decl->index, TRUE);
|
|
|
|
|
/*CLASS_add_symbol(class, JOB->table, decl->index, &sym, NULL);*/
|
|
|
|
|
|
|
|
|
|
sym->global.type = decl->type;
|
|
|
|
|
sym->global.value = ARRAY_count(class->function) - 1;
|
|
|
|
|
|
|
|
|
|
func->nparam = decl->nparam;
|
|
|
|
|
|
|
|
|
|
if (decl->nparam)
|
|
|
|
|
{
|
|
|
|
|
ALLOC(&func->param, decl->nparam * sizeof(PARAM), "CLASS_add_function");
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < decl->nparam; i++)
|
|
|
|
|
func->param[i] = decl->param[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func->type = decl->type;
|
|
|
|
|
func->start = decl->start;
|
|
|
|
|
func->line = decl->line;
|
|
|
|
|
func->name = decl->index;
|
|
|
|
|
func->last_code = (-1);
|
2008-03-17 15:54:17 +01:00
|
|
|
|
func->last_code2 = (-1);
|
[DEVELOPMENT ENVIRONMENT]
* BUG: Use TextEdit.RichText insted of TextEdit.Text.
* BUG: END SUB can be the end of a method. The class analyze now takes
that into account.
[HELP]
* BUG: Fixed the generated treeview.
[COMPILER]
* OPT: The NOT operator used just at the beginning of a conditional
expression is optimized. Consequently, an expression like 'IF NOT 2' is
now equivalent to 'IF 2 = 0' and not to 'IF (NOT 2) <> 0' as before. In
other words, the boolean conversion is now done before the NOT, and not
after. The following instructions are concerned: IF, WHILE, UNTIL.
* NEW: BYREF is new keyword that is a more readable synonymous of '@'.
[GB.DB.FORM]
* BUG: Correctly manage data controls inside TabStrip-like containers.
* BUG: Setting the focus on a non-initialized DataControl does not raise
an error anymore.
[GB.GTK]
* BUG: HSplitter.Layout and VSplitter.Layout now work correctly. It is a
list of children widths, hidden children having a zero width.
* BUG: Window arrangement is done before the Open event is raised, as in
gb.qt.
* BUG: Keyboard, focus and mouse events now work correctly on Window and
DrawingArea controls.
[GB.QT]
* BUG: HSplitter.Layout and VSplitter.Layout now work correctly. It is a
list of children widths, hidden children having a zero width.
* BUG: Many warning fixes.
* BUG: Now the Control.Visible property works like in gb.gtk, i.e. it
returns if the control was not explicitely hidden.
git-svn-id: svn://localhost/gambas/trunk@1060 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-02-06 01:25:48 +01:00
|
|
|
|
func->stack = 8; // Some stack may be needed for initialization functions
|
2007-12-30 17:41:49 +01:00
|
|
|
|
func->finally = 0;
|
|
|
|
|
func->catch = 0;
|
|
|
|
|
func->npmin = -1;
|
|
|
|
|
func->vararg = decl->vararg;
|
|
|
|
|
|
2008-02-24 17:29:02 +01:00
|
|
|
|
// Function startup
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
CODE_begin_function(func);
|
|
|
|
|
JOB->func = func;
|
|
|
|
|
|
2008-02-24 17:29:02 +01:00
|
|
|
|
// Byref check at function startup
|
|
|
|
|
|
|
|
|
|
if (decl->byref)
|
|
|
|
|
CODE_byref(decl->byref);
|
|
|
|
|
|
|
|
|
|
// Optional parameters
|
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
|
for (i = 0; i < func->nparam; i++)
|
|
|
|
|
{
|
|
|
|
|
param = &func->param[i];
|
|
|
|
|
if (param->optional == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (func->npmin < 0)
|
|
|
|
|
func->npmin = i;
|
|
|
|
|
|
|
|
|
|
TRANS_init_optional(param);
|
|
|
|
|
CODE_pop_optional(i - func->nparam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (func->npmin < 0)
|
|
|
|
|
func->npmin = func->nparam;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void CLASS_add_event(CLASS *class, TRANS_EVENT *decl)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
EVENT *event;
|
|
|
|
|
int i;
|
|
|
|
|
CLASS_SYMBOL *sym;
|
2008-04-10 14:06:14 +02:00
|
|
|
|
int count;
|
|
|
|
|
|
|
|
|
|
count = ARRAY_count(class->event);
|
|
|
|
|
if (count >= MAX_CLASS_EVENT)
|
|
|
|
|
THROW("Too many events");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
event = ARRAY_add_void(&class->event);
|
|
|
|
|
TYPE_clear(&event->type);
|
|
|
|
|
event->nparam = 0;
|
|
|
|
|
event->name = NO_SYMBOL;
|
|
|
|
|
|
|
|
|
|
if (!decl) return;
|
|
|
|
|
|
|
|
|
|
sym = CLASS_declare(class, decl->index, TRUE);
|
|
|
|
|
/*CLASS_add_symbol(class, JOB->table, decl->index, &sym, NULL);*/
|
|
|
|
|
|
|
|
|
|
sym->global.type = decl->type;
|
|
|
|
|
sym->global.value = ARRAY_count(class->event) - 1;
|
|
|
|
|
|
|
|
|
|
event->nparam = decl->nparam;
|
|
|
|
|
|
|
|
|
|
if (event->nparam)
|
|
|
|
|
{
|
|
|
|
|
ALLOC(&event->param, decl->nparam * sizeof(PARAM), "CLASS_add_event");
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < decl->nparam; i++)
|
|
|
|
|
{
|
|
|
|
|
event->param[i].type = decl->param[i].type;
|
|
|
|
|
event->param[i].index = decl->param[i].index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event->type = decl->type;
|
|
|
|
|
event->name = decl->index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void CLASS_add_property(CLASS *class, TRANS_PROPERTY *decl)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
PROPERTY *prop;
|
|
|
|
|
CLASS_SYMBOL *sym;
|
|
|
|
|
|
|
|
|
|
prop = ARRAY_add_void(&class->prop);
|
|
|
|
|
TYPE_clear(&prop->type);
|
|
|
|
|
prop->name = NO_SYMBOL;
|
|
|
|
|
prop->read = TRUE;
|
|
|
|
|
prop->write = decl->read == 0;
|
|
|
|
|
|
|
|
|
|
sym = CLASS_declare(class, decl->index, TRUE);
|
|
|
|
|
/*CLASS_add_symbol(class, JOB->table, decl->index, &sym, NULL);*/
|
|
|
|
|
|
|
|
|
|
sym->global.type = decl->type;
|
|
|
|
|
sym->global.value = ARRAY_count(class->prop) - 1;
|
|
|
|
|
|
|
|
|
|
prop->type = decl->type;
|
|
|
|
|
prop->name = decl->index;
|
|
|
|
|
prop->line = decl->line;
|
|
|
|
|
prop->comment = decl->comment;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void CLASS_add_extern(CLASS *class, TRANS_EXTERN *decl)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
EXTFUNC *extfunc;
|
|
|
|
|
int i;
|
|
|
|
|
CLASS_SYMBOL *sym;
|
2008-04-10 14:06:14 +02:00
|
|
|
|
int count;
|
|
|
|
|
|
|
|
|
|
count = ARRAY_count(class->ext_func);
|
|
|
|
|
if (count >= MAX_CLASS_EXTERN)
|
|
|
|
|
THROW("Too many external functions");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
extfunc = ARRAY_add_void(&class->ext_func);
|
|
|
|
|
TYPE_clear(&extfunc->type);
|
|
|
|
|
extfunc->nparam = 0;
|
|
|
|
|
extfunc->name = NO_SYMBOL;
|
|
|
|
|
|
|
|
|
|
if (!decl) return;
|
|
|
|
|
|
|
|
|
|
sym = CLASS_declare(class, decl->index, TRUE);
|
|
|
|
|
/*CLASS_add_symbol(class, JOB->table, decl->index, &sym, NULL);*/
|
|
|
|
|
|
|
|
|
|
sym->global.type = decl->type;
|
|
|
|
|
sym->global.value = ARRAY_count(class->ext_func) - 1;
|
|
|
|
|
|
|
|
|
|
extfunc->nparam = decl->nparam;
|
|
|
|
|
|
|
|
|
|
if (extfunc->nparam)
|
|
|
|
|
{
|
|
|
|
|
ALLOC(&extfunc->param, decl->nparam * sizeof(PARAM), "CLASS_add_extern");
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < decl->nparam; i++)
|
|
|
|
|
{
|
|
|
|
|
extfunc->param[i].type = decl->param[i].type;
|
|
|
|
|
extfunc->param[i].index = decl->param[i].index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extfunc->type = decl->type;
|
|
|
|
|
extfunc->name = decl->index;
|
|
|
|
|
extfunc->library = decl->library;
|
|
|
|
|
extfunc->alias = decl->alias;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
int CLASS_add_constant(CLASS *class, TRANS_DECL *decl)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
CONSTANT *desc;
|
|
|
|
|
int num;
|
|
|
|
|
|
|
|
|
|
num = ARRAY_count(class->constant);
|
2008-04-10 14:06:14 +02:00
|
|
|
|
if (num >= MAX_CLASS_CONST)
|
|
|
|
|
THROW("Too many constants");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
desc = ARRAY_add(&class->constant);
|
|
|
|
|
desc->type = decl->type;
|
|
|
|
|
desc->index = decl->index;
|
|
|
|
|
|
|
|
|
|
desc->value = decl->value;
|
|
|
|
|
if (TYPE_get_id(decl->type) == T_LONG)
|
|
|
|
|
desc->lvalue = decl->lvalue;
|
|
|
|
|
|
|
|
|
|
desc->line = JOB->line;
|
|
|
|
|
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
int CLASS_add_class(CLASS *class, int index)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
int num;
|
|
|
|
|
CLASS_REF *desc;
|
|
|
|
|
CLASS_SYMBOL *sym = CLASS_get_symbol(class, index);
|
|
|
|
|
|
|
|
|
|
num = sym->class - 1;
|
|
|
|
|
if (num < 0)
|
|
|
|
|
{
|
|
|
|
|
num = ARRAY_count(class->class);
|
2008-04-10 14:06:14 +02:00
|
|
|
|
if (num >= MAX_CLASS_CLASS)
|
|
|
|
|
THROW("Too many different classes used");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
desc = ARRAY_add(&class->class);
|
|
|
|
|
desc->index = index;
|
|
|
|
|
|
|
|
|
|
sym->class = num + 1;
|
|
|
|
|
|
|
|
|
|
if (JOB->verbose)
|
|
|
|
|
printf("Adding class %.*s\n", sym->symbol.len, sym->symbol.name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JOB->class->class[num].used = TRUE;
|
2008-05-14 00:35:48 +02:00
|
|
|
|
JOB->class->class[num].exported = FALSE;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
int CLASS_add_class_unused(CLASS *class, int index)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
int num = CLASS_add_class(class, index);
|
|
|
|
|
JOB->class->class[num].used = FALSE;
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-13 14:52:06 +02:00
|
|
|
|
int CLASS_add_class_exported(CLASS *class, int index)
|
|
|
|
|
{
|
|
|
|
|
int num = CLASS_add_class(class, index);
|
|
|
|
|
JOB->class->class[num].exported = TRUE;
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
2008-05-13 14:52:06 +02:00
|
|
|
|
bool CLASS_exist_class(CLASS *class, int index)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
return CLASS_get_symbol(class, index)->class > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
int CLASS_get_array_class(CLASS *class, int type)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
static char *name[] = {
|
|
|
|
|
NULL, "Boolean[]", "Byte[]", "Short[]", "Integer[]", "Long[]", "Single[]", "Float[]",
|
|
|
|
|
"Date[]", "String[]", "String[]", "Variant[]", NULL, NULL, NULL, NULL, "Object[]"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
if (type <= T_VOID || type > T_OBJECT)
|
|
|
|
|
return NO_SYMBOL;
|
|
|
|
|
|
|
|
|
|
index = _array_class[type];
|
|
|
|
|
|
|
|
|
|
if (index == 0)
|
|
|
|
|
{
|
|
|
|
|
if (!TABLE_find_symbol(class->table, name[type], strlen(name[type]), NULL, &index))
|
|
|
|
|
index = CLASS_add_symbol(class, name[type]);
|
|
|
|
|
index = CLASS_add_class(class, index);
|
|
|
|
|
_array_class[type] = index;
|
|
|
|
|
//printf("%s -> %ld\n", name[type], index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
int CLASS_add_unknown(CLASS *class, int index)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
int num;
|
|
|
|
|
int *desc;
|
|
|
|
|
CLASS_SYMBOL *sym = CLASS_get_symbol(class, index);
|
|
|
|
|
|
|
|
|
|
num = sym->unknown - 1;
|
|
|
|
|
if (num < 0)
|
|
|
|
|
{
|
|
|
|
|
num = ARRAY_count(class->unknown);
|
2008-04-10 14:06:14 +02:00
|
|
|
|
if (num >= MAX_CLASS_UNKNOWN)
|
|
|
|
|
THROW("Too many unknown symbols");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
desc = ARRAY_add(&class->unknown);
|
|
|
|
|
*desc = index;
|
|
|
|
|
|
|
|
|
|
sym->unknown = num + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
int CLASS_add_array(CLASS *class, TRANS_ARRAY *array)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
CLASS_ARRAY *desc;
|
|
|
|
|
int num;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
num = ARRAY_count(class->array);
|
2008-04-10 14:06:14 +02:00
|
|
|
|
if (num >= MAX_CLASS_ARRAY)
|
|
|
|
|
THROW("Too many array declarations");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
desc = ARRAY_add(&class->array);
|
|
|
|
|
desc->type = array->type;
|
|
|
|
|
desc->ndim = array->ndim;
|
|
|
|
|
for (i = 0; i < desc->ndim; i++)
|
|
|
|
|
desc->dim[i] = array->dim[i];
|
|
|
|
|
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void CLASS_add_declaration(CLASS *class, TRANS_DECL *decl)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
CLASS_SYMBOL *sym = CLASS_declare(class, decl->index, TRUE);
|
|
|
|
|
VARIABLE *var;
|
2008-04-10 14:06:14 +02:00
|
|
|
|
int count;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
sym->global.type = decl->type;
|
|
|
|
|
|
|
|
|
|
if (TYPE_get_kind(decl->type) == TK_CONST)
|
|
|
|
|
{
|
|
|
|
|
sym->global.value = CLASS_add_constant(class, decl);
|
|
|
|
|
}
|
|
|
|
|
else if (TYPE_is_static(decl->type))
|
|
|
|
|
{
|
2008-04-10 14:06:14 +02:00
|
|
|
|
count = ARRAY_count(class->stat);
|
|
|
|
|
if (count >= MAX_CLASS_SYMBOL)
|
|
|
|
|
THROW("Too many static variables");
|
|
|
|
|
|
|
|
|
|
sym->global.value = count;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
var = ARRAY_add(&class->stat);
|
|
|
|
|
|
|
|
|
|
var->type = decl->type;
|
|
|
|
|
var->index = decl->index;
|
|
|
|
|
var->pos = class->size_stat;
|
|
|
|
|
var->size = TYPE_sizeof(var->type);
|
|
|
|
|
|
|
|
|
|
class->size_stat += var->size;
|
|
|
|
|
|
|
|
|
|
CODE_begin_function(&class->function[FUNC_INIT_STATIC]);
|
|
|
|
|
if (TRANS_init_var(decl))
|
|
|
|
|
CODE_pop_global(sym->global.value, TRUE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-04-10 14:06:14 +02:00
|
|
|
|
count = ARRAY_count(class->dyn);
|
|
|
|
|
if (count >= MAX_CLASS_SYMBOL)
|
|
|
|
|
THROW("Too many dynamic variables");
|
|
|
|
|
|
|
|
|
|
sym->global.value = count;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
var = ARRAY_add(&class->dyn);
|
|
|
|
|
|
|
|
|
|
var->type = decl->type;
|
|
|
|
|
var->index = decl->index;
|
|
|
|
|
var->pos = class->size_dyn;
|
|
|
|
|
var->size = TYPE_sizeof(var->type);
|
|
|
|
|
|
|
|
|
|
class->size_dyn += var->size;
|
|
|
|
|
|
|
|
|
|
CODE_begin_function(&class->function[FUNC_INIT_DYNAMIC]);
|
|
|
|
|
if (TRANS_init_var(decl))
|
|
|
|
|
CODE_pop_global(sym->global.value, FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void reorder_decl(CLASS *class, VARIABLE *tvar, const char *desc)
|
|
|
|
|
{
|
|
|
|
|
int count;
|
|
|
|
|
int pos;
|
|
|
|
|
VARIABLE *var;
|
|
|
|
|
int i, j;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
/* variables statiques */
|
|
|
|
|
|
|
|
|
|
count = ARRAY_count(tvar);
|
|
|
|
|
if (count > 1)
|
|
|
|
|
{
|
|
|
|
|
if (JOB->verbose)
|
|
|
|
|
printf("Reordering %s variables:", desc);
|
|
|
|
|
|
|
|
|
|
pos = 0;
|
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < count; j++)
|
|
|
|
|
{
|
|
|
|
|
var = &tvar[j];
|
|
|
|
|
n = var->size & 3;
|
|
|
|
|
|
|
|
|
|
switch (i)
|
|
|
|
|
{
|
|
|
|
|
case 0: if (n != 0) continue; else break;
|
|
|
|
|
case 1: if (n != 2) continue; else break;
|
|
|
|
|
case 2: if (n != 1 && n != 3) continue; else break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var->pos = pos;
|
|
|
|
|
pos += var->size;
|
|
|
|
|
|
|
|
|
|
if (JOB->verbose)
|
2008-07-18 01:45:32 +02:00
|
|
|
|
printf(" %s (%d) ", TABLE_get_symbol_name(class->table, var->index), var->pos);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (JOB->verbose)
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void CLASS_sort_declaration(CLASS *class)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
reorder_decl(class, class->stat, "static");
|
|
|
|
|
reorder_decl(class, class->dyn, "dynamic");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
int CLASS_add_symbol(CLASS *class, const char *name)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
TABLE_add_symbol(class->table, name, strlen(name), NULL, &index);
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void FUNCTION_add_pos_line(void)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
short *pos;
|
|
|
|
|
|
|
|
|
|
if (JOB->debug)
|
|
|
|
|
{
|
|
|
|
|
pos = ARRAY_add(&JOB->func->pos_line);
|
|
|
|
|
*pos = CODE_get_current_pos();
|
|
|
|
|
//printf("line %ld : %d\n", ARRAY_count(JOB->func->pos_line) - 1, *pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
char *FUNCTION_get_fake_name(int func)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
static char buf[6];
|
|
|
|
|
|
2008-01-06 21:06:44 +01:00
|
|
|
|
snprintf(buf, sizeof(buf), "$%d", func);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int check_one_property_func(CLASS *class, PROPERTY *prop, bool write)
|
|
|
|
|
{
|
|
|
|
|
CLASS_SYMBOL *sym;
|
|
|
|
|
char *name;
|
|
|
|
|
bool is_static;
|
|
|
|
|
FUNCTION *func;
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
JOB->line = prop->line;
|
|
|
|
|
|
|
|
|
|
is_static = TYPE_is_static(prop->type);
|
|
|
|
|
|
|
|
|
|
name = STR_copy(TABLE_get_symbol_name_suffix(class->table, prop->name, write ? "_Write" : "_Read"));
|
|
|
|
|
|
|
|
|
|
if (!TABLE_find_symbol(class->table, name, strlen(name), (SYMBOL **)(void *)&sym, &index))
|
|
|
|
|
THROW("&1 is not declared", name);
|
|
|
|
|
|
|
|
|
|
if (TYPE_get_kind(sym->global.type) != TK_FUNCTION)
|
|
|
|
|
THROW("&1 is declared but is not a function", name);
|
|
|
|
|
|
|
|
|
|
func = &class->function[sym->global.value];
|
|
|
|
|
JOB->line = func->line;
|
|
|
|
|
|
|
|
|
|
if (TYPE_is_public(sym->global.type))
|
|
|
|
|
THROW("A property implementation cannot be public");
|
|
|
|
|
|
|
|
|
|
if (is_static != TYPE_is_static(sym->global.type))
|
|
|
|
|
{
|
|
|
|
|
if (is_static)
|
|
|
|
|
THROW("&1 must be static", name);
|
|
|
|
|
else
|
|
|
|
|
THROW("&1 cannot be static", name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (write)
|
|
|
|
|
{
|
|
|
|
|
if (TYPE_get_id(func->type) != T_VOID)
|
|
|
|
|
goto _BAD_SIGNATURE;
|
|
|
|
|
|
|
|
|
|
if (func->nparam != 1 || func->npmin != 1)
|
|
|
|
|
goto _BAD_SIGNATURE;
|
|
|
|
|
|
|
|
|
|
if (!TYPE_compare(&func->param[0].type, &prop->type))
|
|
|
|
|
goto _BAD_SIGNATURE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!TYPE_compare(&func->type, &prop->type))
|
|
|
|
|
goto _BAD_SIGNATURE;
|
|
|
|
|
|
|
|
|
|
if (func->nparam != 0 || func->npmin != 0)
|
|
|
|
|
goto _BAD_SIGNATURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STR_free(name);
|
|
|
|
|
return sym->global.value;
|
|
|
|
|
|
|
|
|
|
_BAD_SIGNATURE:
|
|
|
|
|
|
|
|
|
|
THROW("&1 declaration does not match", name);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-06 19:49:23 +01:00
|
|
|
|
void CLASS_check_properties(CLASS *class)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
PROPERTY *prop;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_count(class->prop); i++)
|
|
|
|
|
{
|
|
|
|
|
prop = &class->prop[i];
|
|
|
|
|
|
|
|
|
|
prop->read = check_one_property_func(class, prop, FALSE);
|
|
|
|
|
if (prop->write)
|
|
|
|
|
prop->write = check_one_property_func(class, prop, TRUE);
|
|
|
|
|
else
|
|
|
|
|
prop->write = NO_SYMBOL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|