diff --git a/CTestTestfile.cmake b/CTestTestfile.cmake new file mode 100644 index 0000000..08827af --- /dev/null +++ b/CTestTestfile.cmake @@ -0,0 +1,28 @@ +# CMake generated Testfile for +# Source directory: /home/compilerkit/CompilerKit +# Build directory: /home/compilerkit/CompilerKit +# +# This file includes the relevent testing commands required for +# testing this directory and lists subdirectories to be tested as well. +ADD_TEST(complement-test "complement-test") +ADD_TEST(nonterminal-test "nonterminal-test") +ADD_TEST(to-graphviz-visitor-test "to-graphviz-visitor-test") +ADD_TEST(kleene-star-test "kleene-star-test") +ADD_TEST(empty-set-test "empty-set-test") +ADD_TEST(automata-test "automata-test") +ADD_TEST(string-builder-visitor-test "string-builder-visitor-test") +ADD_TEST(symbol-test "symbol-test") +ADD_TEST(scanner-test "scanner-test") +ADD_TEST(alternation-test "alternation-test") +ADD_TEST(empty-string-test "empty-string-test") +ADD_TEST(nullable-visitor-test "nullable-visitor-test") +ADD_TEST(terminal-test "terminal-test") +ADD_TEST(visitor-test "visitor-test") +ADD_TEST(convenience-test "convenience-test") +ADD_TEST(concatenation-test "concatenation-test") +ADD_TEST(pushdown-automata-test "pushdown-automata-test") +ADD_TEST(to-nfa-visitor-test "to-nfa-visitor-test") +ADD_TEST(to-grammar-visitor-test "to-grammar-visitor-test") +ADD_TEST(derivative-visitor-test "derivative-visitor-test") +ADD_TEST(grammar-test "grammar-test") +ADD_TEST(production-test "production-test") diff --git a/examples/automata-demo.c b/examples/automata-demo.c index 85ac272..04c9a0f 100644 --- a/examples/automata-demo.c +++ b/examples/automata-demo.c @@ -9,6 +9,7 @@ CompilerKitFSM *state_machine () CompilerKitFSM* fsm; // Creates pointer for FSM fsm = compilerkit_FSM_new("A"); // Calls the constructor for the FSM + printf("Object created\r\n"); // compilerkit_FSM_set_start_state(fsm, "A"); compilerkit_FSM_add_transition (fsm, "A", "B", 'd'); compilerkit_FSM_add_transition (fsm, "A", "F", 'f'); @@ -19,24 +20,18 @@ CompilerKitFSM *state_machine () compilerkit_FSM_add_transition (fsm, "F", "G", 's'); compilerkit_FSM_add_transition (fsm, "G", "H", 'm'); compilerkit_FSM_add_transition (fsm, "H", "A", ' '); - compilerkit_FSM_add_accepting_state (fsm, "E"); - compilerkit_FSM_add_accepting_state (fsm, "H"); + printf("Transitions added\r\n"); + compilerkit_FSM_add_end_state (fsm, "F"); + compilerkit_FSM_add_end_state (fsm, "E"); + compilerkit_FSM_add_end_state (fsm, "H"); + printf("End states added\r\n"); return fsm; } // Print out the states void print_states(CompilerKitFSM *fsm) { - GList *list; - - printf ("states: "); - list = compilerkit_FSM_get_states (fsm); - while (list) { - printf ((compilerkit_FSM_is_accepting_state(fsm, list->data) ? "(%s) " : "%s "), list->data); - list = g_list_next(list); - } - printf ("\n"); - g_list_free (list); + } // Match a string. @@ -53,6 +48,8 @@ void match_string(CompilerKitFSM *fsm) while (*str) { printf ("%s %c\n", state, *str); state = compilerkit_FSM_get_next_state (fsm, state, *str); + if(state == NULL) + break; *str++; } printf ((compilerkit_FSM_is_accepting_state(fsm, state)) ? @@ -68,8 +65,7 @@ int main (int argc, char ** argv) g_type_init(); fsm = state_machine(); - print_states(fsm); + /*print_states(fsm);*/ match_string(fsm); - g_object_unref (fsm); // Decreases the reference count by 1, if count becomes 0, then free memeory. } \ No newline at end of file diff --git a/examples/nfa-demo.c b/examples/nfa-demo.c new file mode 100644 index 0000000..27591d0 --- /dev/null +++ b/examples/nfa-demo.c @@ -0,0 +1,13 @@ +#include +#include "CompilerKit/nfa.h" + +/** @todo Describe what task main will accomplish. */ +int main (int argc, char ** argv) +{ + CompilerKitNFA* nfa; + g_type_init(); + + /** @todo Briefly show how to use the methods in CompilerKitNFA to accomplish the task. */ + + g_object_unref (nfa); +} \ No newline at end of file diff --git a/include/CompilerKit/automata.h b/include/CompilerKit/automata.h index f5b6e23..d3d9edf 100644 --- a/include/CompilerKit/automata.h +++ b/include/CompilerKit/automata.h @@ -57,6 +57,19 @@ typedef struct _CompilerKitFSM } CompilerKitFSM; +#define bool int +#define true 1 +#define false 0 + +typedef struct _CompilerKitFSMNode +{ + gchar* id; + gchar data; + GList* paths; + bool visited; + bool endState; +} CompilerKitFSMNode; + /** * @struct CompilerKitFSMClass * A finite state machine class struct. @@ -80,42 +93,29 @@ typedef struct _CompilerKitFSMClass GType compilerkit_FSM_get_type (void); /* Public method function prototypes */ -CompilerKitFSM *compilerkit_FSM_new (gchar *str); -void compilerkit_FSM_set_start_state (CompilerKitFSM* self, - gchar *state); -gchar *compilerkit_FSM_get_start_state (CompilerKitFSM* self); +CompilerKitFSM *compilerkit_FSM_new (gchar *str); -void compilerkit_FSM_add_state (CompilerKitFSM *self, - gchar *state); +void compilerkit_FSM_set_start_state(CompilerKitFSM *self, gchar* id); -GList *compilerkit_FSM_get_states (CompilerKitFSM *self); +gchar* compilerkit_FSM_get_start_state(CompilerKitFSM *self); -GList *compilerkit_FSM_get_transitions (CompilerKitFSM *self); +void compilerkit_FSM_add_transition(CompilerKitFSM* self, gchar* parentID, gchar* id, gchar value); -gboolean compilerkit_FSM_has_state (CompilerKitFSM *self, - gchar *state); +bool compilerkit_FSM_has_state(CompilerKitFSM* self, gchar* id); +void compilerkit_FSM_add_end_state(CompilerKitFSM* self,gchar* id); -void compilerkit_FSM_add_transition (CompilerKitFSM* self, - gchar *from_state, - gchar *to_state, - gchar input); +void compilerkit_FSM_node_reset_visited(CompilerKitFSMNode* node); -gchar *compilerkit_FSM_get_next_state (CompilerKitFSM *self, - gchar *from_state, - gchar transition); +CompilerKitFSMNode* compilerkit_FSM_node_find(CompilerKitFSMNode* node, gchar* id); -void compilerkit_FSM_add_accepting_state (CompilerKitFSM* self, - gchar *state); +bool compilerkit_FSM_node_add(CompilerKitFSM *self, gchar* parentID, gchar* id, gchar value); -GList *compilerkit_FSM_get_accepting_states (CompilerKitFSM *self); +void compilerkit_FSM_node_destroy_all(CompilerKitFSMNode* node); -gboolean compilerkit_FSM_is_accepting_state (CompilerKitFSM *self, - gchar *state); +gchar* compilerkit_FSM_get_next_state(CompilerKitFSM* self, gchar* state, gchar value); -void compilerkit_FSM_merge (CompilerKitFSM *self, - CompilerKitFSM *other); G_END_DECLS #endif \ No newline at end of file diff --git a/include/CompilerKit/nfa.h b/include/CompilerKit/nfa.h new file mode 100644 index 0000000..0d2ac95 --- /dev/null +++ b/include/CompilerKit/nfa.h @@ -0,0 +1,86 @@ +/** + * Copyright (C) 2012 The CompilerKit contributors. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef INCLUDE_CompilerKit_nfa_h__ +#define INCLUDE_CompilerKit_nfa_h__ + +#include +G_BEGIN_DECLS +#define COMPILERKIT_TYPE_NFA (compilerkit_nfa_get_type ()) +#define COMPILERKIT_NFA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COMPILERKIT_TYPE_NFA, CompilerKitNFA)) +#define COMPILERKIT_IS_NFA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COMPILERKIT_TYPE_NFA)) +#define COMPILERKIT_NFA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), COMPILERKIT_TYPE_NFA, CompilerKitNFAClass)) +#define COMPILERKIT_IS_NFA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COMPILERKIT_TYPE_NFA)) +#define COMPILERKIT_NFA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COMPILERKIT_TYPE_NFA, CompilerKitNFAClass)) + +typedef struct _CompilerKitNFAPrivate CompilerKitNFAPrivate; + +/** + * @struct CompilerKitNFA + * @todo Briefly describe this struct. (Remove the todo). + * + * Defines all public fields. Private fields live behind an opaque pointer. + * @see #_CompilerKitNFAPrivate for private fields. + * @see #CompilerKitNFAClass for virtual public methods. + * @example nfa-demo.c + * This is an example of how to use the CompilerKitNFA struct. + */ +typedef struct _CompilerKitNFA +{ + /** Base instance (GObject) */ + GObject parent_instance; + + /** @todo Define public fields here */ + + /** Opaque pointer to private fields */ + CompilerKitNFAPrivate *priv; + +} CompilerKitNFA; + +/** + * @struct CompilerKitNFAClass + * @todo Briefly describe this struct. (Remove the todo). + * + * This struct declares the virtual public methods. + * @see #CompilerKitNFA for a list of fields. + */ +typedef struct _CompilerKitNFAClass +{ + /** Base class (GObjectClass) */ + GObjectClass parent_class; + + /** @todo Virtual public methods (function pointers) go here */ + // void (*method_name) (CompilerKitNFA *self, ...); +} CompilerKitNFAClass; + +/** + * @fn compilerkit_nfa_get_type + * Returns the runtime type information for CompilerKitNFA. Macro COMPILERKIT_TYPE_NFA uses it. + * @pre None + * @param None + * @return GType (runtime type information) + */ +GType compilerkit_nfa_get_type (void); + +/** Public method function prototypes + * @todo Add function prototypes here for both virtual and non-virtual public methods. + * @see http://developer.gnome.org/gobject/stable/howto-gobject-methods.html + */ +CompilerKitNFA* compilerkit_nfa_new (void); + +G_END_DECLS +#endif /* INCLUDE_CompilerKit_nfa_h__ */ \ No newline at end of file diff --git a/src/automata.c b/src/automata.c index bf062d8..91747d8 100644 --- a/src/automata.c +++ b/src/automata.c @@ -18,6 +18,7 @@ #include "CompilerKit/automata.h" #include #include +#include "../include/CompilerKit/automata.h" #define COMPILERKIT_FSM_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), COMPILERKIT_TYPE_FSM, CompilerKitFSMPrivate)) @@ -26,22 +27,6 @@ G_DEFINE_TYPE(CompilerKitFSM, compilerkit_FSM, G_TYPE_OBJECT); /** Private method function prototypes */ static void compilerkit_FSM_finalize (GObject* object); static void compilerkit_FSM_dispose (GObject* object); -static void compilerkit_FSM_mergeTables(GHashTable* table1, GHashTable* table2); - -/** - * Get the key for a state and transition. (Private function) - */ -static gchar *compilerkit_FSM_get_transition_key (gchar *state, gchar transition) -{ - int key_length = strlen (state) + 1; - gchar *key = g_malloc (key_length + 1); - gchar *result = key; - - *key++ = transition; - while (*key++ = *state++); - - return result; -} /** * @struct _CompilerKitFSMPrivate @@ -51,75 +36,9 @@ static gchar *compilerkit_FSM_get_transition_key (gchar *state, gchar transition */ struct _CompilerKitFSMPrivate { - /** Starting state of the finite automaton. */ - gchar *start; - /** Set of states (vertices) in the finite automaton. */ - GHashTable *states; - /** Transitions between states (edges) in the finite automaton. */ - GHashTable *transitions; - /** If we are in any of these accepting states by the end of a match, then the match succeeds. */ - GHashTable *accept_states; + CompilerKitFSMNode* start; }; -/** - * compilerkit_FSM_class_init: - * Initializes the CompilerKitFSMClass struct. - * @pre klass is not NULL. - * @param CompilerKitFSMClass to initialize - * @return void - */ -static void -compilerkit_FSM_class_init (CompilerKitFSMClass *klass) -{ - GObjectClass *g_object_class; - - /* Add private structure */ - g_type_class_add_private (klass, sizeof (CompilerKitFSMPrivate)); - - /* Get the parent gobject class */ - g_object_class = G_OBJECT_CLASS(klass); - - /* Hook finalization functions */ - g_object_class->dispose = compilerkit_FSM_dispose; /* instance destructor, reverse of init */ - g_object_class->finalize = compilerkit_FSM_finalize; /* class finalization, reverse of class init */ -} - -/** - * compilerkit_FSM_init: - * Initializes the CompilerKitFSM struct. - * @pre self is not NULL. - * @param CompilerKitFSM to initialize - * @return void - */ -static void -compilerkit_FSM_init (CompilerKitFSM *self) -{ - CompilerKitFSMPrivate* priv; - self->priv = priv = COMPILERKIT_FSM_GET_PRIVATE (self); - - /** @todo Initialize hash tables here */ - priv->start = NULL; - priv->states = g_hash_table_new(g_str_hash, g_str_equal); - priv->transitions = g_hash_table_new(g_str_hash, g_str_equal); - priv->accept_states = g_hash_table_new(g_str_hash, g_str_equal); -} - -/** - * compilerkit_FSM_new: - * Construct a CompilerKitFSM - * @fn compilerkit_FSM_new - * @pre None - * @param None - * @return A new CompilerKitFSM struct. - * @memberof CompilerKitFSM - */ -CompilerKitFSM *compilerkit_FSM_new (gchar *start) -{ - CompilerKitFSM *result = COMPILERKIT_FSM (g_object_new (COMPILERKIT_TYPE_FSM, NULL)); - compilerkit_FSM_set_start_state (result, g_strdup(start)); - return result; -} - /** * compilerkit_FSM_finalize: * Reverse what compilerkit_FSM_class_init allocated. @@ -151,240 +70,218 @@ compilerkit_FSM_dispose (GObject* object) priv = COMPILERKIT_FSM_GET_PRIVATE (self); - g_free (priv->start); - g_hash_table_destroy(priv->states); - g_hash_table_destroy(priv->transitions); - g_hash_table_destroy(priv->accept_states); + //compilerkit_FSM_node_destroy_all(priv->start); G_OBJECT_CLASS (compilerkit_FSM_parent_class)->dispose (object); } /** - * compilerkit_FSM_add_transition: - * Add a transition to a finite state machine. - * If the start and end states aren't already in the set of states, this function adds them in. - * @fn compilerkit_FSM_add_transition - * @pre No NULL parameters. - * @param CompilerKitFSM* A CompilerKitFSM pointer. - * @param gchar* Start state for the transition. - * @param gchar* End state for the transition. - * @param gchar The necessary input to make the transition. + * compilerkit_FSM_class_init: + * Initializes the CompilerKitFSMClass struct. + * @pre klass is not NULL. + * @param CompilerKitFSMClass to initialize * @return void - * @memberof CompilerKitFSM */ -void compilerkit_FSM_add_transition (CompilerKitFSM* self, gchar *from_state, gchar *to_state, gchar transition) +static void +compilerkit_FSM_class_init (CompilerKitFSMClass *klass) { - gchar *key; - g_return_if_fail (COMPILERKIT_IS_FSM (self)); + GObjectClass *g_object_class; - compilerkit_FSM_add_state (self, from_state); - compilerkit_FSM_add_state (self, to_state); - - /** - * @todo Let's pretend we're a DFA, since that's simpler to implement for now. - * This should really be split up into an abstract automaton base class, since DFA and NFA differ on what to do here. - */ - key = compilerkit_FSM_get_transition_key (from_state, transition); + /* Add private structure */ + g_type_class_add_private (klass, sizeof (CompilerKitFSMPrivate)); + + /* Get the parent gobject class */ + g_object_class = G_OBJECT_CLASS(klass); - g_hash_table_insert (self->priv->transitions, key, to_state); + /* Hook finalization functions */ + g_object_class->dispose = compilerkit_FSM_dispose; /* instance destructor, reverse of init */ + g_object_class->finalize = compilerkit_FSM_finalize; /* class finalization, reverse of class init */ } /** - * compilerkit_FSM_add_accepting_state: - * Add an accepting state to a finite state machine. - * @fn compilerkit_FSM_add_accepting_state - * @pre No NULL parameters. - * @param CompilerKitFSM* A CompilerKitFSM pointer. - * @param gchar* An accepting state. + * compilerkit_FSM_init: + * Initializes the CompilerKitFSM struct. + * @pre self is not NULL. + * @param CompilerKitFSM to initialize * @return void - * @memberof CompilerKitFSM */ -void compilerkit_FSM_add_accepting_state (CompilerKitFSM* self, gchar *state) +static void +compilerkit_FSM_init (CompilerKitFSM *self) { - compilerkit_FSM_add_state (self, state); - - g_hash_table_insert(self->priv->accept_states,state, NULL); + CompilerKitFSMPrivate* priv; + self->priv = priv = COMPILERKIT_FSM_GET_PRIVATE (self); + + priv->start = NULL; } -/** - * compilerkit_FSM_merge: - * Copy all states and transitions (but not accepting states) from another CompilerKitFSM into self. - * @fn compilerkit_FSM_merge - * @pre No NULL parameters. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @param CompilerKitFSM* The other CompilerKitFSM pointer. - * @return void - * @memberof CompilerKitFSM - */ -void compilerkit_FSM_merge (CompilerKitFSM *self, CompilerKitFSM *other) +CompilerKitFSM* compilerkit_FSM_new(gchar* start) { - CompilerKitFSMPrivate* priv = self->priv; - CompilerKitFSMPrivate* newPriv = other->priv; - - compilerkit_FSM_mergeTables(priv->states, newPriv->states); - compilerkit_FSM_mergeTables(priv->transitions, newPriv->transitions); + CompilerKitFSM *result = COMPILERKIT_FSM(g_object_new(COMPILERKIT_TYPE_FSM,NULL)); + compilerkit_FSM_set_start_state(result,g_strdup(start)); + return result; } -/** - * Copy entries from table2 into table1. - */ -static void compilerkit_FSM_mergeTables(GHashTable* table1, GHashTable* table2) +void compilerkit_FSM_set_start_state(CompilerKitFSM *self, gchar* id) { - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init (&iter, table2); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - g_hash_table_insert(table1, key, value); - } + //Make the node that has the id specified as the start point + compilerkit_FSM_node_add(self, NULL, id, NULL); } -/** - * compilerkit_FSM_add_state: - * Add a state into the set of states of a finite state machine. - * @fn compilerkit_FSM_add_state - * @pre No NULL parameters. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @param CompilerKitFSM* The other CompilerKitFSM pointer. - * @return void - * @memberof CompilerKitFSM - */ -void compilerkit_FSM_add_state (CompilerKitFSM* self, gchar *state) +gchar* compilerkit_FSM_get_start_state(CompilerKitFSM *self) { - g_assert (self); - g_assert (state); - - g_hash_table_insert(self->priv->states,state, NULL); + if(self->priv->start == NULL) + return NULL; + return g_strdup(self->priv->start->id); } -/** - * compilerkit_FSM_has_state: - * Return whether the state exists. - * @fn compilerkit_FSM_has_state - * @pre CompilerKitFSM* is not `NULL`. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @param gchar* A `state`. (Possibly `NULL`) - * @return gboolean Whether the `state` exists. - * @memberof CompilerKitFSM - */ -gboolean compilerkit_FSM_has_state (CompilerKitFSM *self, gchar *state) +void compilerkit_FSM_add_transition(CompilerKitFSM* self, gchar* parentID, gchar* id, gchar value) { - g_assert (self); - - if (!state) return FALSE; - return g_hash_table_lookup_extended (self->priv->states, state, NULL, NULL); + compilerkit_FSM_node_add(self,parentID,id,value); } -/** - * compilerkit_FSM_set_start_state: - * Designate the starting state of a finite state machine. - * @fn compilerkit_FSM_set_start_state - * @pre No NULL parameters. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @param gchar* The starting state - * @return void - * @memberof CompilerKitFSM - */ -void compilerkit_FSM_set_start_state (CompilerKitFSM* self, gchar *state) +bool compilerkit_FSM_has_state(CompilerKitFSM* self, gchar* id) { - compilerkit_FSM_add_state (self, state); - - g_free (self->priv->start); - - self->priv->start = g_strdup (state); + //Reset all the node visited status so we can traverse it correctly + compilerkit_FSM_node_reset_visited(self->priv->start); + //Grab the correct node + CompilerKitFSMNode* node = compilerkit_FSM_node_find(self->priv->start,id); + //if the node does exist return true + if(node != NULL) + return true; + return false; } -/** - * compilerkit_FSM_get_start_state: - * Return the starting state of a finite state machine. - * @fn compilerkit_FSM_get_start_state - * @pre No NULL parameters. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @return gchar* The start state. - * @memberof CompilerKitFSM - */ -gchar *compilerkit_FSM_get_start_state (CompilerKitFSM* self) +void compilerkit_FSM_add_end_state(CompilerKitFSM* self,gchar* id) { - return self->priv->start; + //Reset all the node visited status so we can traverse it correctly + compilerkit_FSM_node_reset_visited(self->priv->start); + //Grab the correct node + CompilerKitFSMNode* node = compilerkit_FSM_node_find(self->priv->start,id); + if(node != NULL) + node->endState = true; } -/** - * compilerkit_FSM_get_accepting_states: - * Return a GList* of accepting states. - * @fn compilerkit_FSM_get_accepting_states - * @pre No NULL parameters. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @return GList* A GList containing all accepting states. Use `g_list_free()` when done using it. - * @memberof CompilerKitFSM - */ -GList *compilerkit_FSM_get_accepting_states (CompilerKitFSM *self) +bool compilerkit_FSM_is_accepting_state(CompilerKitFSM* self, gchar* id) { - return g_hash_table_get_keys (self->priv->accept_states); + //Reset all the node visited status so we can traverse it correctly + compilerkit_FSM_node_reset_visited(self->priv->start); + //Grab the correct node + CompilerKitFSMNode* node = compilerkit_FSM_node_find(self->priv->start,id); + if(node == NULL) + return false; + printf("found it son\r\n"); + return node->endState; } -/** - * compilerkit_FSM_get_transitions: - * Return a GList* of all transitions. - * @fn compilerkit_FSM_get_transitions - * @pre No NULL parameters. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @return GList* A GList containing all transitions. Use `g_list_free()` when done using it. - * @memberof CompilerKitFSM - */ -GList *compilerkit_FSM_get_transitions (CompilerKitFSM *self) +void compilerkit_FSM_node_reset_visited(CompilerKitFSMNode* node) { - return g_hash_table_get_keys (self->priv->transitions); + //Check to make sure the current node is not NULL before trying to access its data + if(node == NULL) + return; + //Set the nodes visited status to false + node->visited = false; + //Loop through all the paths the node has to make sure they are all visited + int i = 0; + CompilerKitFSMNode* path = NULL; + while((path = (CompilerKitFSMNode*)g_list_nth_data(node->paths,i++)) != NULL) + if(path->visited == false) //Make sure not to visit already visited nodes + compilerkit_FSM_node_reset_visited(path); } -/** - * compilerkit_FSM_get_states: - * Return a GList* of all states. - * @fn compilerkit_FSM_get_states - * @pre No NULL parameters. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @return GList* A GList containing all states. Use `g_list_free()` when done using it. - * @memberof CompilerKitFSM - */ -GList *compilerkit_FSM_get_states (CompilerKitFSM *self) +CompilerKitFSMNode* compilerkit_FSM_node_find(CompilerKitFSMNode* node, gchar* id) { - return g_hash_table_get_keys (self->priv->states); + //Make sure the node is not NULL before attempting to access its private data + if(node == NULL) + return NULL; + //Check if the node is the node we are looking for. If it is return it. + if(g_strcmp0(node->id,id) == 0) + return node; + node->visited = true; + //Loop through all pathways of the current node to check if they are the node we are looking for. + int i = 0; + CompilerKitFSMNode* path = NULL; + if(node->paths == NULL) + return NULL; + while((path = (CompilerKitFSMNode*)g_list_nth_data(node->paths,i++)) != NULL) + { + if(path->visited == false) + { + CompilerKitFSMNode* returnNode = compilerkit_FSM_node_find(path,id); + if(g_strcmp0(returnNode->id,id) == 0) + return returnNode; + } + } + return NULL; } -/** - * compilerkit_FSM_is_accepting_state: - * Return whether the state is an accepting state. - * @fn compilerkit_FSM_is_accepting_state - * @pre CompilerKitFSM* is not `NULL`. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @param gchar* A `state`. (Possibly `NULL`) - * @return gboolean Whether the `state` is accepting. `NULL` states are never accepting. - * @memberof CompilerKitFSM - */ -gboolean compilerkit_FSM_is_accepting_state (CompilerKitFSM *self, gchar *state) +gchar* compilerkit_FSM_get_next_state(CompilerKitFSM* self, gchar* state, gchar value) { - g_assert (self); - if (!state) return FALSE; - return g_hash_table_lookup_extended (self->priv->accept_states, state, NULL, NULL); + CompilerKitFSMNode* node = NULL; + compilerkit_FSM_node_reset_visited(self->priv->start); + node = compilerkit_FSM_node_find(self->priv->start,state); + if(node == NULL) + return NULL; + int i = 0; + CompilerKitFSMNode* path = NULL; + if(node->paths == NULL) + return NULL; + while((path = (CompilerKitFSMNode*)g_list_nth_data(node->paths,i++)) != NULL) + { + if(path->data == value) + return path->id; + } + return NULL; } -/** - * compilerkit_FSM_get_next_state: - * Return the next state given a state and the transition character. - * @fn compilerkit_FSM_get_next_state - * @pre CompilerKitFSM* is not NULL. - * @param CompilerKitFSM* A CompilerKitFSM pointer (`self`). - * @param gchar* A `state`. (Possibly `NULL`). - * @param gchar A character. - * @return gchar* The next state. - * @memberof CompilerKitFSM - */ -gchar *compilerkit_FSM_get_next_state (CompilerKitFSM *self, gchar *from_state, gchar transition) +bool compilerkit_FSM_node_add(CompilerKitFSM *self, gchar* parentID, gchar* id, gchar value) { - gchar *key; - g_assert (self); - if (!from_state) return from_state; - key = compilerkit_FSM_get_transition_key (from_state, transition); - return g_hash_table_lookup (self->priv->transitions, key); + if(id == NULL) + return false; + //Reset all the node visited status so we can traverse it correctly + compilerkit_FSM_node_reset_visited(self->priv->start); + //Make sure the node does not already exist + if(compilerkit_FSM_node_find(self->priv->start,id) != NULL) + return false; + //Declare the node for the parent + CompilerKitFSMNode* node = NULL; + if(parentID != NULL) + { + //Get the node designated as the parent node + compilerkit_FSM_node_reset_visited(self->priv->start); + node = compilerkit_FSM_node_find(self->priv->start,parentID); + } + //If we have been given a parent and it was not found return a state of failure + if(node == NULL && parentID != NULL) + return false; + //Allocate a new node and set the data for it + CompilerKitFSMNode* newNode = malloc(sizeof(CompilerKitFSMNode)); + newNode->id = g_strdup(id); + newNode->data = value; + newNode->paths = NULL; + newNode->endState = false; + newNode->visited = false; + if(node != NULL) + { + //Append the new node onto the parent node + node->paths = g_list_append(node->paths,newNode); + } + else + { + //Set the new node as the start node + self->priv->start = newNode; + } + //Return that the addition was complete + return true; } +void compilerkit_FSM_node_destroy_all(CompilerKitFSMNode* node) +{ + int i = 0; + CompilerKitFSMNode* path = NULL; + while((path = (CompilerKitFSMNode*)g_list_nth_data(node->paths,i++)) != NULL) + compilerkit_FSM_node_destroy_all(path); + //g_free(node->data); + //g_free(node->id); + g_list_free(node->paths); + //g_free(node); +} \ No newline at end of file diff --git a/src/convenience.c b/src/convenience.c index 72f1246..e30f092 100644 --- a/src/convenience.c +++ b/src/convenience.c @@ -168,7 +168,7 @@ GObject *compilerkit_optional_new (GObject *regex) */ GObject *compilerkit_regex_digits(void) { - return NULL; + return compilerkit_character_class_new('0','9'); } /** * compilerkit_regex_lower: @@ -182,7 +182,7 @@ GObject *compilerkit_regex_digits(void) */ GObject *compilerkit_regex_lower(void) { - return NULL; + return compilerkit_character_class_new('a','z'); } /** * compilerkit_regex_upper: @@ -196,7 +196,7 @@ GObject *compilerkit_regex_lower(void) */ GObject *compilerkit_regex_upper(void) { - return NULL; + return compilerkit_character_class_new('A','Z'); } /** * compilerkit_regex_punct: diff --git a/src/nfa.c b/src/nfa.c new file mode 100644 index 0000000..4b01ee8 --- /dev/null +++ b/src/nfa.c @@ -0,0 +1,138 @@ +/** + * Copyright (C) 2012 The CompilerKit contributors. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "CompilerKit/nfa.h" +#define COMPILERKIT_NFA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), COMPILERKIT_TYPE_NFA, CompilerKitNFAPrivate)) +G_DEFINE_TYPE(CompilerKitNFA, compilerkit_nfa, G_TYPE_OBJECT); + +/** @todo Private method function prototypes go here (for private methods, declare as static) */ +static void compilerkit_nfa_finalize (GObject* object); +static void compilerkit_nfa_dispose (GObject* object); + +/** + * @struct _CompilerKitNFAPrivate + * The private fields of the CompilerKitNFA struct. + * + * @see #CompilerKitNFA + */ +struct _CompilerKitNFAPrivate +{ + /** @todo Declare private members here */ + /** + * @todo dummy is here so everything will compile by default. + * If the class does not require private fields, search for private and remove all relevant macros, function calls, etc. + */ + int dummy; +}; + +/** + * compilerkit_nfa_class_init: + * @fn compilerkit_nfa_class_init + * Initializes the CompilerKitNFAClass (virtual table). + * @pre klass is not NULL. + * @param CompilerKitNFAClass to initialize + * @return void + */ +static void +compilerkit_nfa_class_init (CompilerKitNFAClass *klass) +{ + GObjectClass *g_object_class; + + /* Add private structure */ + g_type_class_add_private (klass, sizeof (CompilerKitNFAPrivate)); + + /* Get the parent gobject class */ + g_object_class = G_OBJECT_CLASS(klass); + + /** @todo Hook virtual methods to implementations */ + // klass->method = method_implementation; + + /* Hook finalization functions */ + g_object_class->dispose = compilerkit_nfa_dispose; /* instance destructor, reverse of init */ + g_object_class->finalize = compilerkit_nfa_finalize; /* class finalization, reverse of class init */ +} + +/** + * compilerkit_nfa_init: + * @fn compilerkit_nfa_init + * Initializes the CompilerKitNFA instance. + * @pre self is not NULL. + * @param CompilerKitNFA to initialize + * @return void + */ +static void +compilerkit_nfa_init (CompilerKitNFA *self) +{ + CompilerKitNFAPrivate *priv; + + self->priv = priv = COMPILERKIT_NFA_GET_PRIVATE (self); + + /** @todo Initialize public fields */ + // self->public_field = some_value; + + /** @todo Initialize private fields */ + // priv->member = whatever; +} + +/** + * compilerkit_nfa_new: + * @fn compilerkit_nfa_new + * @memberof CompilerKitNFA + * Construct a CompilerKitNFA instance. + * @pre None + * @param None + * @return A new CompilerKitNFA struct. + */ +CompilerKitNFA* compilerkit_nfa_new (void) +{ + return COMPILERKIT_NFA (g_object_new (COMPILERKIT_TYPE_NFA, NULL)); +} + +/** + * compilerkit_nfa_finalize: + * @fn compilerkit_nfa_finalize + * Reverse what compilerkit_nfa_class_init allocated. + * @pre GObject is not NULL. + * @param GObject* An object to finalize. + * @return void + */ +static void +compilerkit_nfa_finalize (GObject* object) +{ + G_OBJECT_CLASS (compilerkit_nfa_parent_class)->finalize (object); +} + +/** + * compilerkit_nfa_dispose: + * @fn compilerkit_nfa_dispose + * Reverse what compilerkit_nfa_init allocated. + * @pre GObject is not NULL. + * @param GObject* An object to dispose. + * @return void + */ +static void +compilerkit_nfa_dispose (GObject* object) +{ + CompilerKitNFA *self = COMPILERKIT_NFA (object); + CompilerKitNFAPrivate* priv; + + priv = COMPILERKIT_NFA_GET_PRIVATE (self); + + /** @todo Deallocate memory as necessary */ + + G_OBJECT_CLASS (compilerkit_nfa_parent_class)->dispose (object); +} \ No newline at end of file diff --git a/tests/automata-test.c b/tests/automata-test.c index 077e1a4..67b2c96 100644 --- a/tests/automata-test.c +++ b/tests/automata-test.c @@ -58,22 +58,12 @@ void test_FSM_states (void) g_test_timer_start (); fsm = compilerkit_FSM_new ("zero"); - compilerkit_FSM_add_state (fsm, "one"); - compilerkit_FSM_add_state (fsm, "two"); - compilerkit_FSM_add_state (fsm, "three"); - - g_assert (compilerkit_FSM_has_state (fsm, "zero")); - g_assert (compilerkit_FSM_has_state (fsm, "one")); - g_assert (compilerkit_FSM_has_state (fsm, "two")); - g_assert (compilerkit_FSM_has_state (fsm, "three")); - g_assert (!compilerkit_FSM_has_state (fsm, "four")); - g_assert (!compilerkit_FSM_has_state (fsm, NULL)); - - compilerkit_FSM_add_transition (fsm, "zero", "five", '5'); - compilerkit_FSM_add_accepting_state (fsm, "six"); - g_assert (compilerkit_FSM_has_state (fsm, "five")); - g_assert (compilerkit_FSM_has_state (fsm, "six")); + compilerkit_FSM_add_transition(fsm,"zero","one","a"); + compilerkit_FSM_add_transition(fsm,"zero","two","b"); + g_assert(compilerkit_FSM_has_state(fsm,"zero")); + g_assert(compilerkit_FSM_has_state(fsm,"one")); + g_assert_cmpfloat(g_test_timer_elapsed (), <=, 1); g_object_unref (fsm); } diff --git a/tests/nfa-test.c b/tests/nfa-test.c new file mode 100644 index 0000000..17cb987 --- /dev/null +++ b/tests/nfa-test.c @@ -0,0 +1,61 @@ +/** + * Copyright (C) 2012 The CompilerKit contributors. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include "CompilerKit.h" + +/** @todo Write test cases for NFA of the form: void test_nfa_case (void); */ +/** @todo Add to `main`: g_test_add_func ("/nfa/case", test_nfa_case); */ + +/** + * test_nfa_case: + * @fn test_nfa_case + * Tests compilerkit_nfa_case in CompilerKitNFA struct. + * @pre None + * @param None + * @return void + */ +void test_nfa_case (void) +{ + CompilerKitNFA *obj; + + g_test_message ("Testing NFA case"); + g_test_timer_start (); + + /** @todo Test here */ + g_assert(FALSE); + + g_object_unref (obj); + + // This test shouldn't take too long to run + g_assert_cmpfloat(g_test_timer_elapsed (), <=, 1); +} + +int main (int argc, char ** argv) +{ + g_test_init (&argc, &argv, NULL); + g_type_init (); + + g_test_add_func ("/nfa/case", test_nfa_case); + + /** + * @todo Add additional test cases as necessary here: + * g_test_add_func ("/nfa/other_case", test_nfa_other_case); + */ + + g_test_run (); +} \ No newline at end of file