~ubuntu-branches/ubuntu/hardy/orbital-eunuchs-sniper/hardy

« back to all changes in this revision

Viewing changes to src/sexpr/parser.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2007-05-29 09:32:48 UTC
  • mfrom: (1.1.1 upstream) (2.1.2 gutsy)
  • Revision ID: james.westby@ubuntu.com-20070529093248-laj1bsm2dffohdf9
Tags: 1.30+svn20070601-1
Fix broken "upstream" rule to generate correctly versioned orig.tar.gz
to avoid native package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
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.
 
6
 
 
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
 
17
SOFTWARE.
 
18
 
 
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.
 
22
**/
 
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
 
26
          supermon above. **/
 
27
/**
 
28
 * Matt's smaller s-expression parsing library
 
29
 *
 
30
 * Written by Matt Sottile (matt@lanl.gov), January 2002.
 
31
 ***/
 
32
 
 
33
#include <stdio.h>
 
34
#include <stdlib.h>
 
35
#include <string.h>
 
36
#include <assert.h>
 
37
#include "sexp.h"
 
38
#include "faststack.h"
 
39
 
 
40
/*
 
41
 * constants related to atom buffer sizes and growth.
 
42
 */
 
43
static int sexp_val_start_size = 256;
 
44
static int sexp_val_grow_size  = 64;
 
45
 
 
46
/*
 
47
 * Function for tuning growth parameters.
 
48
 */
 
49
void set_parser_buffer_params(int ss, int gs) {
 
50
  if (ss > 0)
 
51
    sexp_val_start_size = ss;
 
52
  else 
 
53
    fprintf(stderr,"PARSER.C: Cannot set buffer start size to a value<1.\n");
 
54
 
 
55
  if (gs > 0)
 
56
    sexp_val_grow_size = gs;
 
57
  else
 
58
    fprintf(stderr,"PARSER.C: Cannot set buffer grow size to a value<1.\n");
 
59
}
 
60
 
 
61
/**
 
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!!!
 
65
 */
 
66
typedef struct parse_stack_data
 
67
{
 
68
  sexp_t *fst, *lst;
 
69
}
 
70
parse_data_t;
 
71
 
 
72
/**
 
73
 * parse_data_t stack - similar malloc prevention to sexp_t_cache.
 
74
 */
 
75
faststack_t *pd_cache;
 
76
 
 
77
/** 
 
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.  
 
84
 */ 
 
85
faststack_t *sexp_t_cache;
 
86
 
 
87
/**
 
88
 * sexp_t allocation
 
89
 */
 
90
#ifdef _NO_MEMORY_MANAGEMENT_
 
91
sexp_t *
 
92
sexp_t_allocate() {
 
93
  sexp_t *sx = (sexp_t *) calloc(1, sizeof(sexp_t));
 
94
  assert(sx != NULL);
 
95
  return(sx);
 
96
}
 
97
#else
 
98
sexp_t *
 
99
sexp_t_allocate() {
 
100
  sexp_t *sx;
 
101
  stack_lvl_t *l;
 
102
 
 
103
  if (sexp_t_cache == NULL) {
 
104
    sexp_t_cache = make_stack();
 
105
    sx = (sexp_t *)malloc(sizeof(sexp_t));
 
106
    assert(sx != NULL);
 
107
    sx->next = sx->list = NULL;
 
108
  } else {
 
109
    if (empty_stack(sexp_t_cache)) {
 
110
      sx = (sexp_t *)malloc(sizeof(sexp_t));
 
111
      assert(sx != NULL);
 
112
      sx->next = sx->list = NULL;
 
113
    } else {
 
114
      l = pop(sexp_t_cache);
 
115
      sx = (sexp_t *)l->data;
 
116
    }
 
117
  }
 
118
 
 
119
  return sx;
 
120
}
 
121
#endif
 
122
 
 
123
/**
 
124
 * sexp_t de-allocation
 
125
 */
 
126
#ifdef _NO_MEMORY_MANAGEMENT_
 
127
void
 
128
sexp_t_deallocate(sexp_t *s) {
 
129
  /*  free(s);*/
 
130
}
 
131
#else
 
132
void
 
