mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
935 lines
21 KiB
C
935 lines
21 KiB
C
/*
|
|
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
* published by the Free Software Foundation; either version 2.1 of the
|
|
* License, or (at your option) any later version. This library is
|
|
* distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this library; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifdef __KERNEL__
|
|
# include <linux/config.h>
|
|
# include <linux/module.h>
|
|
# include <linux/kernel.h>
|
|
# include <linux/string.h>
|
|
# include <linux/errno.h>
|
|
#else
|
|
# include <stdlib.h>
|
|
# include <errno.h>
|
|
#endif
|
|
|
|
#include "iostream.h"
|
|
#include "lexis.h"
|
|
#include "sxpr_parser.h"
|
|
#include "sys_string.h"
|
|
#include "enum.h"
|
|
|
|
/** @file
|
|
* Sxpr parsing.
|
|
*
|
|
* So that the parser does not leak memory, all sxprs constructed by
|
|
* the parser must be freed on error. On successful parse the sxpr
|
|
* returned becomes the responsibility of the caller.
|
|
*
|
|
* @author Mike Wray <mike.wray@hpl.hp.com>
|
|
*/
|
|
|
|
#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
|
|
#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args)
|
|
|
|
static void reset(Parser *z);
|
|
static int inputchar(Parser *p, char c);
|
|
static int savechar(Parser *p, char c);
|
|
extern void parse_error(Parser *in);
|
|
extern void parse_error_id(Parser *in, ParseErrorId id);
|
|
|
|
static int begin_start(Parser *p, char c);
|
|
static int state_start(Parser *p, char c);
|
|
static int end_start(Parser *p);
|
|
|
|
static int begin_comment(Parser *p, char c);
|
|
static int state_comment(Parser *p, char c);
|
|
static int end_comment(Parser *p);
|
|
|
|
static int begin_string(Parser *p, char c);
|
|
static int state_string(Parser *p, char c);
|
|
static int end_string(Parser *p);
|
|
static int state_escape(Parser *p, char c);
|
|
static int state_octal(Parser *p, char c);
|
|
static int state_hex(Parser *p, char c);
|
|
|
|
static int begin_atom(Parser *p, char c);
|
|
static int state_atom(Parser *p, char c);
|
|
static int end_atom(Parser *p);
|
|
|
|
static int state_list(Parser *p, char c);
|
|
static int begin_list(Parser *p, char c);
|
|
static int end_list(Parser *p);
|
|
|
|
/** Print a parse error.
|
|
*
|
|
* @param in parser
|
|
* @param msg format followed by printf arguments
|
|
*/
|
|
void eprintf(Parser *in, char *msg, ...){
|
|
va_list args;
|
|
if(in->error_out){
|
|
va_start(args, msg);
|
|
IOStream_vprint(in->error_out, msg, args);
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
/** Print a parse warning.
|
|
*
|
|
* @param in parser
|
|
* @param msg format followed by printf arguments
|
|
*/
|
|
void wprintf(Parser *in, char *msg, ...){
|
|
va_list args;
|
|
if(in->error_out){
|
|
va_start(args, msg);
|
|
IOStream_vprint(in->error_out, msg, args);
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
/*============================================================================*/
|
|
|
|
/** Record defining the message for a parse error. */
|
|
typedef struct {
|
|
ParseErrorId id;
|
|
char *message;
|
|
} ParseError;
|
|
|
|
/** Format for printing parse error messages. */
|
|
#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s"
|
|
|
|
/** Message catalog for the parse error codes. */
|
|
static ParseError catalog[] = {
|
|
{ PARSE_ERR_UNSPECIFIED, "unspecified error" },
|
|
{ PARSE_ERR_NOMEM, "out of memory" },
|
|
{ PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
|
|
{ PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
|
|
{ PARSE_ERR_INVALID_SYNTAX, "syntax error" },
|
|
{ PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
/** Number of entries in the message catalog. */
|
|
const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
|
|
|
|
void ParserState_free(ParserState *z){
|
|
if(!z) return;
|
|
objfree(z->val);
|
|
deallocate(z);
|
|
}
|
|
|
|
int ParserState_new(ParserStateFn *fn, char *name,
|
|
ParserState *parent, ParserState **val){
|
|
int err = 0;
|
|
ParserState *z;
|
|
z = ALLOCATE(ParserState);
|
|
if(z){
|
|
z->name = name;
|
|
z->fn = fn;
|
|
z->parent = parent;
|
|
z->val = ONULL;
|
|
} else {
|
|
err = -ENOMEM;
|
|
}
|
|
if(!err) *val = z;
|
|
return err;
|
|
}
|
|
|
|
/** Free a parser.
|
|
* No-op if the parser is null.
|
|
*
|
|
* @param z parser
|
|
*/
|
|
void Parser_free(Parser *z){
|
|
if(!z) return;
|
|
objfree(z->val);
|
|
z->val = ONONE;
|
|
deallocate(z);
|
|
}
|
|
|
|
/** Create a new parser. The error stream defaults to null.
|
|
*/
|
|
Parser * Parser_new(void){
|
|
Parser *z = ALLOCATE(Parser);
|
|
int err = -ENOMEM;
|
|
|
|
if(!z) goto exit;
|
|
err = 0;
|
|
reset(z);
|
|
exit:
|
|
if(err){
|
|
Parser_free(z);
|
|
z = NULL;
|
|
}
|
|
return z;
|
|
}
|
|
|
|
/** Get the next character.
|
|
* Records the character read in the parser,
|
|
* and sets the line and character counts.
|
|
*
|
|
* @param p parser
|
|
* @return error flag: 0 on success, non-zero on error
|
|
*/
|
|
static int inputchar(Parser *p, char c){
|
|
int err = 0;
|
|
if(c=='\n'){
|
|
p->line_no++;
|
|
p->char_no = 0;
|
|
} else {
|
|
p->char_no++;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static int savechar(Parser *p, char c){
|
|
int err = 0;
|
|
if(p->buf_i >= p->buf_n){
|
|
err = -ENOMEM;
|
|
goto exit;
|
|
}
|
|
p->buf[p->buf_i] = c;
|
|
p->buf_i++;
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int Parser_input_char(Parser *p, char c){
|
|
int err = 0;
|
|
if(at_eof(p)){
|
|
//skip;
|
|
} else {
|
|
inputchar(p, c);
|
|
}
|
|
if(!p->state){
|
|
err = begin_start(p, c);
|
|
if(err) goto exit;
|
|
}
|
|
err = p->state->fn(p, c);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int Parser_input_eof(Parser *p){
|
|
int err = 0;
|
|
p->eof = 1;
|
|
err = Parser_input_char(p, IOSTREAM_EOF);
|
|
return err;
|
|
}
|
|
|
|
int Parser_input(Parser *p, char *buf, int buf_n){
|
|
int err = 0;
|
|
int i = 0;
|
|
if(buf_n <= 0){
|
|
err = Parser_input_eof(p);
|
|
goto exit;
|
|
}
|
|
for(i = 0; i<buf_n; i++){
|
|
err = Parser_input_char(p, buf[i]);
|
|
if(err) goto exit;
|
|
}
|
|
exit:
|
|
err = (err < 0 ? err : buf_n);
|
|
return err;
|
|
}
|
|
|
|
int Parser_push(Parser *p, ParserStateFn *fn, char *name){
|
|
int err = 0;
|
|
err = ParserState_new(fn, name, p->state, &p->state);
|
|
return err;
|
|
}
|
|
|
|
int Parser_pop(Parser *p){
|
|
int err = 0;
|
|
ParserState *s = p->state;
|
|
p->state = s->parent;
|
|
if (p->start_state == s) {
|
|
p->start_state = NULL;
|
|
}
|
|
ParserState_free(s);
|
|
return err;
|
|
}
|
|
|
|
int Parser_return(Parser *p){
|
|
int err = 0;
|
|
Sxpr val = ONONE;
|
|
if(!p->state){
|
|
err = -EINVAL;
|
|
goto exit;
|
|
}
|
|
val = p->state->val;
|
|
p->state->val = ONONE;
|
|
err = Parser_pop(p);
|
|
if(err) goto exit;
|
|
if(p->state){
|
|
err = cons_push(&p->state->val, val);
|
|
} else {
|
|
val = nrev(val);
|
|
p->val = val;
|
|
}
|
|
exit:
|
|
if(err){
|
|
objfree(val);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/** Determine if a character is a separator.
|
|
*
|
|
* @param p parser
|
|
* @param c character to test
|
|
* @return 1 if a separator, 0 otherwise
|
|
*/
|
|
static int is_separator(Parser *p, char c){
|
|
return in_sep_class(c);
|
|
}
|
|
|
|
/** Return the current token.
|
|
* The return value points at the internal buffer, so
|
|
* it must not be modified (or freed). Use copy_token() if you need a copy.
|
|
*
|
|
* @param p parser
|
|
* @return token
|
|
*/
|
|
char *peek_token(Parser *p){
|
|
return p->buf;
|
|
}
|
|
|
|
/** Return a copy of the current token.
|
|
* The returned value should be freed when finished with.
|
|
*
|
|
* @param p parser
|
|
* @return copy of token
|
|
*/
|
|
char *copy_token(Parser *p){
|
|
return strdup(peek_token(p));
|
|
}
|
|
|
|
static int do_intern(Parser *p){
|
|
int err = 0;
|
|
Sxpr obj = intern(peek_token(p));
|
|
if(NOMEMP(obj)){
|
|
err = -ENOMEM;
|
|
} else {
|
|
p->state->val = obj;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static int do_string(Parser *p){
|
|
int err = 0;
|
|
Sxpr obj;
|
|
obj = string_new(peek_token(p));
|
|
if(NOMEMP(obj)){
|
|
err = -ENOMEM;
|
|
} else {
|
|
p->state->val = obj;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
void newtoken(Parser *p){
|
|
memset(p->buf, 0, p->buf_n);
|
|
p->buf_i = 0;
|
|
p->tok_begin_line = p->line_no;
|
|
p->tok_begin_char = p->char_no;
|
|
}
|
|
|
|
int get_escape(char c, char *d){
|
|
int err = 0;
|
|
switch(c){
|
|
case 'a': *d = '\a'; break;
|
|
case 'b': *d = '\b'; break;
|
|
case 'f': *d = '\f'; break;
|
|
case 'n': *d = '\n'; break;
|
|
case 'r': *d = '\r'; break;
|
|
case 't': *d = '\t'; break;
|
|
case 'v': *d = '\v'; break;
|
|
case c_escape: *d = c_escape; break;
|
|
case c_single_quote: *d = c_single_quote; break;
|
|
case c_double_quote: *d = c_double_quote; break;
|
|
default:
|
|
err = -EINVAL;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int Parser_ready(Parser *p){
|
|
return CONSP(p->val) || (p->start_state && CONSP(p->start_state->val));
|
|
}
|
|
|
|
Sxpr Parser_get_val(Parser *p){
|
|
Sxpr v = ONONE;
|
|
if(CONSP(p->val)){
|
|
v = CAR(p->val);
|
|
p->val = CDR(p->val);
|
|
} else if (CONSP(p->start_state->val)){
|
|
p->val = p->start_state->val;
|
|
p->val = nrev(p->val);
|
|
p->start_state->val = ONULL;
|
|
v = CAR(p->val);
|
|
p->val = CDR(p->val);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
Sxpr Parser_get_all(Parser *p){
|
|
Sxpr v = ONULL;
|
|
if(CONSP(p->val)){
|
|
v = p->val;
|
|
p->val = ONONE;
|
|
} else if(p->start_state && CONSP(p->start_state->val)){
|
|
v = p->start_state->val;
|
|
p->start_state->val = ONULL;
|
|
v = nrev(v);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
int begin_start(Parser *p, char c){
|
|
int err = 0;
|
|
err = Parser_push(p, state_start, "start");
|
|
if(err) goto exit;
|
|
p->start_state = p->state;
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int state_start(Parser *p, char c){
|
|
int err = 0;
|
|
if(at_eof(p)){
|
|
err = end_start(p);
|
|
} else if(in_space_class(c)){
|
|
//skip
|
|
} else if(in_comment_class(c)){
|
|
begin_comment(p, c);
|
|
} else if(c == c_list_open){
|
|
begin_list(p, c);
|
|
} else if(c == c_list_close){
|
|
parse_error(p);
|
|
err = -EINVAL;
|
|
} else if(in_string_quote_class(c)){
|
|
begin_string(p, c);
|
|
} else if(in_printable_class(c)){
|
|
begin_atom(p, c);
|
|
} else if(c == 0x04){
|
|
//ctrl-D, EOT: end-of-text.
|
|
Parser_input_eof(p);
|
|
} else {
|
|
parse_error(p);
|
|
err = -EINVAL;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int end_start(Parser *p){
|
|
int err = 0;
|
|
err = Parser_return(p);
|
|
return err;
|
|
}
|
|
|
|
int begin_comment(Parser *p, char c){
|
|
int err = 0;
|
|
err = Parser_push(p, state_comment, "comment");
|
|
if(err) goto exit;
|
|
err = inputchar(p, c);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int state_comment(Parser *p, char c){
|
|
int err = 0;
|
|
if(c == '\n' || at_eof(p)){
|
|
err = end_comment(p);
|
|
} else {
|
|
err = inputchar(p, c);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int end_comment(Parser *p){
|
|
return Parser_pop(p);
|
|
}
|
|
|
|
int begin_string(Parser *p, char c){
|
|
int err = 0;
|
|
err = Parser_push(p, state_string, "string");
|
|
if(err) goto exit;
|
|
newtoken(p);
|
|
p->state->delim = c;
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int state_string(Parser *p, char c){
|
|
int err = 0;
|
|
if(at_eof(p)){
|
|
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
|
|
err = -EINVAL;
|
|
} else if(c == p->state->delim){
|
|
err = end_string(p);
|
|
} else if(c == '\\'){
|
|
err = Parser_push(p, state_escape, "escape");
|
|
} else {
|
|
err = savechar(p, c);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int end_string(Parser *p){
|
|
int err = 0;
|
|
err = do_string(p);
|
|
if(err) goto exit;
|
|
err = Parser_return(p);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int state_escape(Parser *p, char c){
|
|
int err = 0;
|
|
char d;
|
|
if(at_eof(p)){
|
|
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
|
|
err = -EINVAL;
|
|
goto exit;
|
|
}
|
|
if(get_escape(c, &d) == 0){
|
|
err = savechar(p, d);
|
|
if(err) goto exit;
|
|
err = Parser_pop(p);
|
|
} else if(c == 'x'){
|
|
p->state->fn = state_hex;
|
|
p->state->ival = 0;
|
|
p->state->count = 0;
|
|
} else {
|
|
p->state->fn = state_octal;
|
|
p->state->ival = 0;
|
|
p->state->count = 0;
|
|
err = Parser_input_char(p, c);
|
|
}
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int octaldone(Parser *p){
|
|
int err = 0;
|
|
char d = (char)(p->state->ival & 0xff);
|
|
err = Parser_pop(p);
|
|
if(err) goto exit;
|
|
err = Parser_input_char(p, d);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int octaldigit(Parser *p, char c){
|
|
int err = 0;
|
|
p->state->ival *= 8;
|
|
p->state->ival += c - '0';
|
|
p->state->count++;
|
|
if(err) goto exit;
|
|
if(p->state->ival < 0 || p->state->ival > 0xff){
|
|
parse_error(p);
|
|
err = -EINVAL;
|
|
goto exit;
|
|
}
|
|
if(p->state->count == 3){
|
|
err = octaldone(p);
|
|
}
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int state_octal(Parser *p, char c){
|
|
int err = 0;
|
|
if(at_eof(p)){
|
|
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
|
|
err = -EINVAL;
|
|
goto exit;
|
|
} else if('0' <= c && c <= '7'){
|
|
err = octaldigit(p, c);
|
|
} else {
|
|
err = octaldone(p);
|
|
if(err) goto exit;
|
|
Parser_input_char(p, c);
|
|
}
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int hexdone(Parser *p){
|
|
int err = 0;
|
|
char d = (char)(p->state->ival & 0xff);
|
|
err = Parser_pop(p);
|
|
if(err) goto exit;
|
|
err = Parser_input_char(p, d);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int hexdigit(Parser *p, char c, char d){
|
|
int err = 0;
|
|
p->state->ival *= 16;
|
|
p->state->ival += c - d;
|
|
p->state->count++;
|
|
if(err) goto exit;
|
|
if(p->state->ival < 0 || p->state->ival > 0xff){
|
|
parse_error(p);
|
|
err = -EINVAL;
|
|
goto exit;
|
|
}
|
|
if(p->state->count == 2){
|
|
err = hexdone(p);
|
|
}
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int state_hex(Parser *p, char c){
|
|
int err = 0;
|
|
if(at_eof(p)){
|
|
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
|
|
err = -EINVAL;
|
|
goto exit;
|
|
} else if('0' <= c && c <= '9'){
|
|
err = hexdigit(p, c, '0');
|
|
} else if('A' <= c && c <= 'F'){
|
|
err = hexdigit(p, c, 'A');
|
|
} else if('a' <= c && c <= 'f'){
|
|
err = hexdigit(p, c, 'a');
|
|
} else if(p->state->count){
|
|
err =hexdone(p);
|
|
if(err) goto exit;
|
|
Parser_input_char(p, c);
|
|
}
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int begin_atom(Parser *p, char c){
|
|
int err = 0;
|
|
err = Parser_push(p, state_atom, "atom");
|
|
if(err) goto exit;
|
|
newtoken(p);
|
|
err = savechar(p, c);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int state_atom(Parser *p, char c){
|
|
int err = 0;
|
|
if(at_eof(p)){
|
|
err = end_atom(p);
|
|
} else if(is_separator(p, c) ||
|
|
in_space_class(c) ||
|
|
in_comment_class(c)){
|
|
err = end_atom(p);
|
|
if(err) goto exit;
|
|
err = Parser_input_char(p, c);
|
|
} else {
|
|
err = savechar(p, c);
|
|
}
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int end_atom(Parser *p){
|
|
int err = 0;
|
|
err = do_intern(p);
|
|
if(err) goto exit;
|
|
err = Parser_return(p);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
int state_list(Parser *p, char c){
|
|
int err = 0;
|
|
if(at_eof(p)){
|
|
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
|
|
err = -EINVAL;
|
|
} else if(c == c_list_close){
|
|
p->state->val = nrev(p->state->val);
|
|
err = end_list(p);
|
|
} else {
|
|
err = state_start(p, c);
|
|
}
|
|
return err;
|
|
|
|
}
|
|
|
|
int begin_list(Parser *p, char c){
|
|
return Parser_push(p, state_list, "list");
|
|
}
|
|
|
|
int end_list(Parser *p){
|
|
return Parser_return(p);
|
|
}
|
|
|
|
/** Reset the fields of a parser to initial values.
|
|
*
|
|
* @param z parser
|
|
*/
|
|
static void reset(Parser *z){
|
|
IOStream *error_out = z->error_out;
|
|
int flags = z->flags;
|
|
memzero(z, sizeof(Parser));
|
|
z->buf_n = sizeof(z->buf) - 1;
|
|
z->buf_i = 0;
|
|
z->line_no = 1;
|
|
z->char_no = 0;
|
|
z->error_out = error_out;
|
|
z->flags = flags;
|
|
}
|
|
|
|
/** Set the parser error stream.
|
|
* Parse errors are reported on the the error stream if it is non-null.
|
|
*
|
|
* @param z parser
|
|
* @param error_out error stream
|
|
*/
|
|
void set_error_stream(Parser *z, IOStream *error_out){
|
|
if(z){
|
|
z->error_out = error_out;
|
|
}
|
|
}
|
|
|
|
/** Get the parser error message for an error code.
|
|
*
|
|
* @param id error code
|
|
* @return error message (empty string if the code is unknown)
|
|
*/
|
|
static char *get_message(ParseErrorId id){
|
|
int i;
|
|
for(i=0; i<catalog_n; i++){
|
|
if(id == catalog[i].id){
|
|
return catalog[i].message;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
/** Get the line number.
|
|
*
|
|
* @param in parser
|
|
*/
|
|
int get_line(Parser *in){
|
|
return in->line_no;
|
|
}
|
|
|
|
/** Get the column number.
|
|
*
|
|
* @param in parser
|
|
*/
|
|
int get_column(Parser *in){
|
|
return in->char_no;
|
|
}
|
|
|
|
/** Get the line number the current token started on.
|
|
*
|
|
* @param in parser
|
|
*/
|
|
int get_tok_line(Parser *in){
|
|
return in->tok_begin_line;
|
|
}
|
|
|
|
/** Get the column number the current token started on.
|
|
*
|
|
* @param in parser
|
|
*/
|
|
int get_tok_column(Parser *in){
|
|
return in->tok_begin_char;
|
|
}
|
|
|
|
/** Report a parse error.
|
|
* Does nothing if the error stream is null or there is no error.
|
|
*
|
|
* @param in parser
|
|
*/
|
|
static void report_error(Parser *in){
|
|
if(in->error_out && in->err){
|
|
char *msg = get_message(in->err);
|
|
char *tok = peek_token(in);
|
|
IOStream_print(in->error_out, PARSE_ERR_FMT,
|
|
get_tok_line(in), get_tok_column(in), msg);
|
|
if(tok && tok[0]){
|
|
IOStream_print(in->error_out, " '%s'", tok);
|
|
}
|
|
IOStream_print(in->error_out, "\n");
|
|
}
|
|
}
|
|
|
|
/** Get the error message for the current parse error code.
|
|
* Does nothing if there is no error.
|
|
*
|
|
* @param in parser
|
|
* @param buf where to place the message
|
|
* @param n maximum number of characters to place in buf
|
|
* @return current error code (zero for no error)
|
|
*/
|
|
int parse_error_message(Parser *in, char *buf, int n){
|
|
if(in->err){
|
|
char *msg = get_message(in->err);
|
|
snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg);
|
|
}
|
|
return in->err;
|
|
}
|
|
|
|
/** Flag an unspecified parse error. All subsequent reads will fail.
|
|
*
|
|
* @param in parser
|
|
*/
|
|
void parse_error(Parser *in){
|
|
parse_error_id(in, PARSE_ERR_INVALID_SYNTAX);
|
|
}
|
|
|
|
/** Flag a parse error. All subsequent reads will fail.
|
|
* Does not change the parser error code if it is already set.
|
|
*
|
|
* @param in parser
|
|
* @param id error code
|
|
*/
|
|
void parse_error_id(Parser *in, ParseErrorId id){
|
|
if(!in->err){
|
|
in->err = id;
|
|
report_error(in);
|
|
}
|
|
}
|
|
|
|
/** Test if the parser's error flag is set.
|
|
*
|
|
* @param in parser
|
|
* @return 1 if set, 0 otherwise
|
|
*/
|
|
int has_error(Parser *in){
|
|
return (in->err > 0);
|
|
}
|
|
|
|
/** Test if the parser is at end of input.
|
|
*
|
|
* @param in parser
|
|
* @return 1 if at EOF, 0 otherwise
|
|
*/
|
|
int at_eof(Parser *p){
|
|
return p->eof;
|
|
}
|
|
|
|
#ifdef SXPR_PARSER_MAIN
|
|
/* Stuff for standalone testing. */
|
|
|
|
#include "file_stream.h"
|
|
#include "string_stream.h"
|
|
|
|
extern int stringof(Sxpr exp, char **s);
|
|
int child_string(Sxpr exp, Sxpr key, char **s){
|
|
int err = 0;
|
|
Sxpr val = sxpr_child_value(exp, key, ONONE);
|
|
err = stringof(val, s);
|
|
return err;
|
|
}
|
|
|
|
extern int intof(Sxpr exp, int *v);
|
|
int child_int(Sxpr exp, Sxpr key, int *v){
|
|
int err = 0;
|
|
Sxpr val = sxpr_child_value(exp, key, ONONE);
|
|
err = intof(val, v);
|
|
return err;
|
|
}
|
|
|
|
int eval_vnet(Sxpr exp){
|
|
int err = 0;
|
|
Sxpr oid = intern("id");
|
|
int id;
|
|
err = child_int(exp, oid, &id);
|
|
if(err) goto exit;
|
|
dprintf("> vnet id=%d\n", id);
|
|
exit:
|
|
dprintf("< err=%d\n", err);
|
|
return err;
|
|
}
|
|
|
|
int eval_connect(Sxpr exp){
|
|
int err = 0;
|
|
Sxpr ovif = intern("vif");
|
|
Sxpr ovnet = intern("vnet");
|
|
char *vif;
|
|
int vnet;
|
|
|
|
err = child_string(exp, ovif, &vif);
|
|
if(err) goto exit;
|
|
err = child_int(exp, ovnet, &vnet);
|
|
if(err) goto exit;
|
|
dprintf("> connect vif=%s vnet=%d\n", vif, vnet);
|
|
exit:
|
|
dprintf("< err=%d\n", err);
|
|
return err;
|
|
}
|
|
|
|
int eval(Sxpr exp){
|
|
int err = 0;
|
|
Sxpr oconnect = intern("connect");
|
|
Sxpr ovnet = intern("vnet");
|
|
|
|
if(sxpr_elementp(exp, ovnet)){
|
|
err = eval_vnet(exp);
|
|
} else if(sxpr_elementp(exp, oconnect)){
|
|
err = eval_connect(exp);
|
|
} else {
|
|
err = -EINVAL;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/** Main program for testing.
|
|
* Parses input and prints it.
|
|
*
|
|
* @param argc number of arguments
|
|
* @param argv arguments
|
|
* @return error code
|
|
*/
|
|
int main(int argc, char *argv[]){
|
|
Parser *pin;
|
|
int err = 0;
|
|
char buf[1024];
|
|
int k;
|
|
Sxpr obj;
|
|
//Sxpr l, x;
|
|
int i = 0;
|
|
|
|
pin = Parser_new();
|
|
set_error_stream(pin, iostdout);
|
|
dprintf("> parse...\n");
|
|
while(1){
|
|
k = fread(buf, 1, 1, stdin);
|
|
err = Parser_input(pin, buf, k);
|
|
while(Parser_ready(pin)){
|
|
obj = Parser_get_val(pin);
|
|
printf("obj %d\n", i++);
|
|
objprint(iostdout, obj, 0); printf("\n");
|
|
}
|
|
if(k <= 0) break;
|
|
}
|
|
/* obj = Parser_get_all(pin); */
|
|
/* for(l = obj ; CONSP(l); l = CDR(l)){ */
|
|
/* x = CAR(l); */
|
|
/* objprint(iostdout, x, 0); printf("\n"); */
|
|
/* eval(x); */
|
|
/* } */
|
|
dprintf("> err=%d\n", err);
|
|
return 0;
|
|
}
|
|
#endif
|