Logo Search packages:      
Sourcecode: gambas version File versions  Download package

gbc_trans_code.c

/***************************************************************************

  trans_code.c

  P-code generation

  (c) 2000-2004 Benoît 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_CODE_C

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "gb_common.h"
#include "gb_error.h"
#include "gbc_compile.h"
#include "gbc_trans.h"
#include "gb_code.h"
#include "gb_limit.h"

/*#define DEBUG*/

PRIVATE FUNCTION *func;

PRIVATE void add_local(long sym_index, TYPE type, long value)
{
  CLASS_SYMBOL *sym;
  PARAM *loc;

  loc = ARRAY_add(&func->local);
  loc->index = sym_index;
  loc->type = type;
  loc->value = value;

  sym = CLASS_declare(JOB->class, sym_index, FALSE);

  sym->local.type = type;
  sym->local.value = value;
}


PRIVATE void create_local_from_param()
{
  int i;

  for (i = 0; i < func->nparam; i++)
  {
    if (TYPE_get_id(func->param[i].type) != T_NULL)
    {
      add_local(func->param[i].index, func->param[i].type, (i - func->nparam));
    }
  }
}

PRIVATE void remove_local()
{
  int i;
  CLASS_SYMBOL *sym;

  for (i = 0; i < ARRAY_count(func->local); i++)
  {
    sym = CLASS_get_symbol(JOB->class, func->local[i].index);
    TYPE_clear(&sym->local.type);
  }
}


PRIVATE boolean TRANS_local(void)
{
  PATTERN *save = JOB->current;
  long sym_index;
  TRANS_DECL decl;

  if (PATTERN_is(*JOB->current, RS_DIM))
    JOB->current++;
  else if (!TRANS_check_declaration())
    return FALSE;

  sym_index = PATTERN_index(*JOB->current);
  JOB->current++;

  if (!TRANS_type(TT_DO_NOT_CHECK_AS | TT_CAN_SQUARE | TT_CAN_ARRAY | TT_CAN_NEW, &decl))
  {
    JOB->current = save;
    return FALSE;
  }

  if (!PATTERN_is_newline(*JOB->current))
    THROW(E_SYNTAX);

  add_local(sym_index, decl.type, func->nlocal);

  if (TRANS_init_var(&decl))
    CODE_pop_local(func->nlocal);

  func->nlocal++;

  if (JOB->verbose)
    printf("LOCAL %s AS %s\n", TABLE_get_symbol_name(JOB->class->table, sym_index), TYPE_get_desc(decl.type));

  return TRUE;
}


PUBLIC void TRANS_statement(void)
{
  static TRANS_STATEMENT statement[] = {
    { RS_EXIT, TRANS_break },
    { RS_BREAK, TRANS_break },
    { RS_CONTINUE, TRANS_continue },
    { RS_GOTO, TRANS_goto },
    { RS_RETURN, TRANS_return },
    { RS_PRINT, TRANS_print },
    { RS_INPUT, TRANS_input },
    { RS_WRITE, TRANS_write },
    { RS_READ, TRANS_read },
    { RS_OPEN, TRANS_open },
    { RS_CLOSE, TRANS_close },
    { RS_SEEK, TRANS_seek },
    { RS_FLUSH, TRANS_flush },
    { RS_STOP, TRANS_stop },
    { RS_QUIT, TRANS_quit },
    { RS_EXEC, TRANS_exec },
    { RS_SHELL, TRANS_shell },
    { RS_WAIT, TRANS_wait },
    { RS_KILL, TRANS_kill },
    { RS_RENAME, TRANS_rename },
    { RS_INC, TRANS_inc },
    { RS_DEC, TRANS_dec },
    { RS_SWAP, TRANS_swap },
    { RS_MKDIR, TRANS_mkdir },
    { RS_RMDIR, TRANS_rmdir },
    { RS_USE, TRANS_use },
    { RS_COPY, TRANS_copy },
    { RS_RAISE, TRANS_raise },
    { RS_LINK, TRANS_link },
    { RS_LOCK, TRANS_lock },
    { RS_UNLOCK, TRANS_unlock },
    { RS_NONE, NULL }
  };

  PATTERN *look = JOB->current;
  TRANS_STATEMENT *st;

  if (PATTERN_is(look[0], RS_LINE) && PATTERN_is(look[1], RS_INPUT))
  {
    JOB->current += 2;
    TRANS_line_input();
  }
  else
  {
    if (PATTERN_is_reserved(look[0]))
    {
      for (st = statement; st->id; st++)
      {
        if (PATTERN_is(look[0], st->id))
        {
          JOB->current++;
          (*st->func)();
          return;
        }
      }
    }

    if (!TRANS_affectation())
      TRANS_expression(TRUE);
  }
}


