Skip to content
Permalink
Browse files

Added "Opt" (optional) rule, and fixed some problems with clearing ch…

…ild nodes of a Seq.
  • Loading branch information
nfomon committed Oct 9, 2015
1 parent 3950421 commit d2783bce90e5131a504b61f9465770a25527e568
Showing with 136 additions and 39 deletions.
  1. +4 −0 exstatik/Lexer.cpp
  2. +2 −0 statik/Makefile.am
  3. +76 −0 statik/Opt.cpp
  4. +34 −0 statik/Opt.h
  5. +1 −1 statik/STree.cpp
  6. +18 −38 statik/Seq.cpp
  7. +1 −0 statik/State.h
@@ -5,12 +5,14 @@

#include "statik/Keyword.h"
#include "statik/Regexp.h"
#include "statik/Opt.h"
#include "statik/Or.h"
#include "statik/Seq.h"
#include "statik/Star.h"
using statik::KEYWORD;
using statik::REGEXP;
using statik::Rule;
using statik::OPT;
using statik::OR;
using statik::SEQ;
using statik::STAR;
@@ -44,6 +46,8 @@ auto_ptr<Rule> exstatik::CreateLexer_Seq() {
auto_ptr<Rule> lexer(SEQ("seq"));
lexer->AddChild(KEYWORD("cat"));
lexer->AddChild(KEYWORD("dog"));
Rule* optmoo = lexer->AddChild(OPT("opt"));
optmoo->AddChild(KEYWORD("moo"));
lexer->AddChild(KEYWORD("car"));
return lexer;
}
@@ -16,6 +16,8 @@ STATIK_SRCS = \
Meta.h \
ObjectPool.h \
OData.h \
Opt.cpp \
Opt.h \
Or.cpp \
Or.h \
OrderList.cpp \
@@ -0,0 +1,76 @@
// Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level
// directory of this distribution and at http://shok.io/code/copyright.html

#include "Opt.h"

#include "IncParser.h"
#include "OutputFunc.h"
#include "SLog.h"
#include "STree.h"

#include <memory>
#include <string>
#include <vector>
using std::auto_ptr;
using std::string;
using std::vector;

using namespace statik;

auto_ptr<Rule> statik::OPT(const string& name) {
return auto_ptr<Rule>(new Rule(name,
MakeParseFunc_Opt(),
MakeOutputFunc_Root())); // FIXME hack?
}

auto_ptr<ParseFunc> statik::MakeParseFunc_Opt() {
return auto_ptr<ParseFunc>(new ParseFunc_Opt());
}

void ParseFunc_Opt::operator() (ParseAction::Action action, const List& inode, const STree* initiator) {
// Process
g_log.debug() << "Parsing Opt at " << *m_node;

if (ParseAction::Restart == action) {
if (m_node->children.empty()) {
if (m_node->GetRule().GetChildren().size() != 1) {
throw SError("Opt rule must have exactly one child");
}
(void) m_node->GetRule().GetChildren().at(0)->MakeNode(*m_node, inode);
} else {
STree& child = *m_node->children.at(0);
child.GetIncParser().Enqueue(ParseAction(ParseAction::Restart, child, inode));
}
return;
}
if (m_node->children.empty()) {
throw SError("Cannot parse Opt at " + m_node->Print() + " that has no children");
} else if (action != ParseAction::ChildUpdate) {
throw SError("Failed to process non-ChildUpdate action in Opt: " + m_node->Print());
}

// Compute
const STree& child = *m_node->children.at(0);
State& state = m_node->GetState();
const State& child_state = child.GetState();
if (child.IsClear()) {
g_log.info() << "Opt: " << *m_node << " child " << child << " is clear - clearing self";
m_node->ClearNode(inode);
return;
}
if (child_state.IsLocked()) {
g_log.info() << "Opt: " << *m_node << " child " << child << " is locked - locking self";
state.Lock();
}
if (child_state.IsPending()) {
throw SError("Opt: " + m_node->Print() + " cannot compute with pending child");
} else if (child_state.IsBad()) {
g_log.info() << "Opt: " << *m_node << " going complete since child is bad";
state.GoComplete();
m_node->GetIConnection().SetEnd(m_node->IStart());
} else {
state.SetStation(child_state.GetStation());
m_node->GetIConnection().SetEnd(child.IEnd());
}
g_log.debug() << "Opt " << *m_node << " now has child: " << child << " with IStart: " << m_node->IStart() << " and IEnd: " << m_node->IEnd();
}
@@ -0,0 +1,34 @@
// Copyright (C) 2015 Michael Biggs. See the COPYING file at the top-level
// directory of this distribution and at http://shok.io/code/copyright.html

#ifndef _statik_Opt_h_
#define _statik_Opt_h_

/* Optional rule */

#include "List.h"
#include "ParseAction.h"
#include "ParseFunc.h"
#include "Rule.h"
#include "STree.h"

#include <memory>
#include <string>

