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 )