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

eval_read.c

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

  eval_read.c

  Lexical parser

  (c) 2000-2003 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 __EVAL_READ_C

#include <ctype.h>

#include "gb_common.h"
#include "gb_error.h"
#include "gb_table.h"

#include "eval.h"
#include "eval_read.h"


/*#define DEBUG*/

PRIVATE long source_ptr;
PRIVATE int last_pattern_type = -1;
PRIVATE PATTERN last_pattern = 0;
PRIVATE boolean begin_line = FALSE;

/* We declare the well known class to the compiler */

/*
PRIVATE void READ_exit(void)
{
  static char *wkclass[] = { "gb", "Class", "File", "Error", "App", "Sys", NULL };
  long index;
  char **wkc;

  for (wkc = wkclass; *wkc; wkc++)
  {
    if (TABLE_find_symbol(JOB->class->table, *wkc, strlen(*wkc), NULL, &index))
      CLASS_add_class(JOB->class, index);
  }
}
*/


PUBLIC void READ_dump_pattern(PATTERN *pattern)
{
  int type = PATTERN_TYPE(*pattern);
  long index = PATTERN_INDEX(*pattern);
  long pos;

  pos = (long)(pattern - EVAL->pattern);
  if (pos >= 0 && pos < ARRAY_count(EVAL->pattern))
    printf("%ld ", pos);

  if (PATTERN_flag(*pattern) & RT_FIRST)
    printf("!");
  else
    printf(" ");

  if (PATTERN_flag(*pattern) & RT_POINT)
    printf(".");
  else
    printf(" ");

  printf(" ");

  if (type == RT_RESERVED)
    printf("RESERVED     %s\n", TABLE_get_symbol_name(COMP_res_table, index));
  else if (type == RT_NUMBER)
    printf("NUMBER       %s\n", TABLE_get_symbol_name(EVAL->table, index));
  else if (type == RT_IDENTIFIER)
    printf("IDENTIFIER   %s\n", TABLE_get_symbol_name(EVAL->table, index));
  else if (type == RT_STRING)
    printf("STRING       %s\n", TABLE_get_symbol_name(EVAL->string, index));
  else if (type == RT_TSTRING)
    printf("TSTRING      %s\n", TABLE_get_symbol_name(EVAL->string, index));
  else if (type == RT_NEWLINE)
    printf("NEWLINE      (%ld)\n", index);
  else if (type == RT_END)
    printf("END\n");
  else if (type == RT_PARAM)
    printf("PARAM        %ld\n", index);
  else if (type == RT_SUBR)
    printf("SUBR         %s\n", COMP_subr_info[index].name);
  else
    printf("?            %ld\n", index);
}


PRIVATE uchar get_char_offset(int offset)
{
  offset += source_ptr;

  if (offset >= EVAL->len || offset < 0)
    return 0;
  else
    return (uchar)(EVAL->source[offset]);
}


PRIVATE uchar get_char(void)
{
  return get_char_offset(0);
}

PRIVATE uchar next_char(void)
{
  source_ptr++;
  return get_char();
}


PRIVATE void add_pattern(int type, long index)
{
  PATTERN *pattern;

  /*
  if (index > 100)
    THROW("add_pattern", "Too many words.");
  */

  pattern = ARRAY_add(&EVAL->pattern);

  *pattern = MAKE_PATTERN(type, index);
  last_pattern_type = type;
  last_pattern = *pattern;

  #ifdef DEBUG
  READ_dump_pattern(pattern);
  #endif
}


PRIVATE void add_newline()
{
  add_pattern(RT_NEWLINE, 0);
  source_ptr++;
}


PRIVATE void add_end()
{
  add_pattern(RT_END, 0);
  source_ptr++;
}


PRIVATE bool is_number()
{
  int pos = 0;
  unsigned char car;
  unsigned char car2;

  car = get_char_offset(pos);

  if (car == '-' || car == '+')
  {
    car = get_char_offset(-1);
    if (car && !isspace(car))
      return FALSE;
    pos++;
    car = get_char_offset(pos);
  }

  if (isdigit(car))
    return TRUE;

  car2 = toupper(get_char_offset(pos + 1));

  if (car == '&')
  {  
    if (car2 == 'H')
    {
      pos += 2;
      goto __HEX;
    }
    
    if (car2 == 'X')
    {
      pos += 2;
      goto __BIN;
    }
    
    pos++;
    goto __HEX;
  }
  else if (car == '%')
  {
    pos ++;
    goto __BIN;
  }
  else
    return FALSE;
  
__HEX:
 
  car = get_char_offset(pos);
  return (isdigit(car) || index("abcdefABCDEF", car) != NULL);
  
__BIN:
   
  car = get_char_offset(pos);
  return (car == '0' || car == '1');
}