namespace statik {

std::auto_ptr<Rule> OPT(const std::string& name);

struct ParseFunc_Opt : public ParseFunc {
virtual ~ParseFunc_Opt() {}
virtual void operator() (ParseAction::Action action, const List& inode, const STree* initiator);
virtual std::auto_ptr<ParseFunc> Clone() {
return std::auto_ptr<ParseFunc>(new ParseFunc_Opt());
}
};

std::auto_ptr<ParseFunc> MakeParseFunc_Opt();

}

#endif // _statik_Opt_h_
@@ -114,7 +114,7 @@ string STree::DrawNode(const string& context, const STree* initiator) const {
} else if (m_state.IsComplete()) {
fillcolor = "#aaaaff";
} else {
throw SError("Stree::DrawNode() - unknown state");
throw SError("STree::DrawNode() - unknown state");
}
s += dotVar(this, context) + " [label=\"" + Util::safeLabelStr(m_rule.Name()) + "\", style=\"filled\", fillcolor=\"" + fillcolor + "\", fontsize=12.0];\n";

@@ -101,6 +101,13 @@ void ParseFunc_Seq::operator() (ParseAction::Action action, const List& inode, c
} else if (childState.IsComplete()) {
g_log.debug() << "ParseFunc_Seq at " << *m_node << ": Child is complete. Check on its next connections.";
if (next != m_node->children.end()) {
if ((*next)->IsClear()) {
g_log.debug() << " - next child is clear; erasing and re-creating it at the correct location";
m_node->children.erase(next);
(void) m_node->GetRule().GetChildren().at(child_index+1)->MakeNode(*m_node, (*child)->IEnd(), child+1);
state.GoPending();
return;
}
if (&(*child)->IEnd() != &(*next)->IStart()) {
m_node->GetIncParser().Enqueue(ParseAction(ParseAction::Restart, **next, (*child)->IEnd(), m_node));
state.GoPending();
@@ -112,43 +119,6 @@ void ParseFunc_Seq::operator() (ParseAction::Action action, const List& inode, c
state.GoPending();
return;
}
/*
switch(action) {
case ParseAction::ChildGrow: {
if (next != m_node->children.end()) {
if (&(*child)->IEnd() == &(*next)->IStart()) {
g_log.debug() << "ParseFunc_Seq at " << *m_node << ": Child grew, but next node is already in the right spot";
} else {
// Clear and Restart the next child
g_log.debug() << "ParseFunc_Seq at " << *m_node << ": Child grew, so clearing and restarting next, which is " << **next;
(*next)->ClearNode(inode);
m_node->GetIncParser().Enqueue(ParseAction(ParseAction::Restart, **next, (*child)->IEnd(), m_node));
state.GoOK();
return;
}
} else if (child_index != m_node->GetRule().GetChildren().size() - 1) {
g_log.debug() << "ParseFunc_Seq at " << *m_node << ": Child grew, so creating new next";
// Create next child
(void) m_node->GetRule().GetChildren().at(child_index+1)->MakeNode(*m_node, (*child)->IEnd());
state.GoOK();
return;
}
} break;
case ParseAction::ChildShrink: {
g_log.debug() << "ParseFunc_Seq at " << *m_node << ": Child shrank, so restarting next without clearing it";
if (next != m_node->children.end()) {
// Restart the next child
m_node->GetIncParser().Enqueue(ParseAction(ParseAction::Restart, **next, (*child)->IEnd(), m_node));
state.GoOK();
return;
} else if (child_index != m_node->GetRule().GetChildren().size() - 1) {
// Create next child
(void) m_node->GetRule().GetChildren().at(child_index+1)->MakeNode(*m_node, (*child)->IEnd());
state.GoOK();
return;
}
} break;
*/
} else if (childState.IsBad()) {
g_log.debug() << "Seq: Child is bad, so leaving subsequent connections alone; let it breach";
} else {
@@ -184,7 +154,17 @@ void ParseFunc_Seq::operator() (ParseAction::Action action, const List& inode, c
const State& istate = breachChild->GetState();
g_log.debug() << "Investigating breach child " << *breachChild;
if (istate.IsPending()) {
throw SError("Seq's breach child is Pending");
g_log.info() << "Seq's breach child is Pending; clearing it and recomputing self";
for (STree::child_mod_iter i = m_node->children.begin(); i != m_node->children.end(); ++i) {
if (breachChild == *i) {
m_node->children.erase(i);
g_log.debug() << " - erasing the cleared child!";
state.GoPending();
m_node->GetIncParser().Enqueue(ParseAction(ParseAction::ChildUpdate, *m_node, inode, m_node));
return;
}
}
throw SError("Failed to erase the pending child");
} else if (istate.IsBad()) {
state.GoBad();
m_node->GetIConnection().SetEnd(breachChild->IEnd());
@@ -31,6 +31,7 @@ class State {
void Clear();

Station GetStation() const { return m_station; }
void SetStation(Station station) { m_station = station; }

bool IsPending() const { return ST_PENDING == m_station; }
bool IsOK() const { return ST_OK == m_station; }

0 comments on commit d2783bc

Please sign in to comment.
You can’t perform that action at this time.