133
sexp_t_deallocate(sexp_t *s) {
 
134
  if (sexp_t_cache == NULL) sexp_t_cache = make_stack();
 
135
 
 
136
  s->list = s->next = NULL;
 
137
  sexp_t_cache = push(sexp_t_cache, s);
 
138
}
 
139
#endif
 
140
 
 
141
/**
 
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.
 
144
 */
 
145
#ifdef _NO_MEMORY_MANAGEMENT_
 
146
void sexp_cleanup() {
 
147
}
 
148
#else
 
149
void sexp_cleanup() {
 
150
  stack_lvl_t *l;
 
151
 
 
152
  if (pd_cache != NULL) {
 
153
    l = pd_cache->top;
 
154
    while (l != NULL) {
 
155
      free(l->data);
 
156
      l = l->below;
 
157
    }
 
158
    destroy_stack(pd_cache);
 
159
    pd_cache = NULL;
 
160
  }
 
161
 
 
162
  if (sexp_t_cache != NULL) {
 
163
    l = sexp_t_cache->top;
 
164
    while (l != NULL) {
 
165
      free(l->data);
 
166
      l = l->below;
 
167
    }
 
168
    destroy_stack(sexp_t_cache);
 
169
    sexp_t_cache = NULL;
 
170
  }
 
171
}
 
172
#endif
 
173
 
 
174
/**
 
175
 * allocation
 
176
 */
 
177
parse_data_t *
 
178
pd_allocate() {
 
179
  parse_data_t *p;
 
180
  stack_lvl_t *l;
 
181
 
 
182
  if (pd_cache == NULL) {
 
183
    pd_cache = make_stack();
 
184
    p = (parse_data_t *)malloc(sizeof(parse_data_t));
 
185
    assert(p!=NULL);
 
186
  } else {
 
187
    if (empty_stack(pd_cache)) {
 
188
      p = (parse_data_t *)malloc(sizeof(parse_data_t));
 
189
      assert(p!=NULL);
 
190
    } else {
 
191
      l = pop(pd_cache);
 
192
      p = (parse_data_t *)l->data;
 
193
    }
 
194
  }
 
195
 
 
196
  return p;
 
197
}
 
198
 
 
199
/**
 
200
 * de-allocation
 
201
 */
 
202
void
 
203
pd_deallocate(parse_data_t *p) {
 
204
  if (pd_cache == NULL) pd_cache = make_stack();
 
205
 
 
206
  pd_cache = push(pd_cache, p);
 
207
}
 
208
 
 
209
/**
 
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..
 
213
 */
 
214
void
 
215
destroy_continuation (pcont_t * pc)
 
216
{
 
217
  stack_lvl_t *lvl;
 
218
  parse_data_t *lvl_data;
 
219
 
 
220
  if (pc == NULL) return; /* return if null passed in */
 
221
 
 
222
  if (pc->stack != NULL) {
 
223
    lvl = pc->stack->top;
 
224
    
 
225
    /*
 
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. 
 
228
     */
 
229
    
 
230
    while (lvl != NULL) {
 
231
      lvl_data = (parse_data_t *)lvl->data;
 
232
 
 
233
      /**
 
234
       * Seems to have fixed bug with destroying partially parsed
 
235
       * expression continuations with the short three lines below.
 
236
       */
 
237
      if (lvl_data != NULL) {
 
238
        lvl_data->lst = NULL;
 
239
        destroy_sexp(lvl_data->fst);
 
240
        lvl_data->fst = NULL;
 
241
 
 
242
        /* free(lvl_data); */
 
243
        pd_deallocate(lvl_data);
 
244
        lvl->data = lvl_data = NULL;
 
245
      }
 
246
 
 
247
      lvl = lvl->below;
 
248
    }
 
249
    
 
250
    //
 
251
    // stack has no data on it anymore, so we can free it.
 
252
    //
 
253
    destroy_stack(pc->stack);
 
254
    pc->stack = NULL;
 
255
  }
 
256
 
 
257
  //
 
258
  // free up other allocated data
 
259
  //
 
260
  free (pc->val);
 
261
  free (pc);
 
262
}
 
263
 
 
264
/* 
 
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.
 
268
 */
 
269
sexp_t *
 
270
parse_sexp (char *s, int len)
 
