gambas-source-code/main/gbc/gbc_header.c
Benoît Minisini a0ecaa77e6 [CONFIGURATION]
* BUG: Automatically search libraries in lib64 before searching in lib.
* BUG: Fixed the $FFI_LIB test in main/configure.ac.

[DEVELOPMENT ENVIRONMENT]
* BUG: Tips of the days are displayed correctly again.

[INTERPRETER]
* BUG: Val() now takes the thousand separator into account when this 
  separator is a space character.
* BUG: Removed the 64 bits warning.
* BUG: Fixes the 'lib64' problem. Now components are searched in the 'lib64' 
  directory on 64 bits OS. If they are not stored in 'lib64', then the 
  default 'lib' directory is used.
* NEW: Passing argument by reference is not allowed anymore if not 
  explicitely specified in the method declaration.

[COMPILER]
* NEW: Passing argument by reference is not allowed anymore if not 
  explicitely specified in the method declaration.

[INFORMER]
* BUG: Fixes the 'lib64' problem. Now components are searched in the 'lib64' 
  directory on 64 bits OS. If they are not stored in 'lib64', then the 
  default 'lib' directory is used.


git-svn-id: svn://localhost/gambas/trunk@1108 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-02-24 16:29:02 +00:00

823 lines
17 KiB
C
Raw Blame History