PRIVATE void add_number()
{
  unsigned char car;
  long start;
  long index;

  start = source_ptr;
  car = get_char();

  if (car == '-' || car == '+')
    car = next_char();

  if (car == '&')
  {
    car = toupper(next_char());

    if (car == 'H')
      goto READ_HEXA;
    else if (car == 'X')
      goto READ_BINARY;
    else
    {
      source_ptr--;
      goto READ_HEXA;
    }
  }
  else if (car == '%')
    goto READ_BINARY;
  else
    goto READ_NUMBER;

READ_BINARY:

  for (;;)
  {
    car = next_char();
    if (car != '0' && car != '1')
      break;
  }

  if (car == '&')
    car = next_char();

  goto END;

READ_HEXA:

  for (;;)
  {
    car = next_char();
    if (!isxdigit(car))
      break;
  }

  if (car == '&')
    car = next_char();

  goto END;

READ_NUMBER:

  while (isdigit(car))
    car = next_char();

  if (car == '.')
  {
    do
    {
      car = next_char();
    }
    while (isdigit(car));
  }

  if (toupper(car) == 'E')
  {
    car = next_char();
    if (car == '+' || car == '-')
      car = next_char();

    while (isdigit(car))
      car = next_char();
  }

  goto END;

END:

  TABLE_add_symbol(EVAL->table, &EVAL->source[start], source_ptr - start, NULL, &index);

  add_pattern(RT_NUMBER, index);
}


PRIVATE void add_identifier()
{
  unsigned char car;
  long start;
  int len;
  long index;
  int type;
  boolean not_first;
  boolean can_be_reserved;
  boolean can_be_subr;
  boolean is_type;
  boolean last_func, last_declare, last_type;

  start = source_ptr;
  len = 1;

  for(;;)
  {
    source_ptr++;
    car = get_char();
    if (car == 0 || ((!isalnum(car)) && (strchr("$_?", (int)car) == NULL)))
      break;
    len++;
  }

  /* On peut mettre ':' dans un identifieur, à condition qu'il ne soit pas en dernier ! */
  /*
  if (comp->source[start + len - 1] == ':')
  {
    source_ptr--;
    len--;
  }
  */

  not_first = PATTERN_IS(last_pattern, RS_PT) || PATTERN_IS(last_pattern, RS_EXCL);
  last_func = PATTERN_IS(last_pattern, RS_PROCEDURE) || PATTERN_IS(last_pattern, RS_SUB) || PATTERN_IS(last_pattern, RS_FUNCTION);
  last_declare = PATTERN_IS(last_pattern, RS_PUBLIC) || PATTERN_IS(last_pattern, RS_PRIVATE) || PATTERN_IS(last_pattern, RS_DIM);
  last_type = PATTERN_is(last_pattern, RS_AS) || PATTERN_is(last_pattern, RS_NEW);
  car = get_char();

  can_be_reserved = !not_first && TABLE_find_symbol(COMP_res_table, &EVAL->source[start], len, NULL, &index);
  if (can_be_reserved)
  {
    if (index == RS_ME || index == RS_NEW || index == RS_LAST)
    {
      /* Toujours réservé, ne rien faire */
    }
    else if (index == RS_CLASS)
    {
      can_be_reserved = begin_line && isspace(car);
    }
    else
    {
      is_type = (PATTERN_is_type(PATTERN_make(RT_RESERVED, index)) || index == RS_NEW);

      if (last_type)
        can_be_reserved = is_type;
      else if (last_func)
        can_be_reserved = FALSE;
      else
        can_be_reserved = !is_type && (car != ':') && (car != '.') && (car != '!') && (car != '(');
    }
  }

  can_be_subr = !not_first && !last_func && !last_declare && !last_type && (car != '.' && car != '!' );

  if (can_be_reserved)
  {
    type = RT_RESERVED;
  }
  else if (can_be_subr && TABLE_find_symbol(COMP_subr_table, &EVAL->source[start], len, NULL, &index))
  {
    type = RT_SUBR;
    /*index = COMP_subr_info[index].opcode;*/
  }
  else
  {
    TABLE_add_symbol(EVAL->table, &EVAL->source[start], len, NULL, &index);
    type = RT_IDENTIFIER;
  }

  add_pattern(type, index);
}