271
{
 
272
  pcont_t *pc = NULL;
 
273
  sexp_t *sx = NULL;
 
274
 
 
275
  pc = cparse_sexp (s, len, pc);
 
276
  sx = pc->last_sexp;
 
277
 
 
278
  destroy_continuation(pc);
 
279
 
 
280
  return sx;
 
281
}
 
282
 
 
283
pcont_t *
 
284
init_continuation(char *str) 
 
285
{
 
286
  pcont_t *cc;
 
287
  /* new continuation... */
 
288
  cc = (pcont_t *)malloc(sizeof(pcont_t));
 
289
  assert(cc != NULL);
 
290
  
 
291
  /* allocate atom buffer */
 
292
  cc->val = (char *)malloc(sizeof(char)*sexp_val_start_size);
 
293
  assert(cc->val != NULL);
 
294
  
 
295
  cc->val_allocated = sexp_val_start_size;
 
296
  cc->val_used = 0;
 
297
 
 
298
  /* allocate stack */
 
299
  cc->esc = 0;
 
300
  cc->stack = make_stack();
 
301
  cc->sbuffer = str;
 
302
  cc->lastPos = NULL;
 
303
  cc->state = 1;
 
304
  cc->vcur = cc->val;
 
305
  cc->depth = 0;
 
306
  cc->qdepth = 0;
 
307
  
 
308
  return cc;
 
309
}
 
310
 
 
311
/**
 
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
 
317
 * repeated calls.
 
318
 */
 
319
sexp_t *
 
320
iparse_sexp (char *s, int len, pcont_t *cc) {
 
321
  pcont_t *pc;
 
322
  sexp_t *sx = NULL;
 
323
  
 
324
  /* 
 
325
   * sanity check.
 
326
   */
 
327
  if (cc == NULL) {
 
328
    fprintf(stderr,"iparse_sexp called with null continuation!\n");
 
329
    return NULL;
 
330
  }
 
331
  
 
332
  /* call the parser */
 
333
  pc = cparse_sexp(s,len,cc);
 
334
  
 
335
  if (cc->last_sexp != NULL) {
 
336
    sx = cc->last_sexp;
 
337
    cc->last_sexp = NULL;
 
338
  }
 
339
  
 
340
  return sx;
 
341
}
 
342
 
 
343
/*************************************************************************/
 
344
/*************************************************************************/
 
345
/*************************************************************************/
 
346
/*************************************************************************/
 
347
/*************************************************************************/
 
348
 
 
349
/**
 
350
 * Continuation based parser - the guts of the package.
 
351
 */
 
352
pcont_t *
 
353
cparse_sexp (char *str, int len, pcont_t *lc)
 
