/* ########################################################################
   
   SMAC FILE USED BY XCORAL EDITOR
   
   File: lex.sc
   Path: /home/pages/smaclib/lex.sc
   Description: 
   Created: Mon Jun 7 1999
   Author: Bruno Pages
   
   RCS $Revision$ $State$
   
   
   ########################################################################
   
   Requires: nothing
   
   Defines: lex_add and match_identifier
   
   Suggested bindings: 
   
   Procedure: 
   
   ########################################################################
   
   Copyright (c) : Bruno Pages
   
   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 2, 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.

   ######################################################################## */

/* this file is used to quickly know if the word beginning
   at the current position is a keyword of the given rule. */

/* compute the rule to search quickly the C[++] keywords */

char ** lex_add(char * ident, char ** table)
{
  char ** result;
  
  if (! table) {
    if (*ident) {
      
      /* return a 'must be' rule */
      
      if ((result = (char **) calloc(2, sizeof(char *))) == 0)
	error("not enough place");
      
      /* result[0] = 0; */
      result[1] = (char *) strdup(ident);
    }
    else {
      
      /* return a 'may be finished' rule */
      
      if ((result = (char **) calloc(3, sizeof(char *))) == 0)
	error("not enough place");
      
      /* result[0] = result[1] = result[2] = 0; */
    }
  }
  else if (! *ident) {
    
    /* add a 'may be finished' rule at the beginning */
    
    if (! table[0]) {
      /* table is a 'must be' rule */
      
      if ((result = (char **) calloc(5, sizeof(char *))) == 0)
	error("not enough place");
      
      /* result[0] = result[1] = result[4] = 0; */
      result[2] = (char *) table[1][0];
      result[3] = (char *) lex_add(table[1] + 1, 0);
      free(table[1]);
      free(table);
    }
    else {
      int n;
      
      for (n = 2; table[n]; n += 2)
	;
      
      if ((result = (char **) calloc(n + 3, sizeof(char *))) == 0)
	error("not enough place");
      
      /* result[0] = result[1] = result[n + 2] = 0 */
      memcpy((char *) result + 2, (char *) table, n * sizeof(char *));
      free(table);
    }
  }
  else if ((! table[0]) && table[1]) {
    /* table is a 'must be' rule */
    
    if (table[1][0] == *ident) {
      if ((result = (char **) calloc(3, sizeof(char *))) == 0)
	error("not enough place");
      
      result[0] = (char *) *ident;
      result[1] = (char *) lex_add(ident + 1, lex_add(table[1] + 1, 0));
      /* result[2] = 0*/
      free(table[1]);
      free(table);
    }
    else {
      if ((result = (char **) calloc(5, sizeof(char *))) == 0)
	error("not enough place");
      
      result[0] = (char *) table[1][0];
      result[1] = (char *) lex_add(table[1] + 1, 0);
      result[2] = (char *) *ident;
      result[3] = (char *) lex_add(ident + 1, 0);
      /* result[4] = 0; */
    }
  }
  else {
    int n;
    
    for (n = (table[0]) ? 0 : 2; table[n]; n += 2) {
      if (((int) table[n]) == *ident) {
	/* have already a rule for the first ident's character, update it */
	table[n + 1] = (char *) lex_add(ident + 1, (char **) table[n + 1]);
	return table;
      }
    }
    
    /* must add the rule */
    if ((result = (char **) calloc(n + 3, sizeof(char *))) == 0)
      error("not enough place");
    
    memcpy((char *) result, (char *) table, n * sizeof(char *));
    result[n] = (char *) *ident;
    result[n + 1] = (char *) lex_add(ident + 1, 0);
  }
  
  return result;
}

/* debug
   
void print_table(int level, char ** table)
{
  int n;
  
  if ((! table[0]) && table[1]) {
    for (n = level; n; n -= 1) printf("    ");
    printf("= %s\n", table[1]);
  }
  else {
    if ((! table[0]) && (! table[1])) {
      for (n = level; n; n -= 1) printf("    ");
      printf("|\n");
      table += 2;
    }
    while (*table) {
      for (n = level; n; n -= 1) printf("    ");
      printf("'%c'\n", table[0]);
      print_table(level + 1, (char **) table[1]);
      table += 2;
    }
  }
}
*/

/* returns 1 if the word beginning at the current position is a
   keyword for the given rule. */

int match_identifier(char ** rule)
{
  if (rule == 0)
    return 0;
  
  for (;;) {
    if (! rule[0]) {
      if (rule[1]) {
	/* end of word must be rule[1] */
	char * p;
	
	for (p = rule[1]; *p; p += 1) {
	  if (*p == current_char())
	    goto_next_char();
	  else
	    return 0;
	}
	return (! strchr(chars_of_word, current_char()));
      }
      else {
	/* word must be finish or may be another case */
	if ((! current_char()) || (! strchr(chars_of_word, current_char())))
	  return 1;
	if (rule[2])
	  /* look at the next case */
	  rule += 2;
	else
	  return 0;
      }
    }
    else if (current_char() == ((int) rule[0])) {
      /* right char, go on a sub rule */
      rule = (char **) rule[1];
      goto_next_char();
    }
    else if (rule[2])
      /* look at the next case */
      rule += 2;
    else
      return 0;
  }
}
