gambas-source-code/main/gbc/gbc_dump.c
Benoît Minisini 5acae8e8bb [WIKI CGI SCRIPT]
* NEW: Do not use <pre> markups, they cannot break lines.

[DEVELOPMENT ENVIRONMENT]
* NEW: Replace anonymous object arrays by template arrays.
* NEW: A button that clears the shortcut in the menu editor.
* NEW: When evaluating expression in the console, a semi-colon at the end 
  of the expression prevents the end newline to be printed, like in the 
  PRINT instruction.
* NEW: CTRL+G in the console makes it flash.
* OPT: Remove the CCoolTabs class, that was not used anymore.
* NEW: The main selected control is unselectable in the form editor now.
* NEW: Selected controls can be resized by pressing CTRL and an arrow key.
* NEW: Some form editor shortcuts have been changed to not conflict with
  the previous feature.
* BUG: Fix the horizontal position of the automatic completion.
* BUG: Look in project classes before component classes in automatic 
  completion.

[INTERPRETER]
* BUG: Fix the memory allocation debug routines.
* BUG: When instanciating a template array class, search for element class 
  symbol locally first.
* BUG: Template arrays now correctly release their elements.
* NEW: Update copyright year in gb_common.h header file.

[COMPILER]
* BUG: Manage .list and .info files incrementally, so that they are up to 
  date even when the project is not fully compiled.
* BUG: Float and Single constants are correctly written in the .info file.

[GB.QT.EXT]
* BUG: Fix some painting artifacts in Editor.
* BUG: In Editor, Undo and Redo now should always work correctly when a 
  line is rewritten.
* NEW: In Editor, when a line is rewritten, the Change event is always 
  emitted.
* NEW: The Editor is cleared now when it prints a CTRL+L character.
* NEW: The Editor flashes now when it prints a CTRL+G character.


git-svn-id: svn://localhost/gambas/trunk@1576 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-09-21 23:22:07 +00:00

630 lines
11 KiB
C