354
{
 
355
  char *t, *s;
 
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;
 
363
  pcont_t *cc;
 
364
  char *val, *vcur;
 
365
  sexp_t *sx = NULL;
 
366
  faststack_t *stack;
 
367
  parse_data_t *data;
 
368
  stack_lvl_t *lvl;
 
369
#ifdef _DEBUG_
 
370
  unsigned long fsm_iterations = 0;
 
371
  unsigned long maxdepth = 0;
 
372
#endif /* _DEBUG_ */
 
373
  char *bufEnd;
 
374
 
 
375
  /* make sure non-null string */
 
376
  if (str == NULL) {
 
377
    fprintf(stderr,"cparse_sexp: called with null string.\n");
 
378
    return lc;
 
379
  }
 
380
  
 
381
  /* first, if we have a non null continuation passed in, restore state. */
 
382
  if (lc != NULL) {
 
383
    cc = lc;
 
384
    val_used = cc->val_used;
 
385
    val_allocated = cc->val_allocated;
 
386
    val = cc->val;
 
387
    vcur = cc->vcur;
 
388
    state = cc->state;
 
389
    depth = cc->depth;
 
390
    qdepth = cc->qdepth;
 
391
    stack = cc->stack;
 
392
    esc = cc->esc;
 
393
    s = str;
 
394
    if (cc->lastPos != NULL)
 
395
      t = cc->lastPos;
 
396
    else {
 
397
      t = s;
 
398
      cc->sbuffer = str;
 
399
    }
 
400
  } else {
 
401
    /* new continuation... */
 
402
    cc = (pcont_t *)malloc(sizeof(pcont_t));
 
403
    assert(cc != NULL);
 
404
    
 
405
    /* allocate atom buffer */
 
406
    cc->val = val = (char *)malloc(sizeof(char)*sexp_val_start_size);
 
407
    assert(val != NULL);
 
408
    
 
409
    cc->val_used = val_used = 0;
 
410
    cc->val_allocated = val_allocated = sexp_val_start_size;
 
411
 
 
412
    vcur = val;
 
413
    
 
414
    /* allocate stack */
 
415
    cc->stack = stack = make_stack();
 
416
    
 
417
    /* t is temp pointer into s for current position */
 
418
    s = str;
 
419
    t = s;
 
420
    cc->sbuffer = str;
 
421
  }
 
422
  
 
423
  bufEnd = cc->sbuffer+len;
 
424
 
 
425
  /*==================*/
 
426
  /* main parser loop */
 
427
  /*==================*/
 
428
  while (t[0] != '\0' && t != bufEnd)
 
429
    {
 
430
#ifdef _DEBUG_
 
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);
 
433
      fsm_iterations++;
 
434
#endif
 
435
 
 
436
      /* based on the current state in the FSM, do something */
 
437
      switch (state)
 
438
        {
 
439
        case 1:
 
440
          switch (t[0])
 
441
            {
 
442
              /* space,tab,CR,LF considered white space */
 
443
            case '\n':
 
444
            case ' ':
 
445
            case '\t':
 
446
            case '\r':             
 
447
              t++;
 
448
              break;
 
449
              /* semicolon starts a comment that extends until a \n is
 
450
                 encountered. */
 
451
            case ';':
 
452
              t++;
 
453
              state = 11;
 
454
              break;
 
455
              /* enter state 2 for open paren */
 
456
            case '(':
 
457
              state = 2;
 
458
              t++;
 
459
              break;
 
460
              /* enter state 3 for close paran */
 
461
            case ')':
 
462
              state = 3;
 
463
              break;
 
464
              /* begin quoted string - enter state 5 */
 
465
            case '\"':
 
466
              state = 5;
 
467
              /* set cur pointer to beginning of val buffer */
 
468
              vcur = val;
 
469
              t++;
 
470
              break;
 
471
              /* single quote - enter state 7 */
 
472
            case '\'':
 
473
              state = 7;
 
474
              t++;
 
475
              break;
 
476
              /* other characters are assumed to be atom parts */
 
477
            default:
 
478
              /* set cur pointer to beginning of val buffer */
 
479
              vcur = val;
 
480
 
 
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. **/
 
487
              vcur[0] = t[0];
 
488
              if (t[0] == '\\') esc = 1;
 
489
              else esc = 0;
 
490
              val_used++;
 
491
 
 
492
              if (val_used == val_allocated) {
 
493
                val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
 
494
                assert(val != NULL);
 
495
                vcur = val + val_used;
 
496
                val_allocated += sexp_val_grow_size;
 
497
              } else vcur++;
 
498
 
 
499
              t++;
 
500
 
 
501
              /* enter state 4 */
 
502
              state = 4;
 
503
              break;
 
504
            }
 
505
          break;
 
506
        case 2:
 
507
          /* open paren */
 
508
          depth++;
 
509
          /* sx = (sexp_t *) malloc (sizeof (sexp_t)); */
 
510
          sx = sexp_t_allocate();
 
511
          assert(sx!=NULL);
 
512
          elts++;
 
513
          sx->ty = SEXP_LIST;
 
514
          sx->next = NULL;
 
515
          sx->list = NULL;
 
516
          
 
517
          if (stack->height < 1)
 
518
            {
 
519
              /* data = (parse_data_t *) malloc (sizeof (parse_data_t)); */
 
520
              data = pd_allocate();
 
521
              assert(data!=NULL);
 
522
              data->fst = data->lst = sx;
 
523
              push (stack, data);
 
524
            }
 
525
          else
 
526
            {
 
527
              data = (parse_data_t *) top_data (stack);
 
528
              if (data->lst != NULL)
 
529
                data->lst->next = sx;
 
530
              else
 
531
                data->fst = sx;
 
532
              data->lst = sx;
 
533
            }
 
534
          
 
535
          /* data = (parse_data_t *) malloc (sizeof (parse_data_t)); */
 
536
          data = pd_allocate();
 
537
          assert(data!=NULL);
 
538
          data->fst = data->lst = NULL;
 
539
          push (stack, data);
 
540
          
 
541
          state = 1;
 
542
          break;
 
543
        case 3:
 
544
          /** close paren **/
 
545
#ifdef _DEBUG_    
 
546
          if (depth > maxdepth) maxdepth = depth;
 
547
#endif /* _DEBUG_ */
 
548
 
 
549
          /* check for close parens that were never opened. */
 
550
          if (depth == 0) {
 
551
            fprintf(stderr,"Badly formed s-expression.  Parser exiting.\n");
 
552
            cc->val = val;
 
553
            cc->val_used = val_used;
 
554
            cc->val_allocated = val_allocated;
 
555
            cc->vcur = vcur;
 
556
            cc->lastPos = t;
 
557
            cc->depth = depth;
 
558
            cc->qdepth = qdepth;
 
559
            cc->state = 1;
 
560
            cc->stack = stack;
 
561
            cc->esc = 0;
 
562
            cc->last_sexp = NULL;
 
563
            cc->error = 1;
 
564
 
 
565
#ifdef _DEBUG_
 
566
            fprintf(stderr,"State Machine Iterations: %d\nMaxdepth: %d\n",
 
567
                    fsm_iterations,maxdepth);
 
568
#endif /* debug */
 
569
 
 
570
            return cc;
 
571
          }
 
572
 
 
573
          t++;
 
574
          depth--;
 
575
 
 
576
          lvl = pop (stack);
 
577
          data = (parse_data_t *) lvl->data;
 
578
          sx = data->fst;
 
579
          /* free (data); */
 
580
          pd_deallocate(data);
 
581
          lvl->data = NULL;
 
582
 
 
583
          if (stack->top != NULL)
 
584
            {
 
585
              data = (parse_data_t *) top_data (stack);
 
586
              data->lst->list = sx;
 
587
            }
 
588
          else
 
589
            {
 
590
              fprintf (stderr, "Hmmm. Stack->top is null.\n");
 
591
            }
 
592
 
 
593
          state = 1;
 
594
 
 
595
          /** if depth = 0 then we finished a sexpr, and we return **/
 
596
          if (depth == 0) {
 
597
            cc->error = 0;
 
598
            cc->val = val;
 
599
            cc->val_allocated = val_allocated;
 
600
            cc->val_used = val_used;
 
601
            cc->vcur = vcur;
 
602
            cc->lastPos = t;
 
603
            cc->depth = depth;
 
604
            cc->qdepth = qdepth;
 
605
            cc->state = 1;
 
606
            cc->stack = stack;
 
607
            cc->esc = 0;
 
608
            while (stack->top != NULL)
 
609
              {
 
610
                lvl = pop (stack);
 
611
                data = (parse_data_t *) lvl->data;
 
612
                sx = data->fst;
 
613
                /* free (data); */
 
614
                pd_deallocate(data);
 
615
                lvl->data = NULL;
 
616
              }
 
617
            cc->last_sexp = sx;
 
618
 
 
619
#ifdef _DEBUG_
 
620
            fprintf(stderr,"State Machine Iterations: %d\nMaxdepth: %d\n",
 
621
                    fsm_iterations,maxdepth);
 
622
#endif /* debug */
 
623
 
 
624
            return cc;
 
625
          }
 
626
          break;
 
627
        case 4: /** parsing atom **/
 
628
          if (esc == 1 && (t[0] == '\"' || t[0] == '(' ||
 
629
                           t[0] == ')' || t[0] == '\'' ||
 
630
                           t[0] == '\\')) {
 
631
            vcur--; /* back up to overwrite the \ */
 
632
            vcur[0] = t[0];
 
633
            vcur++;
 
634
            t++;
 
635
            esc = 0;
 
636
            break;
 
637
          }
 
638
 
 
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) || 
 
643
                (t[0] == '!') ||
 
644
                (t[0] >= '#' && t[0] <= '&')))
 