PRIVATE void add_operator()
{
  unsigned char car;
  long start;
  int len;
  long op = NO_SYMBOL;
  long index;

  start = source_ptr;
  len = 1;

  for(;;)
  {
    source_ptr++;

    if (TABLE_find_symbol(COMP_res_table, &EVAL->source[start], len, NULL, &index))
      op = index;
    else if (op != NO_SYMBOL)
    {
      source_ptr--;
      break;
    }

    car = get_char();
    if (!ispunct(car))
      break;
    len++;
  }

  if (op < 0)
    THROW("Unknown operator");

  add_pattern(RT_RESERVED, op);
}


PRIVATE int xdigit_val(unsigned char c)
{
  c = tolower(c);

  if (c >= '0' && c <= '9')
    return (c - '0');
  else if (c >= 'a' && c <= 'f')
    return (c - 'a' + 10);
  else
    return (-1);
}

PRIVATE void add_string()
{
  unsigned char car;
  long start;
  int len;
  long index;
  int newline;
  bool jump;
  char *p;
  int i;

  start = source_ptr;
  len = 0;
  newline = 0;
  jump = FALSE;
  p = &EVAL->source[source_ptr];

  for(;;)
  {
    source_ptr++;
    car = get_char();

    if (jump)
    {
      if (car == '\n')
        newline++;
      else if (car == '"')
        jump = FALSE;
      else if (!isspace(car))
        break;
    }
    else
    {
      p++;
      len++;

      if (car == '\n')
        THROW("Non terminated string");

      if (car == '\\')
      {
        source_ptr++;
        car = get_char();

        if (car == 'n')
          *p = '\n';
        else if (car == 't')
          *p = '\t';
        else if (car == 'r')
          *p = '\r';
        else if (car == '\"' || car == '\'' || car == '\\')
          *p = car;
        else
        {
          if (car == 'x')
          {
            i = xdigit_val(get_char_offset(1));
            if (i >= 0)
            {
              car = i;
              i = xdigit_val(get_char_offset(2));
              if (i >= 0)
              {
                car = (car << 4) | i;
                *p = car;
                source_ptr += 2;
                continue;
              }
            }
          }

          THROW("Bad character constant in string");
        }
      }
      else if (car == '"')
      {
        p--;
        len--;
        jump = TRUE;
      }
      else
        *p = car;
    }
  }

  p[1] = 0;

  TABLE_add_symbol(EVAL->string, &EVAL->source[start + 1], len, NULL, &index);

  add_pattern(RT_STRING, index);

  for (i = 0; i < newline; i++)
    add_newline();
}


PUBLIC void EVAL_read(void)
{
  uchar car;

  source_ptr = 0;
  begin_line = TRUE;

  while (source_ptr < EVAL->len)
  {
    car = get_char();

    if (car == '\n')
    {
      add_newline();
      begin_line = TRUE;
      continue;
    }

    if (car <= ' ')
    {
      source_ptr++;
      continue;
    }

    /*
    if (car == '\'')
    {
      do
      {
        source_ptr++;
        car = get_char();
      }
      while (car != '\n' && car != 0);

      begin_line = FALSE;
      continue;
    }
    */

    if (car == '"')
    {
      add_string();
      begin_line = FALSE;
      continue;
    }

    if (isalpha(car) || car == '_' || car == (unsigned char)'$')
    {
      add_identifier();
      begin_line = FALSE;
      continue;
    }

    if (is_number())
    {
      add_number();
      begin_line = FALSE;
      continue;
    }

    add_operator();
    begin_line = FALSE;
  }

  /* On ajoute des marqueurs de fin pour simplifier le travail du compilateur
     lorsqu'il examine des patterns à l'avance (pas plus de quatre !) */
  /*add_newline();*/
  add_end();
  add_end();
  add_end();
  add_end();

  /*READ_exit();*/
}

Generated by  Doxygen 1.6.0   Back to index