gbc_trans_expr.c

来自「Gambas is a graphical development enviro」· C语言 代码 · 共 606 行

C
606
字号
/***************************************************************************  trans_expr.c  Expression compiler  (c) 2000-2004 Beno� 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_EXPR_C#include <stdlib.h>#include <string.h>#include <stdio.h>#include <ctype.h>#include "gb_common.h"#include "gb_error.h"#include "gbc_compile.h"#include "gbc_trans.h"#include "gb_code.h"/*#define DEBUG*/PRIVATE boolean Can_new = FALSE;PRIVATE short get_nparam(PATTERN *tree, int *index){  PATTERN pattern;  if (*index < (ARRAY_count(tree) - 1))  {    pattern = tree[*index + 1];    if (PATTERN_is_param(pattern))    {      (*index)++;      return (short)PATTERN_index(pattern);    }  }  /*     G�e le cas o on a cod�un subr sans mettre de parenth�es     => nparam = 0  */  return 0;}PRIVATE void push_number(long index){  TRANS_NUMBER number;  TRANS_DECL decl;  if (TRANS_get_number(index, &number))    THROW(E_SYNTAX);  if (number.type == T_INTEGER)  {    CODE_push_number(number.ival);    return;  }  CLEAR(&decl);  decl.type = TYPE_make(T_FLOAT, 0, 0);  decl.index = NO_SYMBOL;  decl.value = index;  CODE_push_const(CLASS_add_constant(JOB->class, &decl));}PRIVATE void push_string(long index, bool trans){  TRANS_DECL decl;  SYMBOL *sym;  long len;  sym = TABLE_get_symbol(JOB->class->string, index);  len = sym->len;  if (len == 0)  {    CODE_push_null();  }  else if (len == 1 && !trans)  {    CODE_push_char(*(sym->name));  }  else  {    CLEAR(&decl);    if (trans)      decl.type = TYPE_make(T_CSTRING, 0, 0);    else      decl.type = TYPE_make(T_STRING, 0, 0);    decl.index = NO_SYMBOL;    decl.value = index;    CODE_push_const(CLASS_add_constant(JOB->class, &decl));  }}/*PRIVATE void push_class(long index){  TRANS_DECL decl;  decl.type = TYPE_make(T_STRING, 0, 0);  decl.index = NO_SYMBOL;  decl.value = index;  CODE_push_class(CLASS_add_constant(JOB->class, &decl));}*/PRIVATE void trans_identifier(long index, boolean first, boolean point, boolean point_next){  CLASS_SYMBOL *sym = CLASS_get_symbol(JOB->class, index);  boolean is_static;  boolean is_func;  int type;  CONSTANT *constant;  const char *name;  /*CONST_INFO *cst;*/  if (!TYPE_is_null(sym->local.type) && !point)  {    CODE_push_local(sym->local.value);  }  else if (!TYPE_is_null(sym->global.type) && !point)  {    type = TYPE_get_kind(sym->global.type);    if (type == TK_CONST)    {      /*      if (TYPE_get_value(sym->global.type) == T_STRING)        push_string(JOB->class->constant[sym->global.value].index);      else        push_number(JOB->class->constant[sym->global.value].index);      */      constant = &JOB->class->constant[sym->global.value];      type = TYPE_get_id(constant->type);      if (type == T_BYTE          || type == T_BOOLEAN          || type == T_SHORT          || type == T_INTEGER)      {        CODE_push_number(constant->value);      }      else        CODE_push_const(sym->global.value);    }    else    {      if (type == TK_EVENT || type == TK_PROPERTY)      {        goto _UNKNOWN;        /*if (TYPE_is_static(JOB->func->type))          THROW("Cannot raise events in static function");        CODE_push_event(sym->global.value);*/      }      else      {        is_static = TYPE_is_static(sym->global.type);        is_func = type == TK_FUNCTION;        if (!is_static && TYPE_is_static(JOB->func->type))          THROW("Dynamic symbols cannot be used in static function");        if (point_next && is_func)        {          if (!CLASS_exist_class(JOB->class, index))            goto _UNKNOWN;          CODE_push_class(CLASS_add_class(JOB->class, index));        }        else          CODE_push_global(sym->global.value, is_static, is_func);      }    }  }  else  {    /*index = CLASS_add_symbol(JOB->class, index);*/    if (point)      CODE_push_unknown(CLASS_add_unknown(JOB->class, index));    /* Class must be declared now ! */    else if (CLASS_exist_class(JOB->class, index)) /* || (!JOB->class_file && first && isupper(*sym->symbol.name)))*/    {      //printf("%.*s %s\n", sym->symbol.len, sym->symbol.name, isupper(*sym->symbol.name) ? "U" : "l");      CODE_push_class(CLASS_add_class(JOB->class, index));    }    else      goto _UNKNOWN;  }  return;_UNKNOWN:  name = TABLE_get_symbol_name(JOB->class->table, index);  THROW("Unknown identifier: &1", name);}PRIVATE void trans_subr(long subr, short nparam, boolean output){  SUBR_INFO *info = &COMP_subr_info[subr];  if (nparam < info->min_param)    THROW("Not enough arguments to &1()", info->name);  else if (nparam > info->max_param)    THROW("Too many arguments to &1()", info->name);  CODE_subr(info->opcode, nparam, info->optype, output, (info->max_param == info->min_param));}PUBLIC void TRANS_operation(short op, short nparam, boolean output, PATTERN previous){  COMP_INFO *info = &COMP_res_info[op];  switch (info->value)  {    case OP_PT:      if (nparam == 0)        TRANS_use_with();      else if (!PATTERN_is_identifier(previous))        THROW(E_SYNTAX);      break;    case OP_EXCL:      if (!PATTERN_is_identifier(previous))        THROW(E_SYNTAX);      break;    case OP_LSQR:      CODE_push_array(nparam);      break;    case OP_RSQR:      TRANS_subr(TS_SUBR_ARRAY, nparam);      break;    case OP_LBRA:      CODE_call(nparam, output);      break;    case OP_MINUS:      if (nparam == 1)        CODE_op(C_NEG, nparam, TRUE);      else        CODE_op(info->code, nparam, TRUE);      break;    default:      CODE_op(info->code, nparam, (info->flag != RSF_OPN));  }}PRIVATE void trans_expr_from_tree(TRANS_TREE *tree){  int i;  short nparam;  long count;  PATTERN pattern, next_pattern, prev_pattern;  count = ARRAY_count(tree) - 1;  pattern = NULL_PATTERN;  for (i = 0; i <= count; i++)  {    prev_pattern = pattern;    pattern = tree[i];    if (i < count)      next_pattern = tree[i + 1];    else      next_pattern = NULL_PATTERN;    if (PATTERN_is_number(pattern))      push_number(PATTERN_index(pattern));    else if (PATTERN_is_string(pattern))      push_string(PATTERN_index(pattern), FALSE);    else if (PATTERN_is_tstring(pattern))      push_string(PATTERN_index(pattern), TRUE);    else if (PATTERN_is_identifier(pattern))    {      trans_identifier(PATTERN_index(pattern), PATTERN_is_first(pattern),        PATTERN_is_point(pattern), PATTERN_is_point(next_pattern));    }    else if (PATTERN_is_subr(pattern))    {      nparam = get_nparam(tree, &i);      trans_subr(PATTERN_index(pattern), nparam, PATTERN_is_output(pattern));    }    else if (PATTERN_is_reserved(pattern))    {      if (PATTERN_is(pattern, RS_TRUE))      {        CODE_push_boolean(TRUE);      }      else if (PATTERN_is(pattern, RS_FALSE))      {        CODE_push_boolean(FALSE);      }      else if (PATTERN_is(pattern, RS_NULL))      {        CODE_push_null();      }      else if (PATTERN_is(pattern, RS_ME))      {        /*if (FUNCTION_is_static(JOB->func))          THROW("ME cannot be used in a static function");*/        CODE_push_me(FALSE);      }      else if (PATTERN_is(pattern, RS_LAST))      {        CODE_push_last();      }      else if (PATTERN_is(pattern, RS_AT))      {        if (!CODE_popify_last())          THROW("Invalid output parameter");      }      else if (PATTERN_is(pattern, RS_COMMA))      {        CODE_drop();      }      else if (PATTERN_is(pattern, RS_RBRA))      {        CODE_push_return();      }      else if (PATTERN_is(pattern, RS_ERROR))      {        TRANS_subr(TS_SUBR_ERROR, 0);      }      else if (PATTERN_is(pattern, RS_OPTIONAL))      {        CODE_push_void();      }      else      {        nparam = get_nparam(tree, &i);        TRANS_operation((short)PATTERN_index(pattern), nparam, PATTERN_is_output(pattern), prev_pattern);      }    }		/*else if (PATTERN_is_newline(pattern))		{			FUNCTION_add_pos_line();		}*/  }}PRIVATE void trans_new(void){  long index;  int i, nparam;  boolean array = FALSE;  boolean event = FALSE;  boolean collection = FALSE;  bool check_param = FALSE;  nparam = 0;  if (PATTERN_is_identifier(*JOB->current))  {    index = PATTERN_index(*JOB->current);    CODE_push_class(CLASS_add_class(JOB->class, index));    nparam = 1;  }  else if (PATTERN_is_type(*JOB->current))  {    if (PATTERN_is(JOB->current[1], RS_LSQR))    {      CODE_push_number(RES_get_type(PATTERN_index(*JOB->current)));      nparam = 1;    }    else      THROW("Cannot instanciate native types");  }  else if (PATTERN_is(*JOB->current, RS_LBRA))  {    /* NEW Object("Class", ...) */    nparam = 0;    JOB->current--;    check_param = TRUE;  }  JOB->current++;  if (PATTERN_is(*JOB->current, RS_LSQR))  {    if (collection)      THROW("Array declaration is forbidden with typed collection");    JOB->current++;    for (i = 0;; i++)    {      if (i > MAX_ARRAY_DIM)        THROW("Too many dimensions");      TRANS_expression(FALSE);      nparam++;      if (PATTERN_is(*JOB->current, RS_RSQR))        break;      if (!PATTERN_is(*JOB->current, RS_COMMA))        THROW("Comma missing");      JOB->current++;    }    JOB->current++;    array = TRUE;  }  else  {    if (PATTERN_is(*JOB->current, RS_LBRA))    {      JOB->current++;      for(;;)      {        if (nparam > MAX_PARAM_FUNC)          THROW("Too many arguments");        if (PATTERN_is(*JOB->current, RS_AT))          THROW("NEW cannot have output parameters");        TRANS_expression(FALSE);        nparam++;        if (PATTERN_is(*JOB->current, RS_RBRA))          break;        if (!PATTERN_is(*JOB->current, RS_COMMA))          THROW("Comma missing");        JOB->current++;      }      JOB->current++;      if (check_param && nparam == 0)        THROW("Not enough argument to New()");    }    if (PATTERN_is(*JOB->current, RS_AS))    {      JOB->current++;      TRANS_expression(FALSE);      nparam++;      event = TRUE;    }    /*    CODE_call(nparam, FALSE);    CODE_drop();    */  }  if (collection)    CODE_new(nparam, TRUE, event);  else    CODE_new(nparam, array, event);}PUBLIC void TRANS_expression(boolean check_statement){  TRANS_TREE *tree;  if (PATTERN_is(*JOB->current, RS_NEW))  {    if (!Can_new)      THROW("Unexpected NEW");    Can_new = FALSE;    JOB->current++;    trans_new();  }  else  {    tree = TRANS_tree();    if (check_statement && (!TRANS_is_statement(tree)))      THROW("This expression cannot be a statement");    trans_expr_from_tree(tree);    ARRAY_delete(&tree);  }  if (check_statement)  {    /*    if (!CODE_check_statement_last())      THROW("This expression cannot be a statement");    */    CODE_drop();  }}PUBLIC void TRANS_reference(void){  TRANS_expression(FALSE);  if (!CODE_popify_last())    THROW("Invalid assignment");}PUBLIC boolean TRANS_affectation(){  PATTERN *look = JOB->current;  PATTERN *left, *expr, *after;  int niv = 0;  boolean equal = FALSE;  for(;;)  {    if (PATTERN_is_newline(*look) || PATTERN_is_end(*look))      break;    if (PATTERN_is(*look, RS_LBRA) || PATTERN_is(*look, RS_LSQR))    {      niv++;    }    else if (PATTERN_is(*look, RS_RBRA) || PATTERN_is(*look, RS_RSQR))    {      if (niv > 0)        niv--;    }    else if (PATTERN_is(*look, RS_EQUAL))    {      if (niv == 0)      {        equal = TRUE;        break;      }    }    look++;  }  if (!equal)    return FALSE;  left = JOB->current;  *look++ = PATTERN_make(RT_NEWLINE, 0);  expr = look;  Can_new = TRUE;  JOB->current = expr;  TRANS_expression(FALSE);  after = JOB->current;  JOB->current = left;  TRANS_reference();  JOB->current = after;  return TRUE;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?