Chemistry-MolecularMass

 view release on metacpan or  search on metacpan

MolecularMass/MolecularMass.xs  view on Meta::CPAN

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

/***********************************************/
/*                                             */
/*    Structures                               */
/*                                             */
/***********************************************/

typedef struct atom_count_struct *Atom_count_ptr;

typedef struct atom_count_struct {
   char *element_symbol;
   int count;
   Atom_count_ptr next;
} Atom_count;

typedef struct symbol_table_struct *Symtab_ptr;

typedef struct symbol_table_struct {
   Atom_count *start;
   Symtab_ptr next;
} Symtab;

typedef struct token_struct {
   /* 0 - left parenthesis
      1 - element name
      2 - int count number
      3 - right parenthesis
   */
   int type;
   char *element_symbol;
   int count;
} Token;

typedef struct stack_struct *Stack_ptr;

typedef struct stack_struct {
   Symtab *first_tab;
   Symtab *last_tab;
   Stack_ptr prev;
} Stack;

/***********************************************/
/*                                             */
/*      Functions declarations                 */
/*                                             */
/***********************************************/

int verify_brackets(char *);
int check_brackets(char *, char *);
int is_bracket(char);
int is_left_bracket(char);
char other_bracket(char);
int only_alnum(char *, char *);
int not_even(char *, char *);
char *matching_bracket(char *, char *);

Atom_count *parse_formula_c(char *formula);
void print_atom_count(Atom_count *i);
Atom_count *flatten(Symtab *n);
Atom_count *combine(Atom_count *n);
Atom_count *add_atom(Atom_count *i, Atom_count *j);
void free_symtab(Symtab *n);
int tokenize(Token *t, int *error, char **f);
char *make_str_copy(char *s);
void multiply(Atom_count *i, int n);
Atom_count *new_element(char *element_symbol);
Symtab *new_symtab(void);

/***********************************************/
/*                                             */
/*      Functions (for parsing)                */
/*                                             */
/***********************************************/

Atom_count *parse_formula_c(char *formula)
{
   Token tok;
   Token *t = &tok;
   int error = 0;
   Stack *temp_stack;
   Atom_count *ac;
   Symtab *st;
   Stack *stack = (Stack *) malloc(sizeof(Stack));
   stack->first_tab = NULL;
   stack->last_tab = NULL;
   stack->prev = NULL;

   t->type = 4; /* Wrong!!! */
   t->element_symbol = NULL;
   t->count = 0;

   while(tokenize(&tok, &error, &formula))
   {
      if(t->type == 0) /* left parenthesis */
      {
         temp_stack = (Stack *) malloc(sizeof(Stack));
	 temp_stack->first_tab = NULL;
	 temp_stack->last_tab = NULL;
	 temp_stack->prev = stack;
	 stack = temp_stack;
      }
      else if(t->type == 1) /* element name */
      {
         ac = new_element(t->element_symbol);
	 st = new_symtab();
	 st->start = ac;
	 if(stack->first_tab == NULL) stack->first_tab = st;
	 if(stack->last_tab != NULL) stack->last_tab->next = st;
	 stack->last_tab = st;
      }
      else if(t->type == 2) /* count */
      {
         multiply(stack->last_tab->start, t->count);
      }
      else if(t->type == 3) /* right parenthesis */
      {
         ac = combine(flatten(stack->first_tab));
	 free_symtab(stack->first_tab);
	 temp_stack = stack;
	 stack = stack->prev;
	 free(temp_stack);
	 st = new_symtab();
	 st->start = ac;
	 if(stack->first_tab == NULL) stack->first_tab = st;
	 if(stack->last_tab != NULL) stack->last_tab->next = st;
	 stack->last_tab = st;
      }
      else /* Error! */
      {
         return(NULL);
      }
   }
   if(error) return(NULL);
   ac = combine(flatten(stack->first_tab));
   free_symtab(stack->first_tab);
   free(stack);
   return(ac);
}

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