PRIVATE void translate_body()
{
  PATTERN *look;
  bool is_proc = (TYPE_get_id(func->type) == T_VOID);
  bool test_newline;
  long line = 0;
  bool just_got_select = FALSE;

  for(;;)
  {
    test_newline = TRUE;

    if (JOB->line != line)
    {
      FUNCTION_add_pos_line();
      line = JOB->line;
    }

    look = JOB->current;

    if (PATTERN_is(look[0], RS_END))
      if (TRANS_is_end_function(is_proc, &look[1])) 
        break;

    if (PATTERN_is_newline(look[0]))
    {
      JOB->current++;
      JOB->line++;
      test_newline = FALSE;
    }
    else if (!TRANS_local())
      break;

    if (test_newline)
      if (!PATTERN_is_newline(*JOB->current))
        THROW("Syntax error. End of line expected");

  }


  TRANS_control_init();

  for(;;)
  {
    test_newline = TRUE;

    if (JOB->line != line)
    {
      FUNCTION_add_pos_line();
      line = JOB->line;
    }

    look = JOB->current;

    if (PATTERN_is(look[0], RS_END))
      if (TRANS_is_end_function(is_proc, &look[1]))
        break;

    if (PATTERN_is_newline(look[0]))
    {
      JOB->current++;
      JOB->line++;
      continue;
    }
    
    if (just_got_select)
    {
      if (!PATTERN_is(look[0], RS_CASE) && !PATTERN_is(look[0], RS_DEFAULT))
        THROW("Syntax error. CASE or DEFAULT expected after SELECT");
      just_got_select = FALSE;
    }


    if (PATTERN_is_identifier(look[0]) && PATTERN_is(look[1], RS_COLON))
    {
      TRANS_label();
    }
    else if (PATTERN_is(look[0], RS_IF))
    {
      JOB->current++;
      TRANS_if();
    }
    else if (PATTERN_is(look[0], RS_ELSE))
    {
      JOB->current++;
      TRANS_else();
    }
    else if ((PATTERN_is(look[0], RS_END)
              && PATTERN_is(look[1], RS_IF))
             || PATTERN_is(look[0], RS_ENDIF))
    {
      if (PATTERN_is(look[0], RS_END))
        JOB->current += 2;
      else
        JOB->current++;

      TRANS_endif();
    }
    else if (PATTERN_is(look[0], RS_DO))
    {
      JOB->current++;
      TRANS_do(RS_DO);
    }
    else if (PATTERN_is(look[0], RS_WHILE))
    {
      TRANS_do(RS_WHILE);
    }
    else if (PATTERN_is(*look, RS_REPEAT))
    {
      JOB->current++;
      TRANS_do(RS_REPEAT);
    }
    else if (PATTERN_is(look[0], RS_LOOP))
    {
      JOB->current++;
      TRANS_loop(RS_LOOP);
    }
    else if (PATTERN_is(look[0], RS_UNTIL))
    {
      TRANS_loop(RS_UNTIL);
    }
    else if (PATTERN_is(look[0], RS_WEND))
    {
      JOB->current++;
      TRANS_loop(RS_WEND);
    }
    else if (PATTERN_is(look[0], RS_FOR))
    {
      if (PATTERN_is(look[1], RS_EACH))
      {
        JOB->current += 2;
        TRANS_for_each();
      }
      else
      {
        JOB->current++;
        TRANS_for();
      }
    }
    else if (PATTERN_is(look[0], RS_NEXT))
    {
      JOB->current++;
      TRANS_next();
    }
    else if (PATTERN_is(look[0], RS_SELECT))
    {
      JOB->current++;
      TRANS_select();
      just_got_select = TRUE;
    }
    else if (PATTERN_is(look[0], RS_CASE))
    {
      JOB->current++;
      if (PATTERN_is(look[1], RS_ELSE))
      {
        JOB->current++;
        TRANS_default();
      }
      else
        TRANS_case();
    }
    else if (PATTERN_is(look[0], RS_DEFAULT))
    {
      JOB->current++;
      TRANS_default();
    }
    else if (PATTERN_is(look[0], RS_END)
             && PATTERN_is(look[1], RS_SELECT))
    {
      JOB->current += 2;
      TRANS_end_select();
    }
    else if (PATTERN_is(look[0], RS_TRY))
    {
      JOB->current++;
      TRANS_try();
    }
    else if (PATTERN_is(look[0], RS_FINALLY))
    {
      JOB->current++;
      TRANS_finally();
    }
    else if (PATTERN_is(look[0], RS_CATCH))
    {
      JOB->current++;
      TRANS_catch();
    }
    else if (PATTERN_is(*look, RS_WITH))
    {
      JOB->current++;
      TRANS_with();
    }
    else if (PATTERN_is(look[0], RS_END)
             && PATTERN_is(look[1], RS_WITH))
    {
      JOB->current += 2;
      TRANS_end_with();
    }
    else
      TRANS_statement();

    /*
    if (next_newline)
    {
      for(;;)
      {
        if (PATTERN_is_NEWLINE(*JOB->current)
            || PATTERN_is_END(*JOB->current))
          break;
        JOB->current++;
      }
    }
    */

    if (test_newline)
      if (!PATTERN_is_newline(*JOB->current))
        THROW("Syntax error. End of line expected");

  }

  TRANS_control_exit();
}

