Added grammar file description loader
[cascardo/grammar.git] / bnf.c
diff --git a/bnf.c b/bnf.c
new file mode 100644 (file)
index 0000000..8d960f8
--- /dev/null
+++ b/bnf.c
@@ -0,0 +1,298 @@
+#include <grammar.h>
+#include <rdp.h>
+#include <scanner.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+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;
+    }
+
+}