int tokenize(Token *t, int *error, char **formula)
{
   char *formula_offset = *formula;
   char *i = formula_offset;
   char *j;
   char *k;

   if(*i == '(')
   {
      t->type = 0;
      ++formula_offset;
      *formula = formula_offset;
      return(1);
   }
   else if(*i == ')')
   {
      t->type = 3;
      ++formula_offset;
      *formula = formula_offset;
      return(1);
   }
   else if(isupper(*i))
   {
      t->type = 1;
      ++i;
      while(islower(*i))
      {
         ++i;
      }
      j = (char *) malloc(sizeof(char) * (i - formula_offset + 1));
      k = j;
      while(formula_offset != i)
      {
         *k = *formula_offset;
	 ++formula_offset;
	 ++k;
      }
      *k = '\0';
      free(t->element_symbol);
      t->element_symbol = j;
      *formula = formula_offset;
      return(1);
   }
   else if(isdigit(*i))
   {
      t->type = 2;
      ++i;
      while(isdigit(*i))
      {
         ++i;
      }
      j = (char *) malloc(sizeof(char) * (i - formula_offset + 1));
      k = j;
      while(formula_offset != i)
      {
         *k = *formula_offset;
	 ++formula_offset;
	 ++k;
      }
      *k = '\0';
      t->count = atoi(j);
      free(j);
      *formula = formula_offset;
      return(1);
   }
   else if(*i == '\0')
   {
      free(t->element_symbol);
      return(0);
   }
   else
   {
      free(t->element_symbol);
      *error = 1;
      return(0);
   }
}

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

Atom_count *flatten(Symtab *n)
{
   Atom_count *i;
   Atom_count *j;

   if(n == NULL) return(NULL);

   i = n->start;
   j = i;

   n = n->next;
   while(n != NULL)
   {
      if(j == NULL)
      {
         j = n->start;
	 n = n->next;
	 continue;
      }

      while(j->next != NULL)
      {
         j = j->next;
      }
      j->next = n->start;
      n = n->next;
   }
   return i;
}

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

Atom_count *combine(Atom_count *n)
{
   Atom_count *i = NULL;
   return add_atom(i, n);
}

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

Atom_count *add_atom(Atom_count *i, Atom_count *n)
{
   Atom_count *j;

MolecularMass/MolecularMass.xs  view on Meta::CPAN

      return (1);
   }
   return (0);
}

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

char *matching_bracket(char *s, char *t)
{
   char left;
   char right;
   int i = 1;

   left = *s;
   right = other_bracket(*s);
   ++s;

   while (s < t)
   {
      if (*s == right) --i;
      if (*s == left) ++i;
      if (i == 0) break;
      ++s;
   }
   if (i == 0) return (s);
   return (NULL);
}

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

char other_bracket(char b)
{
   if (b == '[') return (']');
   if (b == '{') return ('}');
   if (b == '(') return (')');
   if (b == '<') return ('>');
   if (b == ']') return ('[');
   if (b == '}') return ('{');
   if (b == ')') return ('(');
   if (b == '>') return ('<');
   return ('\0');
}

/************************************************************/
/*                                                          */
/*      XSUB stuff                                          */
/*                                                          */
/************************************************************/

MODULE = Chemistry::MolecularMass            PACKAGE = Chemistry::MolecularMass

int
verify_parens(s)
	char *s;
	CODE:
		RETVAL = verify_brackets(s);
	OUTPUT:
		RETVAL

void
parse_formula(s)
	char *s;
	PREINIT:
		Atom_count *i;
	PPCODE:
		i = parse_formula_c(s);

		if(i == NULL)
		{
		   /* do push nothing on the stack --
		      an empty list is implicitly returned */
		}
		else
		{
		   while(i != NULL)
		   {
		      EXTEND(SP, 2);
		      PUSHs(newSVpv(i->element_symbol, 0));
		      PUSHs(newSViv(i->count));
		      i = i->next;
		   }
		}



( run in 4.089 seconds using v1.01-cache-2.11-cpan-8dfa8b56332 )