Пример #1
0
// Simplify the children of the given node, removing any that never match or do
// nothing.
// The out_changed variable is set to true when any simplifications occur.
static void bnf_simplify_children(bnf_t* tree, bnf_t* parent, bool* out_never,
  bool* out_nop, bool *out_changed)
{
  pony_assert(parent != NULL);

  if(out_never != NULL) *out_never = false;
  if(out_nop != NULL) *out_nop = false;

  // Run through the child list
  bnf_t* prev = NULL;
  bnf_t* p = parent->child;

  while(p != NULL)
  {
    // Simplify the child
    bnf_simplify_node(tree, p, out_changed);

    if(p->id == BNF_NEVER && out_never != NULL)
      *out_never = true;

    if(p->id == BNF_NOP && out_nop != NULL)
      *out_nop = true;

    if(p->id == BNF_NEVER || p->id == BNF_NOP)
    {
      // Remove this child
      if(prev == NULL)  // Removing first node in list
        parent->child = p->sibling;
      else
        prev->sibling = p->sibling;

      bnf_t* next = p->sibling;
      p->sibling = NULL;
      bnf_free(p);
      p = next;
      *out_changed = true;
    }
    else
    {
      prev = p;
      p = p->sibling;
    }
  }

  parent->last_child = prev;
}
Пример #2
0
// Attempt to simplify the given node.
// We simplify from the bottom up, removing subrules that can never match or do
// nothing. We also inline trivial rules when they are referenced.
// The out_changed variable is set to true when any simplifications occur.
static void bnf_simplify_node(bnf_t* tree, bnf_t* bnf, bool *out_changed)
{
  assert(bnf != NULL);
  assert(out_changed != NULL);

  switch(bnf->id)
  {
    case BNF_TREE:
      bnf_simplify_children(tree, bnf, NULL, NULL, out_changed);
      break;

    case BNF_DEF:
      bnf_simplify_node(tree, bnf->child, out_changed);
      break;

    case BNF_SEQ:
    {
      bool any_never = false;
      bnf_simplify_children(tree, bnf, &any_never, NULL, out_changed);

      if(any_never)
      {
        bnf->id = BNF_NEVER;
        *out_changed = true;
      }
      else if(bnf->child == NULL)
      {
        // Empty sequence
        bnf->id = BNF_NOP;
        *out_changed = true;
      }
      else if(bnf->child->sibling == NULL)
      {
        // Lone node in sequence
        bnf_use_child(bnf);
        *out_changed = true;
      }

      break;
    }

    case BNF_OR:
    {
      bool any_nop = false;
      bnf_simplify_children(tree, bnf, NULL, &any_nop, out_changed);

      if(any_nop)
      {
        bnf->optional = true;
        *out_changed = true;
      }

      if(bnf->child == NULL)
      {
        // Empty set
        bnf->id = (bnf->optional) ? BNF_NOP : BNF_NEVER;
        *out_changed = true;
      }
      else if(bnf->child->sibling == NULL && !bnf->optional)
      {
        // Lone node in or
        bnf_use_child(bnf);
        *out_changed = true;
      }

      break;
    }

    case BNF_REPEAT:
      bnf_simplify_children(tree, bnf, NULL, NULL, out_changed);

      if(bnf->child == NULL)
      {
        // Empty body
        bnf->id = BNF_NOP;
        *out_changed = true;
      }

      break;

    case BNF_RULE:
    {
      // Check for inlinable rules
      if(bnf->name == NULL) // Hack rules aren't inlinable
        break;

      bnf_t* def = bnf_find_def(tree, bnf->name);
      assert(def != NULL);

      bnf_t* rule = def->child;
      assert(rule != NULL);

      // We inline rules that are nevers, nops, single token / rule references
      // or have been explicitly marked to inline
      if(rule->id == BNF_NEVER || rule->id == BNF_NOP ||
        rule->id == BNF_TOKEN || rule->id == BNF_QUOTED_TOKEN ||
        rule->id == BNF_RULE || def->inline_rule)
      {
        // Inline rule
        bnf->id = rule->id;
        bnf->name = rule->name;
        bnf->optional = rule->optional;
        bnf->last_child = NULL;
        bnf->child = bnf_copy(rule->child, &bnf->last_child);

        // Child of def should only ever have one child, so don't need to worry
        // about copying siblings
        assert(rule->sibling == NULL);

        // Don't worry about simplifying children now, leave that til the next
        // iteration
        *out_changed = true;
      }

      break;
    }

    default:
      break;
  }
}