sg-parser.c

来自「linux下网络收音机的源码」· C语言 代码 · 共 428 行

C
428
字号
/* * Copyright (c) 2002, 2003, 2004 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include <stdarg.h>#include <string.h>#include <glib/gi18n.h>#include <glib-object.h>#include "sg-parser.h"#include "sg-util.h"#define EXPECT_EOF			(1 << 0)#define EXPECT_SYMBOL			(1 << 1)#define EXPECT_MINUS			(1 << 2)#define EXPECT_VALUE			(1 << 3)#define EXPECT_LEFT_CURLY		(1 << 4)#define EXPECT_RIGHT_CURLY		(1 << 5)#define EXPECT_SEMICOLON		(1 << 6)/*** function declarations ***************************************************/static int	sg_parser_expect_mask		(GTokenType	type);static void	sg_parser_skip_statement	(SGParser	*parser);static gboolean	sg_parser_statement_validate	(SGParserStatement *statement);/*** implementation **********************************************************/SGParser *sg_parser_new (const char *filename, GError **err){  SGParser *parser;  GError *tmp_err = NULL;  g_return_val_if_fail(filename != NULL, NULL);  parser = g_new(SGParser, 1);  if (! (parser->io_channel = g_io_channel_new_file(filename, "r", &tmp_err)))    {      g_set_error(err, 0, 0, _("unable to open %s: %s"), filename, tmp_err->message);      g_error_free(tmp_err);      g_free(parser);      return NULL;    }  parser->filename = g_strdup(filename);  parser->scanner = g_scanner_new(NULL);  parser->scope_stack = NULL;    parser->scanner->input_name = parser->filename;  parser->scanner->user_data = parser;    g_scanner_input_file(parser->scanner,		       g_io_channel_unix_get_fd(parser->io_channel));  return parser;}voidsg_parser_free (SGParser *parser){  g_return_if_fail(parser != NULL);  g_io_channel_shutdown(parser->io_channel, TRUE, NULL);  g_io_channel_unref(parser->io_channel);  g_free(parser->filename);  g_scanner_destroy(parser->scanner);  g_slist_free(parser->scope_stack);  g_free(parser);}voidsg_parser_define (SGParser *parser, SGParserDefinition *definition){  g_return_if_fail(parser != NULL);  g_return_if_fail(definition != NULL);  g_return_if_fail(definition->id != 0);  g_return_if_fail(definition->name != NULL);    g_scanner_scope_add_symbol(parser->scanner,			     definition->parent,			     definition->name,			     definition);}voidsg_parser_definev (SGParser *parser, SGParserDefinition *definitionv){  g_return_if_fail(parser != NULL);  g_return_if_fail(definitionv != NULL);  while (definitionv->name)    sg_parser_define(parser, definitionv++);}/* * Returns a SGParserStatement object, or NULL if sold out. */SGParserStatement *sg_parser_get_statement (SGParser *parser){  SGParserStatement *statement;  GTokenType type;  int expect;  gboolean minus = FALSE;  g_return_val_if_fail(parser != NULL, NULL); loop:  statement = g_new0(SGParserStatement, 1);  statement->parser = parser;  expect = EXPECT_EOF | EXPECT_SYMBOL | EXPECT_MINUS | EXPECT_VALUE | EXPECT_RIGHT_CURLY;  for (;;)    {      type = g_scanner_get_next_token(parser->scanner);      if (type == G_TOKEN_EOF)	{	  if (SG_PARSER_SCOPE(parser) != 0)	    g_scanner_warn(parser->scanner, _("EOF not in root scope"));	  	  sg_parser_statement_free(statement);	  	  return NULL;	}            if (! (expect & sg_parser_expect_mask(type)))	{			/* G_TOKEN_ERROR also ends up here */	  g_scanner_unexp_token(parser->scanner,				G_TOKEN_NONE,				NULL,				"keyword",				NULL,				NULL,				FALSE);	  sg_parser_skip_statement(parser);	  sg_parser_statement_free(statement);	  goto loop;	}#define NO_MINUS		\      {				\	if (minus)		\	  {			\	    g_scanner_warn(parser->scanner, _("unexpected minus sign")); \	    minus = FALSE;	\	  }			\      }#define MINUS(var)		\      {				\	if (minus)		\	  {			\	    (var) = 0 - (var);	\	    minus = FALSE;	\	  }			\      }            switch (type)	{	case G_TOKEN_SYMBOL:	  NO_MINUS;	  statement->definition = parser->scanner->value.v_symbol;	  	  expect = EXPECT_VALUE | EXPECT_LEFT_CURLY | EXPECT_SEMICOLON;	  if (statement->definition->value_type == G_TYPE_INT	      || statement->definition->value_type == G_TYPE_DOUBLE)	    expect |= EXPECT_MINUS;	  break;	  	case '-':	  NO_MINUS;	  minus = TRUE;	  break;	  	case G_TOKEN_IDENTIFIER:	  {	    gboolean v_gboolean;	    NO_MINUS;	    v_gboolean = ! strcmp(parser->scanner->value.v_identifier, "yes");	    g_value_init(&statement->value, G_TYPE_BOOLEAN);	    g_value_set_boolean(&statement->value, v_gboolean);	    expect = EXPECT_LEFT_CURLY | EXPECT_SEMICOLON;	  	    break;	  }	case G_TOKEN_INT:	  {	    if (statement->definition && statement->definition->value_type == G_TYPE_BOOLEAN)	      {		/* support for old configuration files using integers instead of booleans */		NO_MINUS;		g_value_init(&statement->value, G_TYPE_BOOLEAN);		g_value_set_boolean(&statement->value, parser->scanner->value.v_int);	      }	    else if (statement->definition && statement->definition->value_type == G_TYPE_UINT)	      {		NO_MINUS;		g_value_init(&statement->value, G_TYPE_UINT);		g_value_set_uint(&statement->value, parser->scanner->value.v_int);	      }	    else	      {		int v_int = parser->scanner->value.v_int;		MINUS(v_int);		g_value_init(&statement->value, G_TYPE_INT);		g_value_set_int(&statement->value, v_int);	      }	    	    expect = EXPECT_LEFT_CURLY | EXPECT_SEMICOLON;	  	    break;	  }	case G_TOKEN_FLOAT:	  {	    double v_double = parser->scanner->value.v_float;	    MINUS(v_double);	    g_value_init(&statement->value, G_TYPE_DOUBLE);	    g_value_set_double(&statement->value, v_double);	  	    expect = EXPECT_LEFT_CURLY | EXPECT_SEMICOLON;	  	    break;	  }	case G_TOKEN_STRING:	  {	    char *unescaped;	    NO_MINUS;	    unescaped = *parser->scanner->value.v_string	      ? g_strcompress(parser->scanner->value.v_string)	      : NULL;	    g_value_init(&statement->value, G_TYPE_STRING);	    g_value_set_string(&statement->value, unescaped);	    g_free(unescaped);	    	    expect = EXPECT_LEFT_CURLY | EXPECT_SEMICOLON;	  	    break;	  }	case G_TOKEN_LEFT_CURLY:	case G_TOKEN_RIGHT_CURLY:	case ';':	  NO_MINUS;	  statement->terminator = type;	  	  break;	  	default:			/* only to suppress compiler warnings */	  break;	}      #undef NO_MINUS#undef MINUS      if (statement->terminator)	{			/* got a complete statement */	  if (sg_parser_statement_validate(statement))	    break;		/* statement ok, exit the loop */	  else	    {	      sg_parser_statement_free(statement);	      goto loop;	    }	}    }  return statement;}/* * Modifies the parser's state (scoping) according to a statement. */voidsg_parser_statement_evaluate (SGParserStatement *statement){  int scope;  g_return_if_fail(statement != NULL);  if (statement->terminator == '{')    {      g_return_if_fail(statement->definition != NULL);      scope = statement->definition->id;      sg_slist_push(&statement->parser->scope_stack, GINT_TO_POINTER(scope));      g_scanner_set_scope(statement->parser->scanner, scope);    }  else if (statement->terminator == '}')    {      sg_slist_pop(&statement->parser->scope_stack);      scope = GPOINTER_TO_INT(sg_slist_peek(statement->parser->scope_stack));      g_scanner_set_scope(statement->parser->scanner, scope);    }}voidsg_parser_statement_free (SGParserStatement *statement){  g_return_if_fail(statement != NULL);  if (G_IS_VALUE(&statement->value))    g_value_unset(&statement->value);  g_free(statement);}static intsg_parser_expect_mask (GTokenType type){  switch (type)    {    case G_TOKEN_EOF:				return EXPECT_EOF;    case G_TOKEN_SYMBOL:			return EXPECT_SYMBOL;    case '-':					return EXPECT_MINUS;    case G_TOKEN_INT:    case G_TOKEN_FLOAT:    case G_TOKEN_STRING:    case G_TOKEN_IDENTIFIER:			return EXPECT_VALUE;    case G_TOKEN_LEFT_CURLY:			return EXPECT_LEFT_CURLY;    case G_TOKEN_RIGHT_CURLY:			return EXPECT_RIGHT_CURLY;    case ';':					return EXPECT_SEMICOLON;    default:					return 0;    }}static voidsg_parser_skip_statement (SGParser *parser){  GTokenType type;  do    type = g_scanner_get_next_token(parser->scanner);  while (type != G_TOKEN_EOF	 && type != G_TOKEN_LEFT_CURLY	 && type != G_TOKEN_RIGHT_CURLY	 && type != ';');}/* * Checks a statement against its definition and validates it or not. */static gbooleansg_parser_statement_validate (SGParserStatement *statement){  if (statement->definition)    {      if ((statement->definition->scope && statement->terminator != '{')	  || (! statement->definition->scope && statement->terminator != ';'))	{	  g_scanner_warn(statement->parser->scanner, _("wrong terminator"));	  return FALSE;	}      else if (statement->definition->value_type == G_TYPE_NONE)	{	  if (G_IS_VALUE(&statement->value))	    {	      g_scanner_warn(statement->parser->scanner, _("value encountered, but none expected"));	      return FALSE;	    }	}      else if (! G_VALUE_HOLDS(&statement->value, statement->definition->value_type))	{	  g_scanner_warn(statement->parser->scanner, _("incorrect value type"));	  return FALSE;	}    }  if (statement->terminator == '}' && ! sg_slist_peek(statement->parser->scope_stack))    {      g_scanner_warn(statement->parser->scanner, _("unmatched start of scope"));      return FALSE;    }  return TRUE;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?