645
            {
 
646
              vcur[0] = '\0';
 
647
              val_used++;
 
648
 
 
649
              sx = sexp_t_allocate();
 
650
              assert(sx!=NULL);
 
651
              elts++;
 
652
              sx->ty = SEXP_VALUE;
 
653
              sx->val = val;
 
654
              sx->val_allocated = val_allocated;
 
655
              sx->val_used = val_used;
 
656
              sx->next = NULL;
 
657
              sx->aty = SEXP_BASIC;
 
658
 
 
659
              val = (char *)malloc(sizeof(char)*sexp_val_start_size);
 
660
              assert(val != NULL);
 
661
              val_allocated = sexp_val_start_size;
 
662
              val_used = 0;
 
663
              vcur = val;
 
664
              
 
665
              if (!empty_stack (stack))
 
666
                {
 
667
                  data = (parse_data_t *) top_data (stack);
 
668
                  if (data->fst == NULL)
 
669
                    {
 
670
                      data->fst = data->lst = sx;
 
671
                    }
 
672
                  else
 
673
                    {
 
674
                      data->lst->next = sx;
 
675
                      data->lst = sx;
 
676
                    }
 
677
                }
 
678
              else
 
679
                {
 
680
                  /* looks like this expression was just a basic atom - so
 
681
                     return it. */
 
682
                  cc->error = 0;
 
683
                  cc->val = val;
 
684
                  cc->val_used = val_used;
 
685
                  cc->val_allocated = val_allocated;
 
686
                  cc->vcur = vcur;
 
687
                  cc->lastPos = t;
 
688
                  cc->depth = depth;
 
689
                  cc->qdepth = qdepth;
 
690
                  cc->state = 1;
 
691
                  cc->stack = stack;
 
692
                  cc->esc = 0;
 
693
                  cc->last_sexp = sx;
 
694
                  assert(sx != NULL);
 
695
 
 
696
                  return cc;
 
697
                }
 
698
 
 
699
              switch (t[0]) {
 
700
              case ' ':
 
701
              case '\t':
 
702
              case '\n':
 
703
              case '\r':
 
704
                /** NOTE: we know whitespace following atom, so spin ahead
 
705
                    one and let state 1 do what it needs to for the next
 
706
                    character. **/
 
707
                state = 1;
 
708
                t++;
 
709
                break;
 
710
              case ')':
 
711
                state = 3;
 
712
                break;
 
713
              default:
 
714
                state = 1;
 
715
              }
 
716
            }
 