/***************************************************************************
dump.c
Class dumping
(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_DUMP_C
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "gb_common.h"
#include "gb_common_buffer.h"
#include "gb_error.h"
#include "gb_table.h"
#include "gbc_compile.h"
#include "gb_code.h"
#include "gb_file.h"
#include "gbc_chown.h"
static FILE *_finfo;
static const char *get_name(int index)
{
return TABLE_get_symbol_name(JOB->class->table, index);
}
static const char *get_string(int index)
{
return TABLE_get_symbol_name(JOB->class->string, index);
}
static void dump_name(int index)
{
printf("%s", get_name(index));
}
static void dump_type(TYPE type, boolean as)
{
int value;
TYPE_ID id;
CLASS_ARRAY *array;
int i;
id = TYPE_get_id(type);
value = TYPE_get_value(type);
if (id == T_ARRAY)
{
array = &JOB->class->array[value];
printf("[");
for (i = 0; i < array->ndim; i++)
{
if (i > 0)
printf(",");
printf("%d", array->dim[i]);
}
printf("] AS ");
dump_type(array->type, FALSE);
}
else if (id == T_OBJECT && value >= 0)
{
if (as)
printf(" AS ");
dump_name(JOB->class->class[value].index);
}
else
{
if (as)
printf(" AS ");
printf("%s", TYPE_get_desc(type));
}
}
static void dump_function(FUNCTION *func)
{
int i;
printf("(");
for (i = 0; i < func->nparam; i++)
{
if (i > 0) printf(", ");
if (i == func->npmin)
printf("OPTIONAL ");
dump_name(func->param[i].index);
dump_type(func->param[i].type, TRUE);
}
if (func->vararg)
{
if (func->nparam > 0)
printf(", ");
printf("...");
}
printf(")");
}
PUBLIC void CLASS_dump(void)
{
int i;
TYPE type;
CLASS_SYMBOL *sym;
CLASS *class = JOB->class;
if (JOB->is_module)
printf("MODULE ");
else if (JOB->is_form)
printf("FORM ");
else
printf("CLASS ");
printf("%s\n", class->name);
if (class->parent != NO_SYMBOL)
{
printf("CLASS INHERITS ");
dump_name(class->class[class->parent].index);
putchar('\n');
}
if (class->exported)
printf("EXPORT\n");
if (class->autocreate)
printf("CREATE\n");
if (class->optional)
printf("OPTIONAL\n");
putchar('\n');
printf("Static size : %d octets\n", class->size_stat);
printf("Dynamic size : %d octets\n\n", class->size_dyn);
for (i = 0; i < TABLE_count(class->table); i++)
{
sym = CLASS_get_symbol(class, i);
type = sym->global.type;
if (TYPE_is_null(type))
continue;
if (TYPE_is_static(type)) printf("STATIC ");
if (TYPE_is_public(type)) printf("PUBLIC "); else printf("PRIVATE ");
switch(TYPE_get_kind(type))
{
case TK_VARIABLE:
dump_name(i);
dump_type(type, TRUE);
break;
case TK_FUNCTION:
if (TYPE_get_id(type) == T_VOID)
printf("PROCEDURE ");
else
printf("FUNCTION ");
dump_name(i);
dump_function(&class->function[sym->global.value]);
break;
case TK_CONST:
printf("CONST ");
dump_name(i);
dump_type(type, TRUE);
printf(" = ");
dump_name(class->constant[sym->global.value].index);
break;
case TK_PROPERTY:
printf("PROPERTY ");
if (class->prop[sym->global.value].write == NO_SYMBOL)
printf("READ ");
dump_name(i);
dump_type(type, TRUE);
break;
case TK_EVENT:
printf("EVENT ");
dump_name(i);
break;
case TK_UNKNOWN: printf("UNKNOWN "); break;
case TK_EXTERN: printf("EXTERN "); break;
case TK_LABEL: printf("LABEL "); break;
}
putchar('\n');
/*
if (TYPE_get_kind(type) == TK_FUNCTION)
{
func = &class->function[value];
printf(" L:%ld", func->line);
}
else if (TYPE_get_kind(type) == TK_EVENT)
func = (FUNCTION *)&class->event[value];
else if (TYPE_get_kind(type) == TK_EXTERN)
{
func = (FUNCTION *)&class->ext_func[value];
printf(" in %s", TABLE_get_symbol_name(class->table, class->ext_func[value].library));
}
*/
}
putchar('\n');
}
static void export_newline(void)
{
fputc('\n', _finfo);
}
static void export_type(TYPE type, bool scomma)
{
int value;
TYPE_ID id;
id = TYPE_get_id(type);
value = TYPE_get_value(type);
if (id == T_OBJECT && value >= 0)
{
fprintf(_finfo, get_name(JOB->class->class[value].index));
if (scomma)
fputc(';', _finfo);
}
else
fprintf(_finfo, TYPE_get_short_desc(type));
}
static void export_signature(int nparam, int npmin, PARAM *param, bool vararg)
{
int i;
for (i = 0; i < nparam; i++)
{
if (i == npmin)
fprintf(_finfo, "[");
fprintf(_finfo, "(%s)", get_name(param[i].index));
export_type(param[i].type, TRUE);
}
if (npmin < nparam)
fprintf(_finfo, "]");
if (vararg)
fprintf(_finfo, ".");
export_newline();
}
static void create_file(FILE **fw, const char *file)
{
if (!*fw)
{
*fw = fopen(file, "w");
if (!*fw)
THROW("Cannot create file: &1", FILE_cat(FILE_get_dir(COMP_project), file, NULL));
}
}
static char *read_line(FILE *f, int *plen)
{
int len;
char *line;
if (!f)
return NULL;
line = fgets(COMMON_buffer, COMMON_BUF_MAX, f);
if (!line)
return NULL;
len = strlen(line);
if (line[len - 1] == '\n')
{
line[len - 1] = 0;
len--;
}
if (plen)
*plen = len;
return line;
}
static void close_file_and_rename(FILE *f, const char *file, const char *dest)
{
if (f)
{
fclose(f);
unlink(dest);
rename(file, dest);
FILE_set_owner(dest, COMP_project);
}
else
{
unlink(file);
unlink(dest);
}
}
static void class_update_exported(CLASS *class)
{
FILE *fw = NULL;
FILE *fr;
char *name;
int len;
bool inserted = FALSE;
int cmp;
fr = fopen(".list", "r");
if (!fr && !class->exported)
return;
for(;;)
{
name = read_line(fr, &len);
if (!name)
{
cmp = 1;
}
else
{
if (name[len - 1] == '?')
{
char cname[strlen(class->name) + 2];
strcpy(cname, class->name);
strcat(cname, "?");
cmp = strcmp(name, cname);
}
else
cmp = strcmp(name, class->name);
}
if (cmp == 0)
{
if (JOB->verbose)
printf("Remove '%s' from .list file\n", name);
continue;
}
else if ((cmp > 0) && class->exported && !inserted)
{
create_file(&fw, ".list#");
if (JOB->verbose)
printf("Insert '%s%s' into .list file\n", class->name, class->optional ? "?" : "");
fputs(class->name, fw);
if (class->optional)
fputc('?', fw);
fputc('\n', fw);
inserted = TRUE;
}
if (!name)
break;
if (JOB->verbose)
printf("Copy '%s' in .list file\n", name);
create_file(&fw, ".list#");
fputs(name, fw);
fputc('\n', fw);
}
if (fr)
fclose(fr);
close_file_and_rename(fw, ".list#", ".list");
}
static void insert_class_info(CLASS *class, FILE *fw)
{
int i;
TYPE type;
CLASS_SYMBOL *sym;
char kind;
int val;
FUNCTION *func;
EVENT *event;
EXTFUNC *extfunc;
CONSTANT *cst;
if (JOB->verbose)
printf("Insert '%s' information into .info file\n", class->name);
_finfo = fw;
fprintf(_finfo, "#%s\n", class->name);
if (class->parent != NO_SYMBOL)
fprintf(_finfo, "%s", get_name(JOB->class->class[class->parent].index));
export_newline();
if (!class->nocreate)
fprintf(_finfo, "C");
if (class->autocreate)
fprintf(_finfo, "A");
if (class->optional)
fprintf(_finfo, "O");
export_newline();
for (i = 0; i < TABLE_count(class->table); i++)
{
sym = CLASS_get_symbol(class, i);
type = sym->global.type;
if (TYPE_is_null(type))
continue;
if (!TYPE_is_public(type))
continue;
switch(TYPE_get_kind(type))
{
case TK_CONST:
kind = 'C';
break;
case TK_FUNCTION:
kind = 'm';
break;
case TK_PROPERTY:
if (class->prop[sym->global.value].write == NO_SYMBOL)
kind = 'r';
else
kind = 'p';
break;
case TK_EVENT:
kind = ':';
break;
case TK_EXTERN:
kind = 'X';
break;
default:
continue;
}
fprintf(_finfo, "%s\n", get_name(i));
fprintf(_finfo, "%c\n", TYPE_is_static(type) ? toupper(kind) : kind);
export_type(type, FALSE);
if (kind == 'r' || kind == 'p')
{
val = class->prop[sym->global.value].comment;
if (val != NO_SYMBOL)
fprintf(_finfo, "%s", get_string(val));
}
export_newline();
switch(kind)
{
case 'C':
cst = &class->constant[sym->global.value];
switch(TYPE_get_id(type))
{
case T_BOOLEAN:
case T_BYTE:
case T_SHORT:
case T_INTEGER:
fprintf(_finfo, "%d\n", cst->value);
break;
case T_LONG:
fprintf(_finfo, "%" PRId64 "\n", cst->lvalue);
break;
case T_SINGLE:
case T_FLOAT:
fprintf(_finfo, "%s\n", get_name(cst->value));
break;
case T_STRING:
fprintf(_finfo, "%s\n", get_string(cst->value));
break;
default:
export_newline();
break;
}
break;
case 'm':
func = &class->function[sym->global.value];
export_signature(func->nparam, func->npmin, func->param, func->vararg);
break;
case ':':
event = &class->event[sym->global.value];
export_signature(event->nparam, event->nparam, event->param, FALSE);
break;
case 'X':
extfunc = &class->ext_func[sym->global.value];
export_signature(extfunc->nparam, extfunc->nparam, extfunc->param, FALSE);
break;
default:
export_newline();
}
}
}
PUBLIC void CLASS_export(void)
{
FILE *fw = NULL;
FILE *fr;
char *line;
int len;
bool inserted = FALSE;
CLASS *class = JOB->class;
int cmp;
chdir(FILE_get_dir(COMP_project));
class_update_exported(class);
fr = fopen(".info", "r");
line = read_line(fr, &len);
for(;;)
{
if (!line)
cmp = 1;
else
cmp = strcmp(&line[1], class->name);
if (cmp == 0)
{
if (JOB->verbose)
printf("Remove '%s' information from .info file\n", class->name);
for(;;)
{
line = read_line(fr, &len);
if (!line || *line == '#')
break;
}
continue;
}
if (cmp > 0 && class->exported && !inserted)
{
create_file(&fw, ".info#");
insert_class_info(class, fw);
inserted = TRUE;
}
if (!line)
break;
// copying class information
if (JOB->verbose)
printf("Copy '%s' information in .info file\n", &line[1]);
for(;;)
{
create_file(&fw, ".info#");
fputs(line, fw);
fputc('\n', fw);
line = read_line(fr, NULL);
if (!line || *line == '#')
break;
}
}
if (fr)
fclose(fr);
close_file_and_rename(fw, ".info#", ".info");
}