From 4f4a8f35de7249a03a1127f7c2e4bd7905eefd2a Mon Sep 17 00:00:00 2001 From: bjculkin Date: Sat, 18 Mar 2017 14:48:41 -0400 Subject: Add ability to use subgroups for sequences. Subgroups are essentially things like the , in a function call. Now, you should be able to properly have function call arguments marked for you. --- .../bjc/utils/parserutils/SequenceDelimiter.java | 123 +++++++++++++++++++-- .../bjc/utils/parserutils/StringDelimiter.java | 2 +- 2 files changed, 115 insertions(+), 10 deletions(-) (limited to 'BJC-Utils2/src/main') diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/SequenceDelimiter.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/SequenceDelimiter.java index 1180017..96a6c65 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/SequenceDelimiter.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/SequenceDelimiter.java @@ -56,6 +56,12 @@ public class SequenceDelimiter { */ private Set groupExclusions; + /* + * Mapping from sub-group delimiters, to any sub-groups enclosed + * in them. + */ + private Map> subgroups; + /** * Create a new empty delimiter group. * @@ -162,6 +168,33 @@ public class SequenceDelimiter { } } + /** + * Adds sub-group markers to this group. + * + * @param subgroup + * The token to mark a sub-group. + * + * @param contained + * Any sub-groups to enclose in this group. + */ + @SafeVarargs + public final void addSubgroup(T2 subgroup, T2... contained) { + if(subgroup == null) { + throw new NullPointerException("Subgroup marker must not be null"); + } + + Set contains = new HashSet<>(); + for(T2 contain : contained) { + if(contain == null) { + throw new NullPointerException("Contained group must not be null"); + } + + contains.add(contain); + } + + subgroups.put(subgroup, contains); + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -248,11 +281,14 @@ public class SequenceDelimiter { * following grammar while obeying the defined group rules. * *
-	 *           -> ( | )*
-	 *          ->   
-	 *           -> STRING
-	 *           -> STRING
-	 *          -> STRING
+	 *              -> ( |  | )*
+	 *          ->  
+	 *             ->   
+	 *         
+	 *              -> STRING
+	 *              -> STRING
+	 *             -> STRING
+	 *            -> STRING
 	 * 
* * @param seq @@ -264,25 +300,36 @@ public class SequenceDelimiter { * @param contents * The item to use to mark the contents of a group * + * @param subgroup + * The item to use to mark a sub-group. + * * @return The sequence as a tree that matches its group structure. Each - * node in the tree is either a data node or a group node. + * node in the tree is either a data node, a subgroup node, or a + * group node. * * A data node is a leaf node whose data is the string it * represents. * + * A subgroup node is a node with two children, and the name of + * the sub-group as its label. The first child is the contents + * of the sub-group, and the second is the marker that started + * the subgroup. The marker is a leaf node labeled with its + * contents, and the contents contains a recursive tree. + * * A group node is a node with three children, and the name of * the group as its label. The first child is the opening * delimiter, the second is the group contents, and the third is * the closing delimiter. The delimiters are leaf nodes labeled - * with their contents, while the group node contains a list of - * data and group nodes. + * with their contents, while the group node contains a + * recursive tree. * * @throws DelimiterException * Thrown if something went wrong during sequence * delimitation. * */ - public ITree delimitSequence(T root, T contents, @SuppressWarnings("unchecked") T... seq) throws DelimiterException { + public ITree delimitSequence(T root, T contents, T subgroup, @SuppressWarnings("unchecked") T... seq) + throws DelimiterException { /* * The root node of the tree to give back. */ @@ -426,6 +473,64 @@ public class SequenceDelimiter { whoForbid.remove(excludedGroup); } + } else if(!groupStack.empty() && groupStack.top().subgroups.containsKey(tok)){ + /* + * Parse a sub-group. + */ + + /* + * The set of enclosed groups. + */ + Set enclosed = groupStack.top().subgroups.get(tok); + + /* + * The current contents of this group. + */ + ITree contentTree = trees.pop(); + + /* + * Find the first element to enclose in the subgroup. + */ + int ind = contentTree.revFind((chd) -> { + if(chd.getHead().equals(subgroup)) { + return !enclosed.contains(chd.getChild(1)); + } else { + return false; + } + }); + + ITree newContentTree = new Tree<>(contentTree.getHead()); + ITree subgroupContents = new Tree<>(contents); + + /* + * Split content tree into an untouched tree, and the subgroup. + */ + for(int j = 0; j < contentTree.getChildrenCount(); j++) { + ITree child = contentTree.getChild(j); + + if(j < ind) { + newContentTree.addChild(child); + } else { + subgroupContents.addChild(child); + } + } + + /* + * Construct the subgroup. + */ + ITree subgroupTree = new Tree<>(subgroup); + subgroupTree.addChild(subgroupContents); + subgroupTree.addChild(new Tree<>(tok)); + + /* + * Add the subgroup to the group. + */ + newContentTree.addChild(subgroupTree); + + /* + * Add the group contents. + */ + trees.push(newContentTree); } else { trees.top().addChild(new Tree<>(tok)); } diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/StringDelimiter.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/StringDelimiter.java index 4c5b972..8b437aa 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/StringDelimiter.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/StringDelimiter.java @@ -26,6 +26,6 @@ public class StringDelimiter extends SequenceDelimiter { * @see SequenceDelimiter */ public ITree delimitSequence(String... seq) throws DelimiterException { - return super.delimitSequence("root", "contents", seq); + return super.delimitSequence("root", "contents", "subgroup", seq); } } -- cgit v1.2.3