PRIVATE void trans_call(const char *name, int nparam)
{
  CLASS_SYMBOL *sym;

  if (!TABLE_find_symbol(JOB->class->table, name, strlen(name), (SYMBOL **)&sym, NULL))
    return;

  if (TYPE_get_kind(sym->global.type) != TK_FUNCTION)
    return;

  CODE_push_global(sym->global.value, FALSE, TRUE);
  CODE_call(nparam, FALSE);
  CODE_drop();
}


PUBLIC void TRANS_code(void)
{
  int i;
  bool debug;

  debug = JOB->debug;
  
  for (i = 0; i < ARRAY_count(JOB->class->function); i++)
  {
    func = &JOB->class->function[i];

    CODE_begin_function(func);

    if (JOB->verbose)
      printf("Compiling %s()...\n", TABLE_get_symbol_name(JOB->class->table, func->name));

    /* Do not debug implicite or generated functions */
    if (!func->start || func->name == NO_SYMBOL || TABLE_get_symbol_name(JOB->class->table, func->name)[0] == '$')
      JOB->nobreak = TRUE;
    else
      JOB->nobreak = FALSE;

    /* fonction implicite ? */
    if (!func->start)
    {
      if ((i == FUNC_INIT_DYNAMIC) && (JOB->form != NULL))
      {
        /* La désactivation des évènenements devrait se faire DANS le _load */
        CODE_event(FALSE);
        /*CODE_push_me(FALSE);*/
        trans_call("$load", 0);
        CODE_event(TRUE);
      }

      CODE_op(C_RETURN, 0, TRUE);
      if (JOB->verbose)
        CODE_dump(func->code);
      continue;
    }
    
    JOB->line = func->line;
    JOB->current = func->start;
    JOB->func = func;

    create_local_from_param();

    translate_body();

    CODE_return(0);

    CODE_end_function(func);
    FUNCTION_add_pos_line();

    func->stack = func->nlocal + func->nctrl + CODE_stack_usage;

    if (JOB->verbose)
    {
      CODE_dump(func->code);
      printf("%d local(s) %d control(s) ", func->nlocal, func->nctrl);
      printf("%d stack\n", func->stack);
      printf("\n");
    }

    remove_local();
  }

  CLASS_check_properties(JOB->class);

  JOB->func = NULL;
}



PUBLIC boolean TRANS_init_var(TRANS_DECL *decl)
{
  int i;
  TRANS_ARRAY *array;

  if (!decl->is_new)
    return FALSE;

  if (TYPE_is_array(decl->type) && decl->array.ndim > 0)
  {
    array = &decl->array;

    if (TYPE_is_object(decl->type))
      /*CODE_push_class(CLASS_add_class(JOB->class, JOB->class->class[TYPE_get_class(decl->type)]));*/
      CODE_push_class(TYPE_get_value(decl->type));
    else
      CODE_push_number(TYPE_get_id(decl->type));

    for (i = 0; i < array->ndim; i++)
      CODE_push_number(array->dim[i]);

    CODE_new(array->ndim + 1, TRUE, FALSE);
  }
  else
  {
    CODE_push_class(TYPE_get_value(decl->type));
    /*CODE_push_class(CLASS_add_class(JOB->class, TYPE_get_class(decl->type)));*/
    CODE_new(1, FALSE, FALSE);
  }

  return TRUE;
}


/*
PUBLIC void TRANS_init_object()
{
}
*/

PUBLIC void TRANS_init_optional(TRANS_PARAM *param)
{
  PATTERN *look = param->optional;
  PATTERN *save;

  if (look == NULL)
    return;

  save = JOB->current;

  if (PATTERN_is(*look, RS_COMMA) || PATTERN_is(*look, RS_RBRA))
  {
    CODE_push_void();
  }
  else
  {
    if (!PATTERN_is(*look, RS_EQUAL))
      THROW("Syntax error. Invalid optional parameter");

    look++;
    JOB->current = look;
    TRANS_expression(FALSE);

    if (!PATTERN_is(*JOB->current, RS_COMMA) && !PATTERN_is(*JOB->current, RS_RBRA))
      THROW("Syntax error. Invalid optional parameter");
  }

  JOB->current = save;
}

Generated by  Doxygen 1.6.0   Back to index