717
          else
 
718
            {
 
719
              vcur[0] = t[0];
 
720
              if (t[0] == '\\') esc = 1;
 
721
              else esc = 0;
 
722
              val_used++;
 
723
 
 
724
              if (val_used == val_allocated) {
 
725
                val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
 
726
                assert(val != NULL);
 
727
                vcur = val + val_used;
 
728
                val_allocated += sexp_val_grow_size;
 
729
              } else vcur++;
 
730
 
 
731
              t++;
 
732
            }
 
733
          break;
 
734
        case 5:
 
735
          if (esc == 1 && (t[0] == '\"' ||
 
736
                           t[0] == '\'' ||
 
737
                           t[0] == '(' ||
 
738
                           t[0] == ')' ||
 
739
                           t[0] == '\\')) {
 
740
            vcur--;
 
741
            vcur[0] = t[0];
 
742
            vcur++;
 
743
            /** NO NEED TO UPDATE VAL COUNTS **/
 
744
            t++;
 
745
            esc = 0;
 
746
          }
 
747
 
 
748
          if (t[0] == '\"')
 
749
            {
 
750
              state = 6;
 
751
              vcur[0] = '\0';
 
752
              val_used++;
 
753
              /* sx = (sexp_t *) malloc (sizeof (sexp_t)); */
 
754
              sx = sexp_t_allocate();
 
755
              assert(sx!=NULL);
 
756
              elts++;
 
757
              sx->ty = SEXP_VALUE;
 
758
              sx->val = val;
 
759
              sx->val_used = val_used;
 
760
              sx->val_allocated = val_allocated;
 
761
              sx->next = NULL;
 
762
              sx->aty = SEXP_DQUOTE;
 
763
 
 
764
              val = (char *)malloc(sizeof(char)*sexp_val_start_size);
 
765
              assert(val != NULL);
 
766
              val_allocated = sexp_val_start_size;
 
767
              val_used = 0;
 
768
              vcur = val;
 
769
              
 
770
              if (!empty_stack (stack))
 
771
                {
 
772
                  data = (parse_data_t *) top_data (stack);
 
773
                  if (data->fst == NULL)
 
774
                    {
 
775
                      data->fst = data->lst = sx;
 
776
                    }
 
777
                  else
 
778
                    {
 
779
                      data->lst->next = sx;
 
780
                      data->lst = sx;
 
781
                    }
 
782
                }
 
783
              else
 
784
                {
 
785
                  /* looks like this expression was just a basic double
 
786
                     quoted atom - so return it. */
 
787
                  t++; /* spin past the quote */
 
788
 
 
789
                  cc->error = 0;
 
790
                  cc->val = val;
 
791
                  cc->val_used = val_used;
 
792
                  cc->val_allocated = val_allocated;
 
793
                  cc->vcur = vcur;
 
794
                  cc->lastPos = t++;
 
795
                  cc->depth = depth;
 
796
                  cc->qdepth = qdepth;
 
797
                  cc->state = 1;
 
798
                  cc->stack = stack;
 
799
                  cc->esc = 0;
 
800
                  cc->last_sexp = sx;
 
801
                  assert(sx != NULL);
 
802
 
 
803
                  return cc;
 
804
                }
 
805
            }
 
