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 + -
显示快捷键?