2
This software and ancillary information (herein called "SOFTWARE")
3
called Supermon is made available under the terms described
4
here. The SOFTWARE has been approved for release with associated
5
LA-CC Number LA-CC 99-51.
7
Unless otherwise indicated, this SOFTWARE has been authored by an
8
employee or employees of the University of California, operator of the
9
Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with
10
the U.S. Department of Energy. The U.S. Government has rights to use,
11
reproduce, and distribute this SOFTWARE, and to allow others to do so.
12
The public may copy, distribute, prepare derivative works and publicly
13
display this SOFTWARE without charge, provided that this Notice and
14
any statement of authorship are reproduced on all copies. Neither the
15
Government nor the University makes any warranty, express or implied,
16
or assumes any liability or responsibility for the use of this
19
If SOFTWARE is modified to produce derivative works, such modified
20
SOFTWARE should be clearly marked, so as not to confuse it with the
21
version available from LANL.
23
/** NOTICE: This software is licensed under the GNU Public License, which
24
is included as LICENSE_GPL in this source distribution. **/
25
/** NOTE: This library is part of the supermon project, hence the name
28
* Matt's smaller s-expression parsing library
30
* Written by Matt Sottile (matt@lanl.gov), January 2002.
38
#include "faststack.h"
41
* constants related to atom buffer sizes and growth.
43
static int sexp_val_start_size = 256;
44
static int sexp_val_grow_size = 64;
47
* Function for tuning growth parameters.
49
void set_parser_buffer_params(int ss, int gs) {
51
sexp_val_start_size = ss;
53
fprintf(stderr,"PARSER.C: Cannot set buffer start size to a value<1.\n");
56
sexp_val_grow_size = gs;
58
fprintf(stderr,"PARSER.C: Cannot set buffer grow size to a value<1.\n");
62
* this structure is pushed onto the stack so we can keep track of the
63
* first and last elements in a list.
64
* !!!!DON'T USE THESE OUTSIDE THIS FILE!!!
66
typedef struct parse_stack_data
73
* parse_data_t stack - similar malloc prevention to sexp_t_cache.
75
faststack_t *pd_cache;
78
* The global <I>sexp_t_cache</I> is a faststack implementing a cache of
79
* pre-alloced s-expression element entities. Odds are a user should never
80
* touch this. If you do, you're on your own. This is used internally by
81
* the parser and related code to store unused but allocated sexp_t elements.
82
* This should be left alone and manipulated only by the sexp_t_allocate and
83
* sexp_t_deallocate functions. Touching the stack is bad.
85
faststack_t *sexp_t_cache;
90
#ifdef _NO_MEMORY_MANAGEMENT_
93
sexp_t *sx = (sexp_t *) calloc(1, sizeof(sexp_t));
103
if (sexp_t_cache == NULL) {
104
sexp_t_cache = make_stack();
105
sx = (sexp_t *)malloc(sizeof(sexp_t));
107
sx->next = sx->list = NULL;
109
if (empty_stack(sexp_t_cache)) {
110
sx = (sexp_t *)malloc(sizeof(sexp_t));
112
sx->next = sx->list = NULL;
114
l = pop(sexp_t_cache);
115
sx = (sexp_t *)l->data;
124
* sexp_t de-allocation
126
#ifdef _NO_MEMORY_MANAGEMENT_
128
sexp_t_deallocate(sexp_t *s) {
133
sexp_t_deallocate(sexp_t *s) {
134
if (sexp_t_cache == NULL) sexp_t_cache = make_stack();
136
s->list = s->next = NULL;
137
sexp_t_cache = push(sexp_t_cache, s);
142
* cleanup the sexp library. Note this is implemented HERE since we need
143
* to know about pd_cache, which is local to this file.
145
#ifdef _NO_MEMORY_MANAGEMENT_
146
void sexp_cleanup() {
149
void sexp_cleanup() {
152
if (pd_cache != NULL) {
158
destroy_stack(pd_cache);
162
if (sexp_t_cache != NULL) {
163
l = sexp_t_cache->top;
168
destroy_stack(sexp_t_cache);
182
if (pd_cache == NULL) {
183
pd_cache = make_stack();
184
p = (parse_data_t *)malloc(sizeof(parse_data_t));
187
if (empty_stack(pd_cache)) {
188
p = (parse_data_t *)malloc(sizeof(parse_data_t));
192
p = (parse_data_t *)l->data;
203
pd_deallocate(parse_data_t *p) {
204
if (pd_cache == NULL) pd_cache = make_stack();
206
pd_cache = push(pd_cache, p);
210
* Destroy a continuation by freeing all of its fields that it is responsible
211
* for managing, and then free the continuation itself. This includes internal
212
* buffers, stacks, etc..
215
destroy_continuation (pcont_t * pc)
218
parse_data_t *lvl_data;
220
if (pc == NULL) return; /* return if null passed in */
222
if (pc->stack != NULL) {
223
lvl = pc->stack->top;
226
* note that destroy_stack() does not free the data hanging off of the
227
* stack. we have to walk down the stack and do that here.
230
while (lvl != NULL) {
231
lvl_data = (parse_data_t *)lvl->data;
234
* Seems to have fixed bug with destroying partially parsed
235
* expression continuations with the short three lines below.
237
if (lvl_data != NULL) {
238
lvl_data->lst = NULL;
239
destroy_sexp(lvl_data->fst);
240
lvl_data->fst = NULL;
242
/* free(lvl_data); */
243
pd_deallocate(lvl_data);
244
lvl->data = lvl_data = NULL;
251
// stack has no data on it anymore, so we can free it.
253
destroy_stack(pc->stack);
258
// free up other allocated data
265
* wrapper around cparse_sexp. assumes s contains a single, complete,
266
* null terminated s-expression. partial sexps or strings containing more
267
* than one will act up.
270
parse_sexp (char *s, int len)
275
pc = cparse_sexp (s, len, pc);
278
destroy_continuation(pc);
284
init_continuation(char *str)
287
/* new continuation... */
288
cc = (pcont_t *)malloc(sizeof(pcont_t));
291
/* allocate atom buffer */
292
cc->val = (char *)malloc(sizeof(char)*sexp_val_start_size);
293
assert(cc->val != NULL);
295
cc->val_allocated = sexp_val_start_size;
300
cc->stack = make_stack();
312
* Iterative parser. Wrapper around parse_sexp that is slightly more
313
* intelligent and allows users to iteratively "pop" the expressions
314
* out of a string that contains a bunch of expressions.
315
* Useful if you have a string like "(foo bar)(goo har)(moo mar)" and
316
* want to get "(foo bar)", "(goo har)", and "(moo mar)" individually on
320
iparse_sexp (char *s, int len, pcont_t *cc) {
328
fprintf(stderr,"iparse_sexp called with null continuation!\n");
332
/* call the parser */
333
pc = cparse_sexp(s,len,cc);
335
if (cc->last_sexp != NULL) {
337
cc->last_sexp = NULL;
343
/*************************************************************************/
344
/*************************************************************************/
345
/*************************************************************************/
346
/*************************************************************************/
347
/*************************************************************************/
350
* Continuation based parser - the guts of the package.
353
cparse_sexp (char *str, int len, pcont_t *lc)
356
register unsigned int val_allocated = 0;
357
register unsigned int val_used = 0;
358
register unsigned int state = 1;
359
register unsigned int depth = 0;
360
register unsigned int qdepth = 0;
361
register unsigned int elts = 0;
362
register unsigned int esc = 0;
370
unsigned long fsm_iterations = 0;
371
unsigned long maxdepth = 0;
375
/* make sure non-null string */
377
fprintf(stderr,"cparse_sexp: called with null string.\n");
381
/* first, if we have a non null continuation passed in, restore state. */
384
val_used = cc->val_used;
385
val_allocated = cc->val_allocated;
394
if (cc->lastPos != NULL)
401
/* new continuation... */
402
cc = (pcont_t *)malloc(sizeof(pcont_t));
405
/* allocate atom buffer */
406
cc->val = val = (char *)malloc(sizeof(char)*sexp_val_start_size);
409
cc->val_used = val_used = 0;
410
cc->val_allocated = val_allocated = sexp_val_start_size;
415
cc->stack = stack = make_stack();
417
/* t is temp pointer into s for current position */
423
bufEnd = cc->sbuffer+len;
425
/*==================*/
426
/* main parser loop */
427
/*==================*/
428
while (t[0] != '\0' && t != bufEnd)
431
printf("PARSER: STATE=%d CURCHAR=%c (0x%x)\n",state,t[0],t);
432
printf(" VAL_ALLOCATED=%d VAL_USED=%d\n",val_allocated,val_used);
436
/* based on the current state in the FSM, do something */
442
/* space,tab,CR,LF considered white space */
449
/* semicolon starts a comment that extends until a \n is
455
/* enter state 2 for open paren */
460
/* enter state 3 for close paran */
464
/* begin quoted string - enter state 5 */
467
/* set cur pointer to beginning of val buffer */
471
/* single quote - enter state 7 */
476
/* other characters are assumed to be atom parts */
478
/* set cur pointer to beginning of val buffer */
481
/** NOTE: the following code originally required a transition
482
to state 4 before processing the first atom character --
483
this required two iterations for the first character
484
of each atom. merging this into here allows us to process
485
what we already know to be a valid atom character before
486
entering state 4. **/
488
if (t[0] == '\\') esc = 1;
492
if (val_used == val_allocated) {
493
val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
495
vcur = val + val_used;
496
val_allocated += sexp_val_grow_size;
509
/* sx = (sexp_t *) malloc (sizeof (sexp_t)); */
510
sx = sexp_t_allocate();
517
if (stack->height < 1)
519
/* data = (parse_data_t *) malloc (sizeof (parse_data_t)); */
520
data = pd_allocate();
522
data->fst = data->lst = sx;
527
data = (parse_data_t *) top_data (stack);
528
if (data->lst != NULL)
529
data->lst->next = sx;
535
/* data = (parse_data_t *) malloc (sizeof (parse_data_t)); */
536
data = pd_allocate();
538
data->fst = data->lst = NULL;
546
if (depth > maxdepth) maxdepth = depth;
549
/* check for close parens that were never opened. */
551
fprintf(stderr,"Badly formed s-expression. Parser exiting.\n");
553
cc->val_used = val_used;
554
cc->val_allocated = val_allocated;
562
cc->last_sexp = NULL;
566
fprintf(stderr,"State Machine Iterations: %d\nMaxdepth: %d\n",
567
fsm_iterations,maxdepth);
577
data = (parse_data_t *) lvl->data;
583
if (stack->top != NULL)
585
data = (parse_data_t *) top_data (stack);
586
data->lst->list = sx;
590
fprintf (stderr, "Hmmm. Stack->top is null.\n");
595
/** if depth = 0 then we finished a sexpr, and we return **/
599
cc->val_allocated = val_allocated;
600
cc->val_used = val_used;
608
while (stack->top != NULL)
611
data = (parse_data_t *) lvl->data;
620
fprintf(stderr,"State Machine Iterations: %d\nMaxdepth: %d\n",
621
fsm_iterations,maxdepth);
627
case 4: /** parsing atom **/
628
if (esc == 1 && (t[0] == '\"' || t[0] == '(' ||
629
t[0] == ')' || t[0] == '\'' ||
631
vcur--; /* back up to overwrite the \ */
639
/* look at an ascii table - these ranges are the non-whitespace, non
640
paren and quote characters that are legal in atoms */
641
if (!((t[0] >= '*' && t[0] <= '~') ||
642
((unsigned char)(t[0]) > 127) ||
644
(t[0] >= '#' && t[0] <= '&')))
649
sx = sexp_t_allocate();
654
sx->val_allocated = val_allocated;
655
sx->val_used = val_used;
657
sx->aty = SEXP_BASIC;
659
val = (char *)malloc(sizeof(char)*sexp_val_start_size);
661
val_allocated = sexp_val_start_size;
665
if (!empty_stack (stack))
667
data = (parse_data_t *) top_data (stack);
668
if (data->fst == NULL)
670
data->fst = data->lst = sx;
674
data->lst->next = sx;
680
/* looks like this expression was just a basic atom - so
684
cc->val_used = val_used;
685
cc->val_allocated = val_allocated;
704
/** NOTE: we know whitespace following atom, so spin ahead
705
one and let state 1 do what it needs to for the next
720
if (t[0] == '\\') esc = 1;
724
if (val_used == val_allocated) {
725
val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
727
vcur = val + val_used;
728
val_allocated += sexp_val_grow_size;
735
if (esc == 1 && (t[0] == '\"' ||
743
/** NO NEED TO UPDATE VAL COUNTS **/
753
/* sx = (sexp_t *) malloc (sizeof (sexp_t)); */
754
sx = sexp_t_allocate();
759
sx->val_used = val_used;
760
sx->val_allocated = val_allocated;
762
sx->aty = SEXP_DQUOTE;
764
val = (char *)malloc(sizeof(char)*sexp_val_start_size);
766
val_allocated = sexp_val_start_size;
770
if (!empty_stack (stack))
772
data = (parse_data_t *) top_data (stack);
773
if (data->fst == NULL)
775
data->fst = data->lst = sx;
779
data->lst->next = sx;
785
/* looks like this expression was just a basic double
786
quoted atom - so return it. */
787
t++; /* spin past the quote */
791
cc->val_used = val_used;
792
cc->val_allocated = val_allocated;
811
if (val_used == val_allocated) {
812
val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
814
vcur = val + val_used;
815
val_allocated += sexp_val_grow_size;
835
else if (t[0] == '(')
852
else if (t[0] == ')')
857
else if (t[0] == '\"')
865
if (t[0] == '\\') esc = 1;
869
if (val_used == val_allocated) {
870
val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
872
vcur = val + val_used;
873
val_allocated += sexp_val_grow_size;
877
/* let it fall through to state 9 if we know we're transitioning
886
/* sx = (sexp_t *) malloc (sizeof (sexp_t)); */
887
sx = sexp_t_allocate();
892
sx->val_allocated = val_allocated;
893
sx->val_used = val_used;
895
sx->aty = SEXP_SQUOTE;
897
val = (char *)malloc(sizeof(char)*sexp_val_start_size);
899
val_allocated = sexp_val_start_size;
903
if (!empty_stack (stack))
905
data = (parse_data_t *) top_data (stack);
906
if (data->fst == NULL)
908
data->fst = data->lst = sx;
912
data->lst->next = sx;
918
/* looks like the whole expression was a single
919
quoted value! So return it. */
922
cc->val_used = val_used;
923
cc->val_allocated = val_allocated;
941
if (t[0] == '\"' && esc == 0)
946
if (t[0] == '\\') esc = 1;
950
if (val_used == val_allocated) {
951
val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
953
vcur = val + val_used;
954
val_allocated += sexp_val_grow_size;
966
fprintf (stderr, "Unknown parser state %d.\n", state);
972
fprintf(stderr,"State Machine Iterations: %d\nMax Paren Depth: %d\n",
973
fsm_iterations, maxdepth);
976
if (depth == 0 && elts > 0) {
979
cc->val_used = val_used;
980
cc->val_allocated = val_allocated;
988
while (stack->top != NULL)
991
data = (parse_data_t *) lvl->data;
1002
cc->val_allocated = val_allocated;
1003
cc->val_used = val_used;
1004
if (t[0] == '\0' || t == bufEnd)
1009
cc->qdepth = qdepth;
1012
cc->last_sexp = NULL;