806
          else
 
807
            {
 
808
              vcur[0] = t[0];
 
809
              val_used++;
 
810
 
 
811
              if (val_used == val_allocated) {
 
812
                val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
 
813
                assert(val != NULL);
 
814
                vcur = val + val_used;
 
815
                val_allocated += sexp_val_grow_size;
 
816
              } else vcur++;
 
817
 
 
818
              if (t[0] == '\\') { 
 
819
                esc = 1;  
 
820
              } else 
 
821
                esc = 0;
 
822
            }
 
823
          t++;
 
824
          break;
 
825
        case 6:
 
826
          vcur = val;
 
827
          state = 1;
 
828
          break;
 
829
        case 7:
 
830
          if (t[0] == '\"')
 
831
            {
 
832
              state = 5;
 
833
              vcur = val;
 
834
            }
 
835
          else if (t[0] == '(')
 
836
            {
 
837
              vcur = val;
 
838
              state = 8;
 
839
            }
 
840
          else
 
841
            {
 
842
              vcur = val;
 
843
              state = 4;
 
844
            }
 
845
          break;
 
846
        case 8:
 
847
          if (esc == 0) {
 
848
            if (t[0] == '(')
 
849
              {
 
850
                qdepth++;
 
851
              }
 
852
            else if (t[0] == ')')
 
853
              {
 
854
                qdepth--;
 
855
                state = 9;
 
856
              }
 
857
            else if (t[0] == '\"')
 
858
              {
 
859
                state = 10;
 
860
              }
 
861
          } else {
 
862
            esc = 0;
 
863
          }
 
864
          vcur[0] = t[0];
 
865
          if (t[0] == '\\') esc = 1;
 
866
          else esc = 0;
 
867
          val_used++;
 
868
 
 
869
          if (val_used == val_allocated) {
 
870
            val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
 
871
            assert(val != NULL);
 
872
            vcur = val + val_used;
 
873
            val_allocated += sexp_val_grow_size;
 
874
          } else vcur++;
 
875
 
 
876
          t++;
 
877
          /* let it fall through to state 9 if we know we're transitioning
 
878
             into that state */
 
879
          if (state != 9)
 
880
            break;
 
881
        case 9:
 
882
          if (qdepth == 0)
 
