From: Thadeu Lima de Souza Cascardo Date: Fri, 7 Oct 2005 15:12:16 +0000 (+0000) Subject: Added grammar file description loader X-Git-Tag: cascardo@tlscascardo--private,libgrammatic--nogobject--0.1--base-0~1 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Fgrammar.git;a=commitdiff_plain;h=1e85e209ae43ef4f84c80c8a0fa92993fdb5c8f1 Added grammar file description loader Grammar File Description Loader, bnf.c, is added. It reads a file which contains a description of a grammar and returns the grammar. git-archimport-id: cascardo@tlscascardo--private/libgrammatic--dev--0.1--patch-20 --- diff --git a/bnf.c b/bnf.c new file mode 100644 index 0000000..8d960f8 --- /dev/null +++ b/bnf.c @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include +#include +#include + +static gint scanner_next (scanner_t* scanner, GString** val) +{ + + int state; + int start; + int stop; + int i; + gchar* buffer; + GString* lexeme; + + state = NONE; + start = 0; + stop = 0; + buffer = malloc (256); + + for (i = 0; stop == 0; i++) + { + + gchar c; + + if (scanner->buffer->len == 0) + { + int r; + r = scanner->cb (scanner->data, buffer, 256); + if (r == 0) + g_string_append_c (scanner->buffer, 0); + else + g_string_append_len (scanner->buffer, buffer, r); + } + + c = scanner->buffer->str[i]; + + switch (state) + { + case NONE: + if (g_ascii_isalpha (c)) + { + start = i; + state = ID; + break; + } + else if (g_ascii_isspace (c)) + { + if (c == '\n') + { + start = i; + state = EOL; + } + break; + } + else if (c == ':') + { + start = i; + state = EQUAL; + break; + } + else if (c == '"') + { + start = i; + state = STRING; + break; + } + else if (c == 0) + { + stop = i; + break; + } + case ID: + if (g_ascii_isalnum (c)) + { + break; + } + else if (g_ascii_isspace (c) || c == 0) + { + stop = i; + break; + } + case EOL: + case EQUAL: + stop = i; + break; + case STRING: + if (c == '"') + stop = i+1; + break; + } + + } + + free (buffer); + + g_string_erase (scanner->buffer, 0, start); + lexeme = g_string_new_len (scanner->buffer->str, stop - start); + g_string_erase (scanner->buffer, 0, stop - start); + + if (val) + { + *val = lexeme; + } + else + { + g_string_free (lexeme, TRUE); + } + + return state; + +} + +enum + { + BNF_GRAMMAR = 1, + BNF_RULES, + BNF_RULE, + BNF_LEFT, + BNF_RIGHT, + BNF_SYMBOL, + BNF_TERMINAL, + BNF_NONTERMINAL + }; + +void grammar_tree (Grammar* grammar, GNode* tree) +{ + + GNode* child_rules; + GNode* child_rule; + GNode* child_left; + GNode* child_right; + GNode* child_symbol; + GNode* child_nonterminal; + GNode* child_terminal; + GNode* child; + symbol_t* symbol; + rule_t* rule; + GString* sym; + GQuark value; + + assert (G_NODE_IS_LEAF(tree) == FALSE); + symbol = tree->data; + assert (symbol->value == BNF_GRAMMAR); + + child_rules = tree->children; + + while (child_rules->children != NULL) + { + + assert (G_NODE_IS_LEAF(child_rules) == FALSE); + symbol = child_rules->data; + assert (symbol->value == BNF_RULES); + + child_rule = child_rules->children; + assert (G_NODE_IS_LEAF(child_rule) == FALSE); + symbol = child_rule->data; + assert (symbol->value == BNF_RULE); + + child_left = child_rule->children; + assert (G_NODE_IS_LEAF (child_left) == FALSE); + symbol = child_left->data; + assert (symbol->value == BNF_LEFT); + + child_nonterminal = child_left->children; + assert (G_NODE_IS_LEAF (child_nonterminal) == FALSE); + symbol = child_nonterminal->data; + assert (symbol->value == BNF_NONTERMINAL); + assert (child_nonterminal->next == NULL); + + child = child_nonterminal->children; + assert (G_NODE_IS_LEAF (child)); + sym = child->data; + + /* Create new rule */ + value = g_quark_from_string (sym->str); + rule = grammar_rule_new (grammar, symbol_new (FALSE, value)); + + child_right = child_left->next->next; + while (child_right->children != NULL) + { + + assert (G_NODE_IS_LEAF(child_right) == FALSE); + symbol = child_right->data; + assert (symbol->value == BNF_RIGHT); + + child_symbol = child_right->children; + assert (G_NODE_IS_LEAF(child_symbol) == FALSE); + symbol = child_symbol->data; + assert (symbol->value == BNF_SYMBOL); + + child = child_symbol->children; + symbol = child->data; + if (symbol->value == BNF_NONTERMINAL) + { + child_nonterminal = child; + assert (G_NODE_IS_LEAF (child_nonterminal) == FALSE); + assert (child_nonterminal->next == NULL); + child = child_nonterminal->children; + assert (G_NODE_IS_LEAF (child)); + sym = child->data; + /* Append nonterminal to rule */ + value = g_quark_from_string (sym->str); + rule_append (rule, symbol_new (FALSE, value)); + } + else if (symbol->value == BNF_TERMINAL) + { + child_terminal = child; + assert (G_NODE_IS_LEAF (child_terminal) == FALSE); + assert (child_terminal->next == NULL); + child = child_terminal->children; + assert (G_NODE_IS_LEAF (child)); + sym = child->data; + /* Append terminal to rule */ + value = g_quark_from_string (sym->str); + rule_append (rule, symbol_new (TRUE, value)); + } + else + { + assert (TRUE); + } + + child_right = child_symbol->next; + + } + + child_rules = child_rule->next; + + } + +} + +Grammar* grammar_load (char* filename) +{ + + Grammar* grammar; + rule_t* rule; + + scanner_t* scanner; + Rdp* parser; + GNode* tree; + + int fd; + + fd = open (filename, O_RDONLY); + + scanner = scanner_new (read, fd); + + parser = rdp_new (scanner_next, scanner, BNF_GRAMMAR); + grammar = (Grammar*) parser; + + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_GRAMMAR)); + rule_append (rule, symbol_new (FALSE, BNF_RULES)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_RULES)); + rule_append (rule, symbol_new (FALSE, BNF_RULE)); + rule_append (rule, symbol_new (FALSE, BNF_RULES)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_RULES)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_RULE)); + rule_append (rule, symbol_new (FALSE, BNF_LEFT)); + rule_append (rule, symbol_new (TRUE, EQUAL)); + rule_append (rule, symbol_new (FALSE, BNF_RIGHT)); + rule_append (rule, symbol_new (TRUE, EOL)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_LEFT)); + rule_append (rule, symbol_new (FALSE, BNF_NONTERMINAL)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_RIGHT)); + rule_append (rule, symbol_new (FALSE, BNF_SYMBOL)); + rule_append (rule, symbol_new (FALSE, BNF_RIGHT)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_RIGHT)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_SYMBOL)); + rule_append (rule, symbol_new (FALSE, BNF_TERMINAL)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_SYMBOL)); + rule_append (rule, symbol_new (FALSE, BNF_NONTERMINAL)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_TERMINAL)); + rule_append (rule, symbol_new (TRUE, STRING)); + rule = grammar_rule_new (grammar, symbol_new (FALSE, BNF_NONTERMINAL)); + rule_append (rule, symbol_new (TRUE, ID)); + + tree = rdp_build (parser); + + close (fd); + scanner_delete (scanner); + + if (tree == NULL) + { + return NULL; + } + else + { + Grammar* gr; + gr = g_object_new (GRAMMAR_TYPE, NULL); + grammar_tree (gr, tree); + return gr; + } + +} diff --git a/bnf.h b/bnf.h new file mode 100644 index 0000000..fb97f86 --- /dev/null +++ b/bnf.h @@ -0,0 +1,8 @@ +#ifndef BNF_H +#define BNF_H + +#include + +Grammar* grammar_load (char* filename); + +#endif BNF_H