ia64/xen-unstable

view tools/vnet/libxutil/sxpr_parser.c @ 6766:219d96d545fc

merge?
author cl349@firebug.cl.cam.ac.uk
date Mon Sep 12 20:00:41 2005 +0000 (2005-09-12)
parents dd668f7527cb
children b2f4823b6ff0 b35215021b32 9af349b055e5 3233e7ecfa9f
line source
1 /*
2 * Copyright (C) 2001 - 2005 Mike Wray <mike.wray@hp.com>
3 *
4 * This library is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1 of the
7 * License, or (at your option) any later version. This library is
8 * distributed in the hope that it will be useful, but WITHOUT ANY
9 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE.
11 * See the GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
18 #ifdef __KERNEL__
19 # include <linux/config.h>
20 # include <linux/module.h>
21 # include <linux/kernel.h>
22 # include <linux/string.h>
23 # include <linux/errno.h>
24 #else
25 # include <stdlib.h>
26 # include <errno.h>
27 #endif
29 #include "sys_net.h"
31 #include "iostream.h"
32 #include "lexis.h"
33 #include "sxpr_parser.h"
34 #include "sys_string.h"
35 #include "enum.h"
37 /** @file
38 * Sxpr parsing.
39 *
40 * So that the parser does not leak memory, all sxprs constructed by
41 * the parser must be freed on error. On successful parse the sxpr
42 * returned becomes the responsibility of the caller.
43 *
44 * @author Mike Wray <mike.wray@hpl.hp.com>
45 */
47 #ifdef DEBUG
48 #define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
49 #else
50 #define dprintf(fmt, args...) do{ }while(0)
51 #endif
53 #undef printf
54 #define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args)
56 static int state_start(Parser *p, char c);
57 static int begin_start(Parser *p, char c);
59 #if 0
60 /** Print a parse error.
61 *
62 * @param in parser
63 * @param msg format followed by printf arguments
64 */
65 static void eprintf(Parser *in, char *msg, ...){
66 va_list args;
67 if(in->error_out){
68 va_start(args, msg);
69 IOStream_vprint(in->error_out, msg, args);
70 va_end(args);
71 }
72 }
74 /** Print a parse warning.
75 *
76 * @param in parser
77 * @param msg format followed by printf arguments
78 */
79 static void wprintf(Parser *in, char *msg, ...){
80 va_list args;
81 if(in->error_out){
82 va_start(args, msg);
83 IOStream_vprint(in->error_out, msg, args);
84 va_end(args);
85 }
86 }
87 #endif
90 /*============================================================================*/
92 /** Record defining the message for a parse error. */
93 typedef struct {
94 ParseErrorId id;
95 char *message;
96 } ParseError;
98 /** Format for printing parse error messages. */
99 #define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s"
101 /** Message catalog for the parse error codes. */
102 static ParseError catalog[] = {
103 { PARSE_ERR_UNSPECIFIED, "unspecified error" },
104 { PARSE_ERR_NOMEM, "out of memory" },
105 { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
106 { PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
107 { PARSE_ERR_INVALID_SYNTAX, "syntax error" },
108 { PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
109 { 0, NULL }
110 };
112 /** Number of entries in the message catalog. */
113 const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
115 /** Set the parser error stream.
116 * Parse errors are reported on the the error stream if it is non-null.
117 *
118 * @param z parser
119 * @param error_out error stream
120 */
121 void Parser_set_error_stream(Parser *z, IOStream *error_out){
122 z->error_out = error_out;
123 }
125 /** Get the parser error message for an error code.
126 *
127 * @param id error code
128 * @return error message (empty string if the code is unknown)
129 */
130 static char *get_message(ParseErrorId id){
131 int i;
132 for(i = 0; i < catalog_n; i++){
133 if(id == catalog[i].id){
134 return catalog[i].message;
135 }
136 }
137 return "";
138 }
140 #if 0
141 /** Get the line number.
142 *
143 * @param in parser
144 */
145 static int get_line(Parser *in){
146 return in->line_no;
147 }
149 /** Get the column number.
150 *
151 * @param in parser
152 */
153 static int get_column(Parser *in){
154 return in->char_no;
155 }
156 #endif
158 /** Get the line number the current token started on.
159 *
160 * @param in parser
161 */
162 static int get_tok_line(Parser *in){
163 return in->tok_begin_line;
164 }
166 /** Get the column number the current token started on.
167 *
168 * @param in parser
169 */
170 static int get_tok_column(Parser *in){
171 return in->tok_begin_char;
172 }
174 /** Return the current token.
175 * The return value points at the internal buffer, so
176 * it must not be modified (or freed). Use copy_token() if you need a copy.
177 *
178 * @param p parser
179 * @return token
180 */
181 char *peek_token(Parser *p){
182 return p->tok;
183 }
185 int token_len(Parser *p){
186 return p->tok_end - p->tok;
187 }
189 /** Return a copy of the current token.
190 * The returned value should be freed when finished with.
191 *
192 * @param p parser
193 * @return copy of token
194 */
195 char *copy_token(Parser *p){
196 int n = token_len(p);
197 char *buf = allocate(n + 1);
198 if(buf){
199 memcpy(buf, peek_token(p), n);
200 buf[n] = '\0';
201 }
202 return buf;
203 }
205 void new_token(Parser *p){
206 memset(p->buf, 0, p->buf_end - p->buf);
207 p->tok = p->buf;
208 p->tok_end = p->tok;
209 p->tok_begin_line = p->line_no;
210 p->tok_begin_char = p->char_no;
211 }
213 /** Report a parse error.
214 * Does nothing if the error stream is null or there is no error.
215 *
216 * @param in parser
217 */
218 static void report_error(Parser *in){
219 if(in->error_out && in->err){
220 char *msg = get_message(in->err);
221 char *tok = peek_token(in);
222 IOStream_print(in->error_out, PARSE_ERR_FMT,
223 get_tok_line(in), get_tok_column(in), msg);
224 if(tok && tok[0]){
225 IOStream_print(in->error_out, " '%s'", tok);
226 }
227 IOStream_print(in->error_out, "\n");
228 }
229 }
231 /** Get the error message for the current parse error code.
232 * Does nothing if there is no error.
233 *
234 * @param in parser
235 * @param buf where to place the message
236 * @param n maximum number of characters to place in buf
237 * @return current error code (zero for no error)
238 */
239 int Parser_error_message(Parser *in, char *buf, int n){
240 if(in->err){
241 char *msg = get_message(in->err);
242 snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in),
243 get_tok_column(in), msg);
244 }
245 return in->err;
246 }
248 /** Flag a parse error. All subsequent reads will fail.
249 * Does not change the parser error code if it is already set.
250 *
251 * @param in parser
252 * @param id error code
253 */
254 int Parser_error_id(Parser *in, ParseErrorId id){
255 if(!in->err){
256 in->err = id;
257 report_error(in);
258 }
259 return -EINVAL;
260 }
262 /** Flag an unspecified parse error.
263 *
264 * @param in parser
265 */
266 int Parser_error(Parser *in){
267 return Parser_error_id(in, PARSE_ERR_INVALID_SYNTAX);
268 }
270 /** Test if the parser's error flag is set.
271 *
272 * @param in parser
273 * @return 1 if set, 0 otherwise
274 */
275 int Parser_has_error(Parser *in){
276 return (in->err > 0);
277 }
279 /** Test if the parser is at end of input.
280 *
281 * @param in parser
282 * @return 1 if at EOF, 0 otherwise
283 */
284 int Parser_at_eof(Parser *p){
285 return p->eof;
286 }
288 void ParserState_free(ParserState *z){
289 if(!z) return;
290 objfree(z->val);
291 deallocate(z);
292 }
294 int ParserState_new(ParserStateFn *fn, char *name,
295 ParserState *parent, ParserState **val){
296 int err = -ENOMEM;
297 ParserState *z;
298 z = ALLOCATE(ParserState);
299 if(!z) goto exit;
300 z->name = name;
301 z->fn = fn;
302 z->parent = parent;
303 z->val = ONULL;
304 err = 0;
305 exit:
306 *val = (err ? NULL : z);
307 return err;
308 }
310 void Parser_pop(Parser *p){
311 ParserState *s = p->state;
312 if(!s) return;
313 p->state = s->parent;
314 if (p->start_state == s) {
315 p->start_state = NULL;
316 }
317 ParserState_free(s);
318 }
320 /** Free a parser.
321 * No-op if the parser is null.
322 *
323 * @param z parser
324 */
325 void Parser_free(Parser *z){
326 if(!z) return;
327 // Hmmm. Need to free states, but careful about double free of values.
328 while(z->state){
329 objfree(z->state->val);
330 Parser_pop(z);
331 }
332 if(z->buf) deallocate(z->buf);
333 objfree(z->val);
334 z->val = ONONE;
335 deallocate(z);
336 }
338 int Parser_push(Parser *p, ParserStateFn *fn, char *name){
339 return ParserState_new(fn, name, p->state, &p->state);
340 }
342 int Parser_return(Parser *p){
343 int err = 0;
344 Sxpr val = ONONE;
345 if(!p->state){
346 err = -EINVAL;
347 goto exit;
348 }
349 val = p->state->val;
350 p->state->val = ONONE;
351 Parser_pop(p);
352 if(p->state){
353 err = cons_push(&p->state->val, val);
354 } else {
355 val = nrev(val);
356 p->val = val;
357 }
358 exit:
359 if(err){
360 objfree(val);
361 }
362 return err;
363 }
365 /** Reset the fields of a parser to initial values.
366 *
367 * @param z parser
368 */
369 static void reset(Parser *z){
370 // leave flags
371 // leave error_out
372 while(z->state){
373 Parser_pop(z);
374 }
375 z->val = ONONE;
376 z->eof = 0;
377 z->err = 0;
378 z->line_no = 1;
379 z->char_no = 0;
380 memset(z->buf, 0, z->buf_end - z->buf);
381 z->tok = z->buf;
382 z->tok_end = z->tok;
383 z->tok_begin_line = 0;
384 z->tok_begin_char = 0;
385 z->start_state = NULL;
386 }
388 /** Create a new parser. The error stream defaults to null.
389 */
390 Parser * Parser_new(void){
391 Parser *z = ALLOCATE(Parser);
392 int n = PARSER_BUF_SIZE;
393 int err = -ENOMEM;
395 if(!z) goto exit;
396 z->buf = allocate(n);
397 if(!z->buf) goto exit;
398 err = 0;
399 z->buf_end = z->buf + n;
400 z->begin = begin_start;
401 reset(z);
402 exit:
403 if(err){
404 Parser_free(z);
405 z = NULL;
406 }
407 return z;
408 }
410 /** Get the next character.
411 * Records the character read in the parser,
412 * and sets the line and character counts.
413 *
414 * @param p parser
415 * @return error flag: 0 on success, non-zero on error
416 */
417 static int input_char(Parser *p, char c){
418 int err = 0;
419 if(c=='\n'){
420 p->line_no++;
421 p->char_no = 0;
422 } else {
423 p->char_no++;
424 }
425 return err;
426 }
428 int save_char(Parser *p, char c){
429 int err = 0;
430 if(p->tok_end >= p->buf_end){
431 int buf_n = (p->buf_end - p->buf) + PARSER_BUF_INCREMENT;
432 char *buf = allocate(buf_n);
433 if(!buf){
434 err = -ENOMEM;
435 goto exit;
436 }
437 memcpy(buf, p->buf, p->tok_end - p->buf);
438 p->buf_end = buf + buf_n;
439 p->tok = buf + (p->tok - p->buf);
440 p->tok_end = buf + (p->tok_end - p->buf);
441 deallocate(p->buf);
442 p->buf = buf;
443 }
444 *p->tok_end++ = c;
445 exit:
446 return err;
447 }
449 /** Determine if a character is a separator.
450 *
451 * @param p parser
452 * @param c character to test
453 * @return 1 if a separator, 0 otherwise
454 */
455 static int is_separator(Parser *p, char c){
456 return in_sep_class(c);
457 }
459 int Parser_set_value(Parser *p, Sxpr obj){
460 int err = 0;
461 if(NOMEMP(obj)){
462 err = -ENOMEM;
463 } else {
464 p->state->val = obj;
465 }
466 return err;
467 }
469 int Parser_intern(Parser *p){
470 Sxpr obj = intern(peek_token(p));
471 return Parser_set_value(p, obj);
472 }
474 int Parser_atom(Parser *p){
475 Sxpr obj;
476 long v;
477 if(Parser_flags(p, PARSE_INT) &&
478 convert_atol(peek_token(p), &v) == 0){
479 obj = OINT(v);
480 } else {
481 obj = atom_new(peek_token(p));
482 }
483 return Parser_set_value(p, obj);
484 }
486 int Parser_string(Parser *p){
487 Sxpr obj = string_new_n(peek_token(p), token_len(p));
488 return Parser_set_value(p, obj);
489 }
491 int Parser_data(Parser *p){
492 Sxpr obj = string_new_n(peek_token(p), token_len(p));
493 return Parser_set_value(p, obj);
494 }
496 int Parser_uint(Parser *p){
497 unsigned int x = htonl(*(unsigned int *)peek_token(p));
498 return Parser_set_value(p, OINT(x));
499 }
501 static int get_escape(char c, char *d){
502 int err = 0;
503 switch(c){
504 case 'a': *d = '\a'; break;
505 case 'b': *d = '\b'; break;
506 case 'f': *d = '\f'; break;
507 case 'n': *d = '\n'; break;
508 case 'r': *d = '\r'; break;
509 case 't': *d = '\t'; break;
510 case 'v': *d = '\v'; break;
511 case c_escape: *d = c_escape; break;
512 case c_single_quote: *d = c_single_quote; break;
513 case c_double_quote: *d = c_double_quote; break;
514 default:
515 err = -EINVAL;
516 }
517 return err;
518 }
520 int Parser_ready(Parser *p){
521 return CONSP(p->val) || (p->start_state && CONSP(p->start_state->val));
522 }
524 Sxpr Parser_get_val(Parser *p){
525 Sxpr v = ONONE;
526 if(CONSP(p->val)){
527 } else if (p->start_state && CONSP(p->start_state->val)){
528 p->val = p->start_state->val;
529 p->val = nrev(p->val);
530 p->start_state->val = ONULL;
531 } else {
532 goto exit;
533 }
534 Sxpr w = p->val;
535 v = CAR(w);
536 p->val = CDR(w);
537 hfree(w);
538 exit:
539 return v;
540 }
542 Sxpr Parser_get_all(Parser *p){
543 Sxpr v = ONULL;
544 if(CONSP(p->val)){
545 v = p->val;
546 p->val = ONONE;
547 } else if(p->start_state && CONSP(p->start_state->val)){
548 v = p->start_state->val;
549 p->start_state->val = ONULL;
550 v = nrev(v);
551 }
552 return v;
553 }
555 static int state_comment(Parser *p, char c){
556 int err = 0;
557 if(c == '\n' || Parser_at_eof(p)){
558 Parser_pop(p);
559 } else {
560 err = input_char(p, c);
561 }
562 return err;
563 }
565 static int begin_comment(Parser *p, char c){
566 int err = 0;
567 err = Parser_push(p, state_comment, "comment");
568 if(err) goto exit;
569 err = input_char(p, c);
570 exit:
571 return err;
572 }
574 static int end_string(Parser *p){
575 int err = 0;
576 err = Parser_string(p);
577 if(err) goto exit;
578 err = Parser_return(p);
579 exit:
580 return err;
581 }
583 static int octaldone(Parser *p){
584 int err = 0;
585 char d = (char)(p->state->ival & 0xff);
586 Parser_pop(p);
587 err = Parser_input_char(p, d);
588 return err;
589 }
591 static int octaldigit(Parser *p, int d){
592 int err = 0;
593 p->state->ival *= 8;
594 p->state->ival += d;
595 p->state->count++;
596 if(err) goto exit;
597 if(p->state->ival < 0 || p->state->ival > 0xff){
598 err = Parser_error(p);
599 goto exit;
600 }
601 if(p->state->count == 3){
602 err = octaldone(p);
603 }
604 exit:
605 return err;
606 }
608 static int state_octal(Parser *p, char c){
609 int err = 0;
610 if(Parser_at_eof(p)){
611 err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
612 goto exit;
613 } else if('0' <= c && c <= '7'){
614 err = octaldigit(p, c - '0');
615 } else {
616 err = octaldone(p);
617 if(err) goto exit;
618 Parser_input_char(p, c);
619 }
620 exit:
621 return err;
622 }
624 static int hexdone(Parser *p){
625 int err = 0;
626 char d = (char)(p->state->ival & 0xff);
627 Parser_pop(p);
628 err = Parser_input_char(p, d);
629 return err;
630 }
632 static int hexdigit(Parser *p, int d){
633 int err = 0;
634 p->state->ival *= 16;
635 p->state->ival += d;
636 p->state->count++;
637 if(err) goto exit;
638 if(p->state->ival < 0 || p->state->ival > 0xff){
639 err = Parser_error(p);
640 goto exit;
641 }
642 if(p->state->count == 2){
643 err = hexdone(p);
644 }
645 exit:
646 return err;
647 }
649 static int state_hex(Parser *p, char c){
650 int err = 0;
651 if(Parser_at_eof(p)){
652 err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
653 goto exit;
654 } else if('0' <= c && c <= '9'){
655 err = hexdigit(p, c - '0');
656 } else if('A' <= c && c <= 'F'){
657 err = hexdigit(p, c - 'A' + 10);
658 } else if('a' <= c && c <= 'f'){
659 err = hexdigit(p, c - 'a' + 10);
660 } else if(p->state->count){
661 err = hexdone(p);
662 if(err) goto exit;
663 Parser_input_char(p, c);
664 }
665 exit:
666 return err;
667 }
669 static int state_escape(Parser *p, char c){
670 int err = 0;
671 char d;
672 if(Parser_at_eof(p)){
673 err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
674 goto exit;
675 }
676 if(get_escape(c, &d) == 0){
677 err = save_char(p, d);
678 if(err) goto exit;
679 Parser_pop(p);
680 } else if(c == 'x'){
681 p->state->fn = state_hex;
682 p->state->ival = 0;
683 p->state->count = 0;
684 } else {
685 p->state->fn = state_octal;
686 p->state->ival = 0;
687 p->state->count = 0;
688 err = Parser_input_char(p, c);
689 }
690 exit:
691 return err;
692 }
694 static int state_string(Parser *p, char c){
695 int err = 0;
696 if(Parser_at_eof(p)){
697 err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
698 } else if(c == p->state->delim){
699 err = end_string(p);
700 } else if(c == '\\'){
701 err = Parser_push(p, state_escape, "escape");
702 } else {
703 err = save_char(p, c);
704 }
705 return err;
706 }
708 static int begin_string(Parser *p, char c){
709 int err = 0;
710 err = Parser_push(p, state_string, "string");
711 if(err) goto exit;
712 new_token(p);
713 p->state->delim = c;
714 exit:
715 return err;
716 }
718 static int end_atom(Parser *p){
719 int err = 0;
720 err = Parser_atom(p);
721 if(err) goto exit;
722 err = Parser_return(p);
723 exit:
724 return err;
725 }
727 static int state_atom(Parser *p, char c){
728 int err = 0;
729 if(Parser_at_eof(p)){
730 err = end_atom(p);
731 } else if(is_separator(p, c) ||
732 in_space_class(c) ||
733 in_comment_class(c)){
734 err = end_atom(p);
735 if(err) goto exit;
736 err = Parser_input_char(p, c);
737 } else {
738 err = save_char(p, c);
739 }
740 exit:
741 return err;
742 }
744 static int begin_atom(Parser *p, char c){
745 int err = 0;
746 err = Parser_push(p, state_atom, "atom");
747 if(err) goto exit;
748 new_token(p);
749 err = save_char(p, c);
750 exit:
751 return err;
752 }
754 static int end_data(Parser *p){
755 int err = 0;
756 err = Parser_data(p);
757 if(err) goto exit;
758 err = Parser_return(p);
759 exit:
760 return err;
761 }
763 static int counted_data(Parser *p, char c){
764 int err = 0;
765 err = save_char(p, c);
766 if(err) goto exit;
767 if(token_len(p) == p->state->count){
768 err = end_data(p);
769 }
770 exit:
771 return err;
772 }
774 static int counted_data_count(Parser *p, char c){
775 int err = 0;
776 if(c == p->state->delim){
777 new_token(p);
778 p->state->count = p->state->ival;
779 p->state->fn = counted_data;
780 } else if('0' <= c && c <= '9'){
781 p->state->ival *= 10;
782 p->state->ival += c - '0';
783 } else {
784 err = -EINVAL;
785 }
786 return err;
787 }
789 static int quoted_data(Parser *p, char c){
790 int err = 0;
791 int count = p->state->count;
792 err = save_char(p, c);
793 if(err) goto exit;
794 // Check that buf is longer than delim and
795 // ends with delim. If so, trim delim off and return.
796 if((token_len(p) >= count) &&
797 !memcmp(p->tok_end - count, p->buf, count)){
798 p->tok_end -= count;
799 end_data(p);
800 }
801 exit:
802 return err;
803 }
805 static int quoted_data_delim(Parser *p, char c){
806 // Saves the delim in the token buffer.
807 int err = 0;
808 err = save_char(p, c);
809 if(err) goto exit;
810 if(c == p->state->delim){
811 p->state->fn = quoted_data;
812 p->state->count = token_len(p);
813 // Advance the token pointer past the delim.
814 p->tok = p->tok_end;
815 }
816 exit:
817 return err;
818 }
820 static int state_data(Parser *p, char c){
821 // Quoted data:
822 // <<delim< anything not containing delimiter<delim<
823 // Where 'delim' is anything not containing '<'.
824 // Counted data:
825 // <*nnn..* N bytes
826 // Where nnn... is N in decimal (
827 int err = 0;
828 switch(c){
829 case c_data_count:
830 p->state->delim = c;
831 p->state->fn = counted_data_count;
832 p->state->ival = 0;
833 new_token(p);
834 break;
835 case c_data_quote:
836 p->state->delim = c;
837 p->state->fn = quoted_data_delim;
838 new_token(p);
839 err = save_char(p, c);
840 break;
841 default:
842 err = Parser_error(p);
843 break;
844 }
845 return err;
846 }
848 static int begin_data(Parser *p, char c){
849 int err = 0;
850 err = Parser_push(p, state_data, "data");
851 if(err) goto exit;
852 new_token(p);
853 exit:
854 return err;
855 }
857 static int state_list(Parser *p, char c){
858 int err = 0;
859 dprintf(">\n");
860 if(Parser_at_eof(p)){
861 err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
862 } else if(c == c_list_close){
863 p->state->val = nrev(p->state->val);
864 err = Parser_return(p);
865 } else {
866 err = state_start(p, c);
867 }
868 dprintf("< err=%d\n", err);
869 return err;
871 }
873 static int begin_list(Parser *p, char c){
874 return Parser_push(p, state_list, "list");
875 }
877 static int state_start(Parser *p, char c){
878 int err = 0;
879 dprintf(">\n");
880 if(Parser_at_eof(p)){
881 err = Parser_return(p);
882 } else if(in_space_class(c)){
883 //skip
884 } else if(in_comment_class(c)){
885 begin_comment(p, c);
886 } else if(c == c_list_open){
887 begin_list(p, c);
888 } else if(c == c_list_close){
889 err = Parser_error(p);
890 } else if(in_string_quote_class(c)){
891 begin_string(p, c);
892 } else if(c == c_data_open){
893 begin_data(p, c);
894 } else if(in_printable_class(c)){
895 begin_atom(p, c);
896 } else if(c == 0x04){
897 //ctrl-D, EOT: end-of-text.
898 Parser_input_eof(p);
899 } else {
900 err = Parser_error(p);
901 }
902 dprintf("< err=%d\n", err);
903 return err;
904 }
906 int begin_start(Parser *p, char c){
907 int err = 0;
908 dprintf(">\n");
909 err = Parser_push(p, state_start, "start");
910 if(err) goto exit;
911 p->start_state = p->state;
912 exit:
913 dprintf("< err=%d\n", err);
914 return err;
915 }
917 int Parser_input_char(Parser *p, char c){
918 int err = 0;
919 if(Parser_at_eof(p)){
920 //skip;
921 } else {
922 input_char(p, c);
923 }
924 if(!p->state){
925 err = p->begin(p, c);
926 if(err) goto exit;
927 }
928 err = p->state->fn(p, c);
929 exit:
930 return err;
931 }
933 int Parser_input_eof(Parser *p){
934 int err = 0;
935 p->eof = 1;
936 err = Parser_input_char(p, IOSTREAM_EOF);
937 return err;
938 }
940 int Parser_input(Parser *p, char *buf, int buf_n){
941 int err = 0;
942 int i = 0;
943 dprintf("> |%s|\n", buf);
944 if(buf_n <= 0){
945 err = Parser_input_eof(p);
946 goto exit;
947 }
948 for(i = 0; i < buf_n; i++){
949 err = Parser_input_char(p, buf[i]);
950 if(err) goto exit;
951 }
952 exit:
953 err = (err < 0 ? err : buf_n);
954 dprintf("< err=%d\n", err);
955 return err;
956 }
958 #ifdef SXPR_PARSER_MAIN
959 /* Stuff for standalone testing. */
961 #include "file_stream.h"
962 //#include "string_stream.h"
964 /** Main program for testing.
965 * Parses input and prints it.
966 *
967 * @param argc number of arguments
968 * @param argv arguments
969 * @return error code
970 */
971 int main(int argc, char *argv[]){
972 Parser *pin;
973 int err = 0;
974 char buf[1024];
975 int k;
976 Sxpr obj;
977 int i = 0;
979 pin = Parser_new();
980 Parser_set_error_stream(pin, iostdout);
981 dprintf("> parse...\n");
982 while(1){
983 k = fread(buf, 1, 100, stdin);
984 if(k>=0){
985 buf[k+1] = '\0';
986 }
987 err = Parser_input(pin, buf, k);
988 while(Parser_ready(pin)){
989 obj = Parser_get_val(pin);
990 printf("obj %d\n", i++);
991 objprint(iostdout, obj, 0); printf("\n");
992 }
993 if(k <= 0) break;
994 }
995 dprintf("> err=%d\n", err);
996 return 0;
997 }
998 #endif