/***************************************************************************
header.c
Analyzing class description
(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 _TRANS_HEADER_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 "gbc_trans.h"
#include "gbc_header.h"
/*#define DEBUG*/
static void analyze_function_desc(TRANS_FUNC *func, int flag)
{
PATTERN *look = JOB->current;
TRANS_PARAM *param;
bool is_output;
bool is_optional = FALSE;
TRANS_DECL ttyp;
uint64_t byref_mask = 1;
if (!PATTERN_is_identifier(*look))
THROW("Syntax error. Invalid identifier in function name");
func->index = PATTERN_index(*look);
look++;
if (flag & HF_EVENT)
TABLE_copy_symbol_with_prefix(JOB->class->table, func->index, ':', NULL, &func->index);
func->nparam = 0;
func->byref = 0;
func->vararg = FALSE;
if ((flag & HF_VOID) && PATTERN_is_newline(*look))
{
JOB->current = ++look;
return;
}
if (!PATTERN_is(*look, RS_LBRA))
THROW(E_UNEXPECTED, READ_get_pattern(look));
look++;
for(;;)
{
param = &func->param[func->nparam];
if (PATTERN_is(*look, RS_RBRA))
{
look++;
break;
}
if (func->nparam > 0)
{
if (!PATTERN_is(*look, RS_COMMA))
THROW("Syntax error. Missing ',' or ')'");
look++;
}
if (PATTERN_is(*look, RS_3PTS))
{
look++;
if (!PATTERN_is(*look, RS_RBRA))
THROW("Syntax error. '...' must be the last argument"); //, get_num_desc(func->nparam + 1));
look++;
func->vararg = TRUE;
break;
}
is_output = FALSE;
if (!(flag & HF_NO_OPT))
{
if (PATTERN_is(*look, RS_OPTIONAL))
{
look++;
is_optional = TRUE;
}
}
if (PATTERN_is(*look, RS_AT) || PATTERN_is(*look, RS_BYREF))
{
func->byref |= byref_mask;
look++;
}
if (!PATTERN_is_identifier(*look))
THROW("Syntax error. The &1 argument is not a valid identifier", TRANS_get_num_desc(func->nparam + 1));
param->index = PATTERN_index(*look);
look++;
JOB->current = look;
if (!TRANS_type(TT_NOTHING, &ttyp))
THROW("Syntax error. Invalid type description of &1 argument", TRANS_get_num_desc(func->nparam + 1));
param->type = ttyp.type;
/*
if (is_output)
TYPE_set_flag(&param->type, TF_OUTPUT);
*/
look = JOB->current;
if (is_optional)
{
param->optional = look;
for(;;)
{
if (PATTERN_is(*look, RS_COMMA) || PATTERN_is(*look, RS_RBRA) || PATTERN_is_newline(*look))
break;
look++;
}
JOB->current = look;
}
func->nparam++;
byref_mask <<= 1;
}
JOB->current = look;
}
static void header_module_type(void)
{
const char *ext;
/*JOB->class->name = STR_copy(FILE_get_name(JOB->name));*/
ext = FILE_get_ext(JOB->name);
if (strcasecmp(ext, "module") == 0)
{
JOB->is_module = TRUE;
JOB->is_form = FALSE;
}
else if (strcasecmp(ext, "class") == 0)
{
JOB->is_module = FALSE;
JOB->is_form = FALSE;
}
else if (strcasecmp(ext, "form") == 0)
{
JOB->is_module = FALSE;
JOB->is_form = TRUE;
}
else
THROW("Unknown file extension");
JOB->declared = TRUE;
}
static bool header_event(TRANS_EVENT *event)
{
PATTERN *look = JOB->current;
TRANS_DECL ttyp;
if (!PATTERN_is(*look, RS_EVENT))
return FALSE;
CLEAR(event);
if (JOB->is_module)
THROW("A module cannot raise events");
JOB->current++;
analyze_function_desc((TRANS_FUNC *)event, HF_VOID);
if (PATTERN_is(*JOB->current, RS_AS))
{
if (!TRANS_type(TT_CAN_SQUARE, &ttyp))
THROW("Syntax error in return type");
event->type = ttyp.type;
}
TYPE_set_kind(&event->type, TK_EVENT);
TYPE_set_flag(&event->type, TF_PUBLIC);
return TRUE;
}
static bool header_property(TRANS_PROPERTY *prop)
{
TRANS_DECL ptype;
PATTERN *look = JOB->current;
bool is_static = FALSE;
bool is_public = TRUE;
CLEAR(prop);
/* static */
if (JOB->is_module)
{
is_static = TRUE;
}
else if (PATTERN_is(*look, RS_STATIC))
{
is_static = TRUE;
look++;
}
/* public */
if (PATTERN_is(*look, RS_PUBLIC) || PATTERN_is(*look, RS_PRIVATE))
{
is_public = PATTERN_is(*look, RS_PUBLIC);
look++;
}
if (!PATTERN_is(*look, RS_PROPERTY))
return FALSE;
look++;
JOB->current = look;
if (!is_public)
THROW("A property must be public");
/* read-only property */
if (PATTERN_is(*JOB->current, RS_READ))
{
prop->read = TRUE;
JOB->current++;
}
else
prop->read = FALSE;
/* property name */
if (!PATTERN_is_identifier(*JOB->current))
THROW("Syntax error. Invalid identifier in property name");
prop->index = PATTERN_index(*JOB->current);
JOB->current++;
if (!TRANS_type(TT_CAN_SQUARE, &ptype))
THROW("Syntax error. Bad property type");
prop->type = ptype.type;
prop->line = JOB->line;
TYPE_set_kind(&prop->type, TK_PROPERTY);
if (is_static)
TYPE_set_flag(&prop->type, TF_STATIC);
TYPE_set_flag(&prop->type, TF_PUBLIC);
if (PATTERN_is_string(*JOB->current))
{
prop->comment = PATTERN_index(*JOB->current);
JOB->current++;
}
else
prop->comment = NO_SYMBOL;
return TRUE;
}
static bool header_extern(TRANS_EXTERN *trans)
{
PATTERN *look = JOB->current;
TRANS_DECL ttyp;
int index;
bool is_public;
/* public ? */
is_public = JOB->is_module && JOB->public_module;
if (PATTERN_is(*look, RS_PUBLIC))
{
is_public = TRUE;
look++;
}
else if (PATTERN_is(*look, RS_PRIVATE))
{
is_public = FALSE;
look++;
}
if (!PATTERN_is(*look, RS_EXTERN))
return FALSE;
look++;
CLEAR(trans);
JOB->current = look;
analyze_function_desc((TRANS_FUNC *)trans, HF_NO_3PTS);
if (PATTERN_is(*JOB->current, RS_AS))
{
if (!TRANS_type(TT_CAN_SQUARE, &ttyp))
THROW("Syntax error in return type");
trans->type = ttyp.type;
}
if (TRANS_is(RS_IN))
{
if (!PATTERN_is_string(*JOB->current))
THROW("Library name must be a string");
index = PATTERN_index(*JOB->current);
JOB->current++;
}
else
{
if (JOB->default_library == NO_SYMBOL)
THROW("IN missing");
index = JOB->default_library;
}
trans->library = index;
if (TRANS_is(RS_EXEC))
{
if (!PATTERN_is_string(*JOB->current))
THROW("Alias name must be a string");
trans->alias = PATTERN_index(*JOB->current);
JOB->current++;
}
else
trans->alias = NO_SYMBOL;
TYPE_set_kind(&trans->type, TK_EXTERN);
TYPE_set_flag(&trans->type, TF_STATIC);
if (is_public) TYPE_set_flag(&trans->type, TF_PUBLIC);
return TRUE;
}
static bool header_class(TRANS_DECL *decl)
{
if (!PATTERN_is(*JOB->current, RS_CLASS))
return FALSE;
JOB->current++;
if (!PATTERN_is_identifier(*JOB->current))
THROW("Syntax error. CLASS needs an identifier");
CLEAR(decl);
decl->index = PATTERN_index(*JOB->current);
JOB->current++;
return TRUE;
}
static bool header_declaration(TRANS_DECL *decl)
{
PATTERN *look = JOB->current;
PATTERN *save;
bool is_static = FALSE;
bool is_public = FALSE;
bool is_const = FALSE;
/*bool other = FALSE;*/
/* static ! */
if (JOB->is_module)
{
is_static = TRUE;
}
else if (PATTERN_is(*look, RS_STATIC))
{
is_static = TRUE;
look++;
}
/* public or private ? */
is_public = JOB->is_module && JOB->public_module;
if (PATTERN_is(*look, RS_PUBLIC))
{
is_public = TRUE;
look++;
}
else if (PATTERN_is(*look, RS_PRIVATE))
{
is_public = FALSE;
look++;
}
/* const ? */
is_const = FALSE;
if (PATTERN_is(*look, RS_CONST))
{
/* static const <=> const */
/*
if (is_static)
return FALSE;
*/
is_const = TRUE;
look++;
}
if (!PATTERN_is_identifier(*look))
return FALSE;
CLEAR(decl);
decl->index = PATTERN_index(*look);
look++;
save = JOB->current;
JOB->current = look;
if (!TRANS_type(((!is_const && !is_public) ? (TT_CAN_SQUARE | TT_CAN_ARRAY) : 0) | TT_CAN_NEW, decl))
{
JOB->current = save;
return FALSE;
}
if (is_static) TYPE_set_flag(&decl->type, TF_STATIC);
if (is_public) TYPE_set_flag(&decl->type, TF_PUBLIC);
if (is_const)
TYPE_set_kind(&decl->type, TK_CONST);
else
TYPE_set_kind(&decl->type, TK_VARIABLE);
if (is_const)
{
if (!decl->init)
THROW("Syntax error. Missing '='");
JOB->current = decl->init;
JOB->current = TRANS_get_constant_value(decl, JOB->current);
}
//JOB->current = look;
return TRUE;
}
static bool header_function(TRANS_FUNC *func)
{
static HEADER_SPECIAL spec[] =
{
{ "_init", HS_PUBLIC + HS_STATIC + HS_PROCEDURE + HS_NOPARAM },
{ "_exit", HS_PUBLIC + HS_STATIC + HS_PROCEDURE + HS_NOPARAM},
{ "_new", HS_PUBLIC + HS_DYNAMIC + HS_PROCEDURE },
{ "_free", HS_PUBLIC + HS_DYNAMIC + HS_PROCEDURE + HS_NOPARAM },
{ "_call", HS_PUBLIC },
{ "_get", HS_PUBLIC + HS_FUNCTION },
{ "_put", HS_PUBLIC + HS_PROCEDURE + HS_PUT },
{ "_next", HS_PUBLIC + HS_NOPARAM },
{ "_unknown", HS_PUBLIC + HS_UNKNOWN },
{ "_compare", HS_PUBLIC + HS_DYNAMIC + HS_FUNCTION + HS_COMPARE },
{ NULL, 0 }
};
PATTERN *look = JOB->current;
PATTERN pat;
TRANS_DECL ttyp;
SYMBOL *sym;
HEADER_SPECIAL *hsp;
bool is_proc = FALSE;
bool is_static = FALSE;
bool is_public = FALSE;
/* static ? */
if (JOB->is_module)
{
is_static = TRUE;
}
else if (PATTERN_is(*look, RS_STATIC))
{
is_static = TRUE;
look++;
}
/* public ou static ? */
is_public = JOB->is_module && JOB->public_module;
if (PATTERN_is(*look, RS_PUBLIC))
{
is_public = TRUE;
look++;
}
else if (PATTERN_is(*look, RS_PRIVATE))
{
is_public = FALSE;
look++;
}
if (PATTERN_is(*look, RS_PROCEDURE) || PATTERN_is(*look, RS_SUB))
is_proc = TRUE;
else if (!PATTERN_is(*look, RS_FUNCTION))
return FALSE;
look++;
CLEAR(func);
JOB->current = look;
analyze_function_desc(func, HF_NORMAL);
//if (!is_proc)
if (PATTERN_is(*JOB->current, RS_AS))
{
if (!TRANS_type(TT_CAN_SQUARE, &ttyp))
THROW("Syntax error. Invalid return type");
func->type = ttyp.type;
is_proc = FALSE;
}
TYPE_set_kind(&func->type, TK_FUNCTION);
if (is_static) TYPE_set_flag(&func->type, TF_STATIC);
if (is_public) TYPE_set_flag(&func->type, TF_PUBLIC);
/* On v<>ifie les m<>hodes sp<73>iales */
sym = TABLE_get_symbol(JOB->class->table, func->index);
if (*sym->name == '_')
{
for (hsp = spec; hsp->name; hsp++)
{
if (sym->len != strlen(hsp->name))
continue;
if (strncmp(sym->name, hsp->name, sym->len))
continue;
if (hsp->flag == HS_ERROR)
THROW("The special method &1 cannot be implemented", hsp->name);
if ((hsp->flag & HS_PUBLIC) && !is_public)
THROW("The special method &1 must be public", hsp->name);
if ((hsp->flag & HS_STATIC) && !is_static)
THROW("The special method &1 must be static", hsp->name);
if ((hsp->flag & HS_DYNAMIC) && is_static)
THROW("The special method &1 cannot be static", hsp->name);
if ((hsp->flag & HS_PROCEDURE) && !is_proc)
THROW("The special method &1 cannot be a function", hsp->name);
if ((hsp->flag & HS_FUNCTION) && is_proc)
THROW("The special method &1 must be a function", hsp->name);
if ((hsp->flag & HS_NOPARAM) && func->nparam > 0)
THROW("The special method &1 takes no arguments", hsp->name);
if (hsp->flag & HS_PUT)
{
if (func->nparam < 1)
THROW("The special method &1 must take at least one argument", hsp->name);
}
if (hsp->flag & HS_UNKNOWN)
{
if (func->nparam > 0 || !func->vararg)
THROW("The special method &1 must take a variable number of arguments only", hsp->name);
}
if (hsp->flag & HS_COMPARE)
{
if (func->type.t.id != T_INTEGER)
THROW("The special method must return an integer");
if (func->nparam != 1)
THROW("The special method must take exactly one argument");
}
break;
}
}
/* on saute le corps de la fonction */
if (!PATTERN_is_newline(*(JOB->current)))
THROW("Syntax error after function declaration");
func->line = PATTERN_index(*(JOB->current)) + 1; /* <20> commence <20>la ligne suivante ! */
func->start = JOB->current + 1;
for(;;)
{
pat = *JOB->current;
if (PATTERN_is_end(pat) || PATTERN_is_command(pat))
{
THROW("Missing END");
}
if (PATTERN_is_newline(pat))
if (PATTERN_is(JOB->current[1], RS_END))
{
if (PATTERN_is_newline(JOB->current[2]))
{
JOB->current += 2;
break;
}
if (TRANS_is_end_function(is_proc, &JOB->current[2]))
{
JOB->current += 3;
break;
}
}
JOB->current++;
}
return TRUE;
}
static bool header_inherits(void)
{
int index;
if (!PATTERN_is(*JOB->current, RS_INHERITS))
return FALSE;
/*{
if (!(PATTERN_is(JOB->current[0], RS_CLASS)
&& PATTERN_is(JOB->current[1], RS_INHERITS)))
return FALSE;
JOB->current++;
}*/
JOB->current++;
if (!PATTERN_is_class(*JOB->current))
THROW("Syntax error. INHERITS needs a class name");
if (JOB->class->parent != NO_SYMBOL)
THROW("Cannot inherit twice");
index = PATTERN_index(*JOB->current);
JOB->class->parent = CLASS_add_class(JOB->class, index);
/*printf("JOB->class->parent = %d\n", JOB->class->parent);*/
JOB->current++;
return TRUE;
}
static bool header_option(void)
{
if (PATTERN_is(JOB->current[0], RS_EXPORT))
{
JOB->current++;
JOB->class->exported = TRUE;
if (PATTERN_is(JOB->current[0], RS_OPTIONAL))
{
JOB->current++;
JOB->class->optional = TRUE;
}
return TRUE;
}
if (PATTERN_is(JOB->current[0], RS_CREATE))
{
JOB->current++;
if (PATTERN_is_newline(JOB->current[0]) || PATTERN_is(JOB->current[0], RS_STATIC))
{
JOB->class->autocreate = TRUE;
if (PATTERN_is(JOB->current[0], RS_STATIC))
JOB->current++;
return TRUE;
}
else if (PATTERN_is(JOB->current[0], RS_PRIVATE))
{
JOB->class->nocreate = TRUE;
JOB->current++;
return TRUE;
}
}
return FALSE;
}
static bool header_library(void)
{
if (!TRANS_is(RS_LIBRARY))
return FALSE;
if (!PATTERN_is_string(*JOB->current))
THROW("Library name must be a string");
JOB->default_library = PATTERN_index(*JOB->current);
JOB->current++;
return TRUE;
}
PUBLIC void HEADER_do(void)
{
union {
TRANS_DECL decl;
TRANS_FUNC func;
TRANS_EVENT event;
TRANS_EXTERN ext;
TRANS_PROPERTY prop;
} trans;
TRANS_reset();
header_module_type();
while (JOB->current < JOB->end)
{
if (PATTERN_is_end(*JOB->current))
break;
if (TRANS_newline())
continue;
if (header_function(&trans.func))
{
CLASS_add_function(JOB->class, &trans.func);
continue;
}
if (header_event(&trans.event))
{
CLASS_add_event(JOB->class, &trans.event);
continue;
}
if (header_property(&trans.prop))
{
CLASS_add_property(JOB->class, &trans.prop);
continue;
}
if (header_extern(&trans.ext))
{
CLASS_add_extern(JOB->class, &trans.ext);
continue;
}
if (header_declaration(&trans.decl))
{
CLASS_add_declaration(JOB->class, &trans.decl);
continue;
}
if (header_class(&trans.decl))
{
CLASS_add_class(JOB->class, trans.decl.index);
continue;
}
if (header_inherits())
continue;
if (header_option())
continue;
if (header_library())
continue;
if (PATTERN_is_command(*JOB->current))
{
JOB->current++;
continue;
}
THROW(E_UNEXPECTED, READ_get_pattern(JOB->current));
}
/* R<>rganisation des variables statiques et dynamiques
pour <20>iter les probl<62>es d'alignement
*/
CLASS_sort_declaration(JOB->class);
if (JOB->verbose)
CLASS_dump();
}