883
            {
 
884
              state = 1;
 
885
              vcur[0] = '\0';
 
886
              /* sx = (sexp_t *) malloc (sizeof (sexp_t)); */
 
887
              sx = sexp_t_allocate();
 
888
              assert(sx!=NULL);
 
889
              elts++;
 
890
              sx->ty = SEXP_VALUE;
 
891
              sx->val = val;
 
892
              sx->val_allocated = val_allocated;
 
893
              sx->val_used = val_used;
 
894
              sx->next = NULL;
 
895
              sx->aty = SEXP_SQUOTE;
 
896
 
 
897
              val = (char *)malloc(sizeof(char)*sexp_val_start_size);
 
898
              assert(val != NULL);
 
899
              val_allocated = sexp_val_start_size;
 
900
              val_used = 0;
 
901
              vcur = val;
 
902
              
 
903
              if (!empty_stack (stack))
 
904
                {
 
905
                  data = (parse_data_t *) top_data (stack);
 
906
                  if (data->fst == NULL)
 
907
                    {
 
908
                      data->fst = data->lst = sx;
 
909
                    }
 
910
                  else
 
911
                    {
 
912
                      data->lst->next = sx;
 
913
                      data->lst = sx;
 
914
                    }
 
915
                }
 
916
              else
 
917
                {
 
918
                  /* looks like the whole expression was a single
 
919
                     quoted value!  So return it. */
 
920
                  cc->error = 0;
 
921
                  cc->val = val;
 
922
                  cc->val_used = val_used;
 
923
                  cc->val_allocated = val_allocated;
 
924
                  cc->vcur = vcur;
 
925
                  cc->lastPos = t;
 
926
                  cc->depth = depth;
 
927
                  cc->qdepth = qdepth;
 
928
                  cc->state = 1;
 
929
                  cc->stack = stack;
 
930
                  cc->esc = 0;
 
931
                  cc->last_sexp = sx;
 
932
                  assert(sx != NULL);
 
933
 
 
934
                  return cc;
 
935
                }
 
936
            }
 
937
          else
 
938
            state = 8;
 
939
          break;
 
940
        case 10:
 
941
          if (t[0] == '\"' && esc == 0)
 
942
            {
 
943
              state = 8;
 
944
            }
 
945
          vcur[0] = t[0];
 
946
          if (t[0] == '\\') esc = 1;
 
947
          else esc = 0;
 
948
          val_used++;
 
949
 
 
950
          if (val_used == val_allocated) {
 
951
            val = (char *)realloc(val,val_allocated+sexp_val_grow_size);
 
952
            assert(val != NULL);
 
953
            vcur = val + val_used;
 
954
            val_allocated += sexp_val_grow_size;
 
955
          } else vcur++;
 
956
 
 
957
          t++;
 
958
          break;
 
959
        case 11:
 
960
          if (t[0] == '\n') {
 
961
            state = 1;
 
962
          }
 
963
          t++;
 
964
          break;
 
965
        default:
 
966
          fprintf (stderr, "Unknown parser state %d.\n", state);
 
967
          break;
 
968
        }
 
969
    }
 
970
 
 
971
#ifdef _DEBUG_
 
972
  fprintf(stderr,"State Machine Iterations: %d\nMax Paren Depth: %d\n",
 
973
          fsm_iterations, maxdepth);
 
974
#endif /* _DEBUG_ */
 
975
 
 
976
  if (depth == 0 && elts > 0) {
 
977
    cc->error = 0;
 
978
    cc->val = val;
 
979
    cc->val_used = val_used;
 
980
    cc->val_allocated = val_allocated;
 
981
    cc->vcur = vcur;
 
982
    cc->lastPos = t;
 
983
    cc->depth = depth;
 
984
    cc->qdepth = qdepth;
 
985
    cc->state = 1;
 
986
    cc->stack = stack;
 
987
    cc->esc = 0;
 
988
    while (stack->top != NULL)
 
989
    {
 
990
      lvl = pop (stack);
 
991
      data = (parse_data_t *) lvl->data;
 
992
      sx = data->fst;
 
993
      /* free (data); */
 
994
      pd_deallocate(data);
 
995
      lvl->data = NULL;
 
996
    }
 
997
    cc->last_sexp = sx;
 
998
  } else {
 
999
    cc->val = val;
 
1000
    cc->esc = esc;
 
1001
    cc->vcur = vcur;
 
1002
    cc->val_allocated = val_allocated;
 
1003
    cc->val_used = val_used;
 
1004
    if (t[0] == '\0' || t == bufEnd)
 
1005
      cc->lastPos = NULL;
 
1006
    else
 
1007
      cc->lastPos = t;
 
1008
    cc->depth = depth;
 
1009
    cc->qdepth = qdepth;
 
1010
    cc->state = state;
 
1011
    cc->stack = stack;
 
1012
    cc->last_sexp = NULL;
 
1013
    cc->error = 0;
 
1014
  }
 
1015
  
 
1016
  return cc;
 
1017
}